|
|
1.1 root 1: /* Procedure integration for GNU CC.
2: Copyright (C) 1988 Free Software Foundation, Inc.
3: Contributed by Michael Tiemann ([email protected])
4:
5: This file is part of GNU CC.
6:
1.1.1.12 root 7: GNU CC is free software; you can redistribute it and/or modify
8: it under the terms of the GNU General Public License as published by
9: the Free Software Foundation; either version 1, or (at your option)
10: any later version.
11:
1.1 root 12: GNU CC is distributed in the hope that it will be useful,
1.1.1.12 root 13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with GNU CC; see the file COPYING. If not, write to
19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
1.1 root 20:
21:
22: #include <stdio.h>
23:
24: #include "config.h"
25: #include "rtl.h"
26: #include "tree.h"
27: #include "flags.h"
28: #include "insn-flags.h"
29: #include "expr.h"
30:
31: #include "obstack.h"
32: #define obstack_chunk_alloc xmalloc
33: #define obstack_chunk_free free
34: extern int xmalloc ();
35: extern void free ();
36:
37: extern struct obstack permanent_obstack, maybepermanent_obstack;
38: extern struct obstack *rtl_obstack, *saveable_obstack, *current_obstack;
39:
40: #define MIN(x,y) ((x < y) ? x : y)
41:
42: extern tree pushdecl ();
1.1.1.5 root 43:
44: /* Default max number of insns a function can have and still be inline.
45: This is overridden on RISC machines. */
46: #ifndef INTEGRATE_THRESHOLD
47: #define INTEGRATE_THRESHOLD(DECL) \
48: (8 * (8 + list_length (DECL_ARGUMENTS (DECL)) + 16*TREE_INLINE (DECL)))
49: #endif
1.1 root 50:
51: /* This is the target of the inline function being expanded,
52: or NULL if there is none. */
53: static rtx inline_target;
54:
55: /* We must take special care not to disrupt life too severely
56: when performing procedure integration. One thing that that
57: involves is not creating illegitimate address which reload
58: cannot fix. Since we don't know what the frame pointer is
59: not capable of (in a machine independent way), we create
60: a pseudo-frame pointer which will have to do for now. */
61: static rtx inline_fp_rtx;
62:
63: /* Convert old frame-pointer offsets to new. Parameters which only
64: produce values (no addresses, and are never assigned), map directly
65: to the pseudo-reg of the incoming value. Parameters that are
66: assigned to but do not have their address taken are given a fresh
67: pseudo-register. Parameters that have their address take are
68: given a fresh stack-slot. */
69: static rtx *parm_map;
70:
71: /* ?? Should this be done here?? It is not right now.
72: Keep track of whether a given pseudo-register is the sum
73: of the frame pointer and a const_int (or zero). */
74: static char *fp_addr_p;
75:
76: /* For the local variables of the procdure being integrated that live
77: on the frame, FRAME_POINTER_DELTA says how much to change their
78: offsets by, so that they now live in the correct place on the
79: frame of the function being compiled. */
80: static int fp_delta;
81:
1.1.1.11 root 82: /* When an insn is being copied by copy_rtx_and_substitute,
83: this is nonzero if we have copied an ASM_OPERANDS.
84: In that case, it is the original input-operand vector.
85: Likewise in copy_for_inline. */
86: static rtvec orig_asm_operands_vector;
87:
88: /* When an insn is being copied by copy_rtx_and_substitute,
89: this is nonzero if we have copied an ASM_OPERANDS.
90: In that case, it is the copied input-operand vector.
91: Likewise in copy_for_inline. */
92: static rtvec copy_asm_operands_vector;
93:
1.1 root 94: /* Return a copy of an rtx (as needed), substituting pseudo-register,
95: labels, and frame-pointer offsets as necessary. */
96: static rtx copy_rtx_and_substitute ();
1.1.1.7 root 97: /* Variant, used for memory addresses that are not memory_address_p. */
98: static rtx copy_address ();
1.1 root 99:
100: static void copy_parm_decls ();
101: static void copy_decl_tree ();
102:
103: static rtx try_fold_cc0 ();
104:
105: /* We do some simple constant folding optimization. This optimization
106: really exists primarily to save time inlining a function. It
1.1.1.5 root 107: also helps users who ask for inline functions without -O. */
1.1 root 108: static rtx fold_out_const_cc0 ();
109:
110: /* Zero if the current function (whose FUNCTION_DECL is FNDECL)
111: is safe and reasonable to integrate into other functions.
112: Nonzero means value is a warning message with a single %s
113: for the function's name. */
114:
115: char *
116: function_cannot_inline_p (fndecl)
117: register tree fndecl;
118: {
119: register rtx insn;
120: tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
1.1.1.5 root 121: int max_insns = INTEGRATE_THRESHOLD (fndecl);
1.1 root 122: register int ninsns = 0;
123: register tree parms;
124:
125: /* No inlines with varargs. `grokdeclarator' gives a warning
126: message about that if `inline' is specified. This code
127: it put in to catch the volunteers. */
128: if (last && TREE_VALUE (last) != void_type_node)
1.1.1.7 root 129: return "varargs function cannot be inline";
1.1 root 130:
131: /* If its not even close, don't even look. */
132: if (get_max_uid () > 2 * max_insns)
1.1.1.7 root 133: return "function too large to be inline";
1.1 root 134:
1.1.1.11 root 135: /* If the structure value address comes in the stack,
136: we can't handle it. */
137: #if defined (STRUCT_VALUE) || defined (STRUCT_VALUE_INCOMING)
1.1.1.13! root 138: if (TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
! 139: || RETURN_IN_MEMORY (TREE_TYPE (TREE_TYPE (fndecl))))
! 140: return "inline functions not supported for this return value type";
1.1.1.11 root 141: #endif
142:
1.1 root 143: /* Don't inline functions which have BLKmode arguments.
144: Don't inline functions that take the address of
145: a parameter and do not specify a function prototype. */
146: for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
147: {
148: if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode)
1.1.1.7 root 149: return "function with large aggregate parameter cannot be inline";
1.1 root 150: if (last == NULL_TREE && TREE_ADDRESSABLE (parms))
1.1.1.7 root 151: return "no prototype, and parameter address used; cannot be inline";
1.1.1.11 root 152: /* If an aggregate is thought of as "in memory"
153: then its components are referred to by narrower memory refs.
154: If the actual parameter is a reg, these refs can't be translated,
155: esp. since copy_rtx_and_substitute doesn't know whether it is
156: reading or writing. */
157: if ((TREE_CODE (TREE_TYPE (parms)) == RECORD_TYPE
158: || TREE_CODE (TREE_TYPE (parms)) == UNION_TYPE)
159: && GET_CODE (DECL_RTL (parms)) == MEM)
160: return "address of an aggregate parameter is used; cannot be inline";
1.1 root 161: }
162:
163: if (get_max_uid () > max_insns)
164: {
165: for (ninsns = 0, insn = get_first_nonparm_insn (); insn && ninsns < max_insns;
166: insn = NEXT_INSN (insn))
167: {
168: if (GET_CODE (insn) == INSN
169: || GET_CODE (insn) == JUMP_INSN
170: || GET_CODE (insn) == CALL_INSN)
171: ninsns++;
172: }
173:
174: if (ninsns >= max_insns)
1.1.1.7 root 175: return "function too large to be inline";
1.1 root 176: }
177:
178: return 0;
179: }
180:
181: /* Variables used within save_for_inline. */
182:
183: /* Mapping from old pesudo-register to new pseudo-registers.
184: The first element of this map is reg_map[FIRST_PSEUDO_REGISTER].
1.1.1.6 root 185: It is allocated in `save_for_inline' and `expand_inline_function',
1.1 root 186: and deallocated on exit from each of those routines. */
187: static rtx *reg_map;
188:
189: /* Mapping from old code-labels to new code-labels.
190: The first element of this map is label_map[min_labelno].
1.1.1.6 root 191: It is allocated in `save_for_inline' and `expand_inline_function',
1.1 root 192: and deallocated on exit from each of those routines. */
193: static rtx *label_map;
194:
1.1.1.6 root 195: /* Mapping from old insn uid's to copied insns.
196: It is allocated in `save_for_inline' and `expand_inline_function',
197: and deallocated on exit from each of those routines. */
198: static rtx *insn_map;
199:
1.1 root 200: /* Map pseudo reg number into the PARM_DECL for the parm living in the reg.
201: Zero for a reg that isn't a parm's home.
202: Only reg numbers less than max_parm_reg are mapped here. */
203: static tree *parmdecl_map;
204:
205: /* Keep track of first pseudo-register beyond those that are parms. */
206: static int max_parm_reg;
207:
1.1.1.7 root 208: /* Offset from arg ptr to the first parm of this inline function. */
209: static int first_parm_offset;
210:
1.1 root 211: /* On machines that perform a function return with a single
212: instruction, such as the VAX, these return insns must be
213: mapped into branch statements. */
214: extern rtx return_label;
215:
216: /* Copy an rtx for save_for_inline. */
217: static rtx copy_for_inline ();
218:
219: /* Make the insns and PARM_DECLs of the current function permanent
220: and record other information in DECL_SAVED_INSNS to allow inlining
221: of this function in subsequent calls. */
222:
223: void
224: save_for_inline (fndecl)
225: tree fndecl;
226: {
227: extern rtx *regno_reg_rtx; /* in emit-rtl.c. */
228: extern current_function_args_size;
229:
230: rtx first_insn, last_insn, insn;
231: rtx head, copy;
232: tree parms;
233: int max_labelno, min_labelno, i, len;
234: int max_reg;
1.1.1.6 root 235: int max_uid;
1.1 root 236:
237: /* Make and emit a return-label if we have not already done so. */
238:
239: if (return_label == 0)
240: {
241: return_label = gen_label_rtx ();
242: emit_label (return_label);
243: }
244:
245: /* Get some bounds on the labels and registers used. */
246:
247: max_labelno = max_label_num ();
248: min_labelno = get_first_label_num ();
249: max_parm_reg = max_parm_reg_num ();
250: max_reg = max_reg_num ();
251:
252: /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL.
253:
254: Set TREE_VOLATILE to 0 if the parm is in a register, otherwise 1.
255: Later we set TREE_READONLY to 0 if the parm is modified inside the fn. */
256:
257: parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
1.1.1.3 root 258: bzero (parmdecl_map, max_parm_reg * sizeof (tree));
1.1 root 259:
260: for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
261: {
262: rtx p = DECL_RTL (parms);
263:
264: if (GET_CODE (p) == REG)
265: {
266: parmdecl_map[REGNO (p)] = parms;
267: TREE_VOLATILE (parms) = 0;
268: }
269: else
270: TREE_VOLATILE (parms) = 1;
271: TREE_READONLY (parms) = 1;
272: }
273:
274: /* The list of DECL_SAVES_INSNS, starts off with a header which
275: contains the following information:
276:
277: the first insn of the function (not including the insns that copy
278: parameters into registers).
279: the first label used by that function,
280: the last label used by that function,
281: and the total number of registers used. */
282:
283: head = gen_inline_header_rtx (NULL, NULL, min_labelno, max_labelno,
284: max_parm_reg, max_reg,
285: current_function_args_size);
1.1.1.6 root 286: max_uid = INSN_UID (head);
1.1 root 287:
288: /* We have now allocated all that needs to be allocated permanently
289: on the rtx obstack. Set our high-water mark, so that we
290: can free the rest of this when the time comes. */
291:
292: preserve_data ();
293:
294: /* Copy the chain insns of this function.
295: Install the copied chain as the insns of this function,
296: for continued compilation;
297: the original chain is recorded as the DECL_SAVED_INSNS
298: for inlining future calls. */
299:
300: /* If there are insns that copy parms from the stack into pseudo registers,
301: those insns are not copied. `expand_inline_function' must
302: emit the correct code to handle such things. */
303:
304: insn = get_insns ();
305: if (GET_CODE (insn) != NOTE)
306: abort ();
307: first_insn = rtx_alloc (NOTE);
308: NOTE_SOURCE_FILE (first_insn) = NOTE_SOURCE_FILE (insn);
309: NOTE_LINE_NUMBER (first_insn) = NOTE_LINE_NUMBER (insn);
310: INSN_UID (first_insn) = INSN_UID (insn);
311: PREV_INSN (first_insn) = NULL;
312: NEXT_INSN (first_insn) = NULL;
313: last_insn = first_insn;
314:
315: /* Each pseudo-reg in the old insn chain must have a unique rtx in the copy.
316: Make these new rtx's now, and install them in regno_reg_rtx, so they
317: will be the official pseudo-reg rtx's for the rest of compilation. */
318:
319: reg_map = (rtx *) alloca ((max_reg + 1) * sizeof (rtx));
320:
321: len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion);
322: for (i = max_reg - 1; i >= FIRST_PSEUDO_REGISTER; i--)
323: reg_map[i] = (rtx)obstack_copy (&maybepermanent_obstack, regno_reg_rtx[i], len);
324: bcopy (reg_map + FIRST_PSEUDO_REGISTER,
325: regno_reg_rtx + FIRST_PSEUDO_REGISTER,
1.1.1.7 root 326: (max_reg - FIRST_PSEUDO_REGISTER) * sizeof (rtx));
1.1 root 327:
328: /* Likewise each label rtx must have a unique rtx as its copy. */
329:
330: label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
331: label_map -= min_labelno;
332:
333: for (i = min_labelno; i < max_labelno; i++)
334: label_map[i] = gen_label_rtx ();
335:
1.1.1.6 root 336: /* Record the mapping of old insns to copied insns. */
337:
338: insn_map = (rtx *) alloca (max_uid * sizeof (rtx));
339: bzero (insn_map, max_uid * sizeof (rtx));
340:
1.1 root 341: /* Now copy the chain of insns. */
342:
343: for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
344: {
1.1.1.11 root 345: orig_asm_operands_vector = 0;
346: copy_asm_operands_vector = 0;
347:
1.1 root 348: switch (GET_CODE (insn))
349: {
350: case NOTE:
1.1.1.7 root 351: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)
352: continue;
353:
1.1 root 354: copy = rtx_alloc (NOTE);
355: NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
356: NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn);
357: break;
358:
359: case INSN:
360: case CALL_INSN:
361: case JUMP_INSN:
362: copy = rtx_alloc (GET_CODE (insn));
363: PATTERN (copy) = copy_for_inline (PATTERN (insn));
364: INSN_CODE (copy) = -1;
365: LOG_LINKS (copy) = NULL;
366: REG_NOTES (copy) = copy_for_inline (REG_NOTES (insn));
367: break;
368:
369: case CODE_LABEL:
370: copy = label_map[CODE_LABEL_NUMBER (insn)];
371: break;
372:
373: case BARRIER:
374: copy = rtx_alloc (BARRIER);
375: break;
376:
377: default:
378: abort ();
379: }
380: INSN_UID (copy) = INSN_UID (insn);
1.1.1.6 root 381: insn_map[INSN_UID (insn)] = copy;
1.1 root 382: NEXT_INSN (last_insn) = copy;
383: PREV_INSN (copy) = last_insn;
384: last_insn = copy;
385: }
386:
387: NEXT_INSN (last_insn) = NULL;
388:
389: NEXT_INSN (head) = get_first_nonparm_insn ();
390: FIRST_PARM_INSN (head) = get_insns ();
391: DECL_SAVED_INSNS (fndecl) = head;
392: DECL_FRAME_SIZE (fndecl) = get_frame_size ();
393: TREE_INLINE (fndecl) = 1;
394:
395: parmdecl_map = 0;
396: label_map = 0;
397: reg_map = 0;
398: return_label = 0;
399:
400: set_new_first_and_last_insn (first_insn, last_insn);
401: }
402:
403: /* Copy the rtx ORIG recursively, replacing pseudo-regs and labels
404: according to `reg_map' and `label_map'.
405: All other kinds of rtx are copied except those that can never be
406: changed during compilation. */
407:
408: static rtx
409: copy_for_inline (orig)
410: rtx orig;
411: {
412: register rtx x = orig;
413: register int i;
414: register enum rtx_code code;
415: register char *format_ptr;
416:
417: if (x == 0)
418: return x;
419:
420: code = GET_CODE (x);
421:
422: /* These types may be freely shared. */
423:
424: switch (code)
425: {
426: case QUEUED:
427: case CONST_INT:
428: case CONST_DOUBLE:
429: case SYMBOL_REF:
430: case PC:
431: case CC0:
432: return x;
433:
1.1.1.11 root 434: case ASM_OPERANDS:
435: /* If a single asm insn contains multiple output operands
436: then it contains multiple ASM_OPERANDS rtx's that share operand 3.
437: We must make sure that the copied insn continues to share it. */
438: if (orig_asm_operands_vector == XVEC (orig, 3))
439: {
440: x = rtx_alloc (ASM_OPERANDS);
441: XSTR (x, 0) = XSTR (orig, 0);
442: XSTR (x, 1) = XSTR (orig, 1);
443: XINT (x, 2) = XINT (orig, 2);
444: XVEC (x, 3) = copy_asm_operands_vector;
445: XVEC (x, 4) = XVEC (orig, 4);
446: return x;
447: }
448: break;
449:
1.1 root 450: case MEM:
451: /* A MEM is allowed to be shared if its address is constant
452: or is a constant plus one of the special registers. */
453: if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
454: return x;
455: if (GET_CODE (XEXP (x, 0)) == PLUS
456: && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
457: && (REGNO (XEXP (XEXP (x, 0), 0)) == FRAME_POINTER_REGNUM
458: || REGNO (XEXP (XEXP (x, 0), 0)) == ARG_POINTER_REGNUM)
459: && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
460: if (GET_CODE (XEXP (x, 0)) == REG
461: && (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
462: || REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM)
463: && CONSTANT_ADDRESS_P (XEXP (x, 1)))
464: return x;
465: break;
466:
467: case LABEL_REF:
468: {
469: /* Must point to the new insn. */
470: return gen_rtx (LABEL_REF, GET_MODE (orig),
471: label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
472: }
473:
474: case REG:
475: if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
476: return reg_map [REGNO (x)];
477: else
478: return x;
479:
480: /* If a parm that gets modified lives in a pseudo-reg,
481: set its TREE_VOLATILE to prevent certain optimizations. */
482: case SET:
483: {
484: rtx dest = SET_DEST (x);
485:
486: if (GET_CODE (dest) == REG
487: && REGNO (dest) < max_parm_reg
1.1.1.3 root 488: && REGNO (dest) >= FIRST_PSEUDO_REGISTER
489: && parmdecl_map[REGNO (dest)] != 0)
1.1 root 490: TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0;
491: }
492: break;
493: }
494:
495: /* Replace this rtx with a copy of itself. */
496:
497: x = rtx_alloc (code);
498: bcopy (orig, x, sizeof (int) * (GET_RTX_LENGTH (code) + 1));
499:
500: /* Now scan the subexpressions recursively.
501: We can store any replaced subexpressions directly into X
502: since we know X is not shared! Any vectors in X
503: must be copied if X was copied. */
504:
505: format_ptr = GET_RTX_FORMAT (code);
506:
507: for (i = 0; i < GET_RTX_LENGTH (code); i++)
508: {
509: switch (*format_ptr++)
510: {
511: case 'e':
512: XEXP (x, i) = copy_for_inline (XEXP (x, i));
513: break;
514:
1.1.1.6 root 515: case 'u':
516: /* Change any references to old-insns to point to the
517: corresponding copied insns. */
518: return insn_map[INSN_UID (XEXP (x, i))];
519:
1.1 root 520: case 'E':
1.1.1.6 root 521: if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0)
1.1 root 522: {
523: register int j;
524:
525: XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0));
526: for (j = 0; j < XVECLEN (x, i); j++)
527: XVECEXP (x, i, j)
528: = copy_for_inline (XVECEXP (x, i, j));
529: }
530: break;
531: }
532: }
1.1.1.11 root 533:
534: if (code == ASM_OPERANDS && orig_asm_operands_vector == 0)
535: {
536: orig_asm_operands_vector = XVEC (orig, 3);
537: copy_asm_operands_vector = XVEC (x, 3);
538: }
539:
1.1 root 540: return x;
541: }
542:
543: /* Integrate the procedure defined by FNDECL. Note that this function
544: may wind up calling itself. Since the static variables are not
545: reentrant, we do not assign them until after the possibility
546: or recursion is eliminated.
547:
548: If IGNORE is nonzero, do not produce a value.
549: Otherwise store the value in TARGET if it is nonzero and that is convenient.
550:
551: Value is:
552: (rtx)-1 if we could not substitute the function
553: 0 if we substituted it and it does not produce a value
554: else an rtx for where the value is stored. */
555:
556: rtx
557: expand_inline_function (fndecl, parms, target, ignore, type, structure_value_addr)
558: tree fndecl, parms;
559: rtx target;
560: int ignore;
561: tree type;
562: rtx structure_value_addr;
563: {
564: tree formal, actual;
565: rtx header = DECL_SAVED_INSNS (fndecl);
566: rtx insns = FIRST_FUNCTION_INSN (header);
1.1.1.9 root 567: rtx insn;
1.1 root 568: int max_regno = MAX_REGNUM (header) + 1;
569: register int i;
570: int min_labelno = FIRST_LABELNO (header);
571: int max_labelno = LAST_LABELNO (header);
572: int nargs;
573: rtx *arg_vec;
1.1.1.9 root 574: rtx local_return_label = 0;
1.1 root 575: rtx follows_call = 0;
1.1.1.7 root 576: rtx this_struct_value_rtx = 0;
1.1 root 577:
578: if (max_regno < FIRST_PSEUDO_REGISTER)
1.1.1.3 root 579: abort ();
1.1 root 580:
581: nargs = list_length (DECL_ARGUMENTS (fndecl));
582:
1.1.1.7 root 583: first_parm_offset = FIRST_PARM_OFFSET (fndecl);
584:
1.1 root 585: /* We expect PARMS to have the right length; don't crash if not. */
586: if (list_length (parms) != nargs)
587: return (rtx)-1;
1.1.1.13! root 588: /* Also check that the parms type match. Since the appropriate
! 589: conversions or default promotions have already been applied,
! 590: the machine modes should match exactly. */
! 591: for (formal = DECL_ARGUMENTS (fndecl),
! 592: actual = parms;
! 593: formal;
! 594: formal = TREE_CHAIN (formal),
! 595: actual = TREE_CHAIN (actual))
! 596: {
! 597: tree arg = TREE_VALUE (actual);
! 598: enum machine_mode mode = TYPE_MODE (DECL_ARG_TYPE (formal));
! 599: if (mode != TYPE_MODE (TREE_TYPE (arg)))
! 600: return (rtx)-1;
! 601: /* If they are block mode, the types should match exactly. */
! 602: if (mode == BLKmode && TREE_TYPE (arg) != TREE_TYPE (formal))
! 603: return (rtx)-1;
! 604: }
1.1 root 605:
606: /* Make a fresh binding contour that we can easily remove. */
607: pushlevel (0);
608: expand_start_bindings (0);
609:
610: /* Get all the actual args as RTL, and store them in ARG_VEC. */
611:
612: arg_vec = (rtx *)alloca (nargs * sizeof (rtx));
613:
614: for (formal = DECL_ARGUMENTS (fndecl),
615: actual = parms,
616: i = 0;
617: formal;
618: formal = TREE_CHAIN (formal),
619: actual = TREE_CHAIN (actual),
620: i++)
621: {
622: tree arg = TREE_VALUE (actual); /* this has already been converted */
1.1.1.13! root 623: enum machine_mode tmode = TYPE_MODE (DECL_ARG_TYPE (formal));
! 624: enum machine_mode imode = TYPE_MODE (TREE_TYPE (formal));
1.1 root 625: rtx copy;
626:
1.1.1.7 root 627: emit_note (DECL_SOURCE_FILE (formal), DECL_SOURCE_LINE (formal));
1.1 root 628:
629: if (TREE_ADDRESSABLE (formal))
630: {
631: int size = int_size_in_bytes (TREE_TYPE (formal));
632: copy = assign_stack_local (tmode, size);
1.1.1.12 root 633: if (!memory_address_p (DECL_MODE (formal), XEXP (copy, 0)))
634: copy = change_address (copy, VOIDmode, copy_rtx (XEXP (copy, 0)));
1.1 root 635: store_expr (arg, copy, 0);
636: }
637: else if (! TREE_READONLY (formal)
638: || TREE_VOLATILE (formal))
639: {
640: /* If parm is modified or if it hasn't a pseudo reg,
641: we may not simply substitute the actual value;
642: copy it through a register. */
643: copy = gen_reg_rtx (tmode);
644: store_expr (arg, copy, 0);
645: }
646: else
647: {
648: copy = expand_expr (arg, 0, tmode, 0);
649:
650: /* We do not use CONSTANT_ADDRESS_P here because
651: the set of cases where that might make a difference
652: are a subset of the cases that arise even when
653: it is a CONSTANT_ADDRESS_P (i.e., fp_delta
654: gets into the act. */
655: if (GET_CODE (copy) != REG && ! CONSTANT_P (copy))
656: copy = copy_to_reg (copy);
657: }
1.1.1.13! root 658: /* If passed mode != nominal mode, COPY is now the passed mode.
! 659: Convert it to the nominal mode (i.e. truncate it). */
! 660: if (tmode != imode)
! 661: copy = convert_to_mode (imode, copy);
1.1 root 662: arg_vec[i] = copy;
663: }
664:
665: copy_parm_decls (DECL_ARGUMENTS (fndecl), arg_vec);
666:
667: /* Perform postincrements before actually calling the function. */
668: emit_queue ();
669:
670: /* clean up stack so that variables might have smaller offsets. */
671: do_pending_stack_adjust ();
672:
673: /* Pass the function the address in which to return a structure value. */
674: if (structure_value_addr)
1.1.1.7 root 675: {
676: if (GET_CODE (struct_value_rtx) == MEM)
677: {
678: this_struct_value_rtx = force_reg (Pmode, structure_value_addr);
679: }
680: else
681: {
682: this_struct_value_rtx = struct_value_rtx;
683: emit_move_insn (this_struct_value_rtx, structure_value_addr);
684: }
685: }
1.1 root 686:
687: /* Now prepare for copying the insns.
688: Set up reg_map, parm_map and label_map saying how to translate
689: the pseudo-registers, stack-parm references and labels when copying. */
690:
691: reg_map = (rtx *) alloca (max_regno * sizeof (rtx));
692: bzero (reg_map, max_regno * sizeof (rtx));
693:
694: if (DECL_ARGUMENTS (fndecl))
695: {
696: tree decl = DECL_ARGUMENTS (fndecl);
697: int offset = FUNCTION_ARGS_SIZE (header);
1.1.1.7 root 698:
1.1 root 699: parm_map =
700: (rtx *)alloca ((offset / UNITS_PER_WORD) * sizeof (rtx));
701: bzero (parm_map, (offset / UNITS_PER_WORD) * sizeof (rtx));
1.1.1.7 root 702: parm_map -= first_parm_offset / UNITS_PER_WORD;
1.1 root 703:
704: for (formal = decl, i = 0; formal; formal = TREE_CHAIN (formal), i++)
705: {
706: /* Create an entry in PARM_MAP that says what pseudo register
707: is associated with an address we might compute. */
1.1.1.7 root 708: if (DECL_OFFSET (formal) >= 0)
709: {
710: /* This parameter has a home in the stack. */
711: parm_map[DECL_OFFSET (formal) / BITS_PER_WORD] = arg_vec[i];
712: }
713: else
714: {
715: /* Parameter that was passed in a register;
716: does it have a home on the stack (as a local)? */
717: rtx frtx = DECL_RTL (formal);
718: rtx offset = 0;
719: if (GET_CODE (frtx) == MEM)
720: {
721: frtx = XEXP (frtx, 0);
722: if (GET_CODE (frtx) == PLUS)
723: {
724: if (XEXP (frtx, 0) == frame_pointer_rtx
725: && GET_CODE (XEXP (frtx, 1)) == CONST_INT)
726: offset = XEXP (frtx, 1);
727: else if (XEXP (frtx, 1) == frame_pointer_rtx
728: && GET_CODE (XEXP (frtx, 0)) == CONST_INT)
729: offset = XEXP (frtx, 0);
730: }
731: if (offset)
732: parm_map[INTVAL (offset) / UNITS_PER_WORD] = arg_vec[i];
733: else abort ();
734: }
735: else if (GET_CODE (frtx) != REG)
736: abort ();
737: }
1.1 root 738: /* Create an entry in REG_MAP that says what rtx is associated
739: with a pseudo register from the function being inlined. */
740: if (GET_CODE (DECL_RTL (formal)) == REG)
741: reg_map[REGNO (DECL_RTL (formal))] = arg_vec[i];
742: }
1.1.1.7 root 743:
1.1.1.8 root 744: /* Make certain that we can accept struct_value_{incoming_rtx,rtx},
1.1.1.7 root 745: and map it. If it is a hard register, it is mapped automagically. */
1.1.1.12 root 746: if (this_struct_value_rtx == 0
747: || GET_CODE (struct_value_incoming_rtx) == REG)
1.1.1.7 root 748: ;
749: else if (GET_CODE (struct_value_incoming_rtx) == MEM
750: && XEXP (XEXP (struct_value_incoming_rtx, 0), 0) == frame_pointer_rtx
751: && GET_CODE (XEXP (XEXP (struct_value_incoming_rtx, 0), 1)) == CONST_INT)
752: parm_map[INTVAL (XEXP (XEXP (struct_value_incoming_rtx, 0), 1)) / UNITS_PER_WORD]
753: = this_struct_value_rtx;
754: else
755: abort ();
1.1 root 756: }
757: else
758: {
759: parm_map = NULL;
760: }
761:
762: label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
763: label_map -= min_labelno;
764:
765: for (i = min_labelno; i < max_labelno; i++)
766: label_map[i] = gen_label_rtx ();
767:
1.1.1.6 root 768: /* As we copy insns, record the correspondence, so that inter-insn
769: references can be copied into isomorphic structure. */
770:
771: insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx));
772: bzero (insn_map, INSN_UID (header) * sizeof (rtx));
773:
1.1 root 774: /* Set up a target to translate the inline function's value-register. */
775:
776: if (structure_value_addr != 0 || TYPE_MODE (type) == VOIDmode)
777: inline_target = 0;
778: else
1.1.1.3 root 779: {
780: /* Machine mode function was declared to return. */
781: enum machine_mode departing_mode = TYPE_MODE (type);
782: /* (Possibly wider) machine mode it actually computes
783: (for the sake of callers that fail to declare it right). */
784: enum machine_mode arriving_mode
1.1.1.10 root 785: = TYPE_MODE (DECL_RESULT_TYPE (fndecl));
1.1.1.3 root 786:
1.1.1.5 root 787: /* Don't use MEMs as direct targets because on some machines
788: substituting a MEM for a REG makes invalid insns.
789: Let the combiner substitute the MEM if that is valid. */
790: if (target && GET_CODE (target) == REG
791: && GET_MODE (target) == departing_mode)
1.1.1.3 root 792: inline_target = target;
793: else
794: inline_target = target = gen_reg_rtx (departing_mode);
795:
796: /* If function's value was promoted before return,
797: avoid machine mode mismatch when we substitute INLINE_TARGET.
798: But TARGET is what we will return to the caller. */
799: if (arriving_mode != departing_mode)
800: inline_target = gen_rtx (SUBREG, arriving_mode, target, 0);
801: }
1.1 root 802:
803: /* We are about to make space in this function's stack frame
804: for a copy of the stack frame of the inline function.
805: First, create an RTX that points to that stack frame
806: with the same offset usually used for the frame pointer.
807: This will be substituted for all frame-pointer references. */
808:
809: fp_delta = get_frame_size ();
810: #ifdef FRAME_GROWS_DOWNWARD
811: fp_delta = - fp_delta;
812: #endif
813: fp_delta -= STARTING_FRAME_OFFSET;
814:
815: inline_fp_rtx
816: = copy_to_mode_reg (Pmode,
817: plus_constant (frame_pointer_rtx, fp_delta));
818:
819: /* Now allocate the space for that to point at. */
820:
821: assign_stack_local (VOIDmode, DECL_FRAME_SIZE (fndecl));
822:
823: /* Now copy the insns one by one. */
824:
825: for (insn = insns; insn; insn = NEXT_INSN (insn))
826: {
827: rtx copy, pattern, next = 0;
828:
1.1.1.11 root 829: orig_asm_operands_vector = 0;
830: copy_asm_operands_vector = 0;
831:
1.1 root 832: switch (GET_CODE (insn))
833: {
834: case INSN:
835: pattern = PATTERN (insn);
836:
837: /* Special handling for the insn immediately after a CALL_INSN
838: that returned a value:
839: If it does copy the value, we must avoid the usual translation
840: of the return-register into INLINE_TARGET.
841: If it just USEs the value, the inline function expects it to
842: stay in the return-register and be returned,
843: so copy it into INLINE_TARGET. */
844:
845: if (follows_call
846: /* Allow a stack-adjust, handled normally, to come in between
847: the call and the value-copying insn. */
848: && ! (GET_CODE (pattern) == SET
849: && SET_DEST (pattern) == stack_pointer_rtx))
850: {
851: if (GET_CODE (pattern) == SET
852: && rtx_equal_p (SET_SRC (pattern), follows_call))
853: /* This insn copies the value: take special care to copy
854: that value to this insn's destination. */
855: {
856: copy = emit_insn (gen_rtx (SET, VOIDmode,
857: copy_rtx_and_substitute (SET_DEST (pattern)),
858: follows_call));
1.1.1.9 root 859: RTX_INTEGRATED_P (copy) = 1;
1.1 root 860: follows_call = 0;
861: break;
862: }
863: else if (GET_CODE (pattern) == USE
864: && rtx_equal_p (XEXP (pattern, 0), follows_call))
865: /* This insn does nothing but says the value is expected
866: to flow through to the inline function's return-value.
867: Make that happen, then ignore this insn. */
868: {
869: copy = emit_insn (gen_rtx (SET, VOIDmode, inline_target,
870: follows_call));
1.1.1.9 root 871: RTX_INTEGRATED_P (copy) = 1;
1.1 root 872: follows_call = 0;
873: break;
874: }
875: /* If it does neither, this value must be ignored. */
876: follows_call = 0;
877: }
878:
879: /* The (USE (REG n)) at return from the function should be ignored
880: since we are changing (REG n) into inline_target. */
1.1.1.6 root 881: copy = 0;
1.1 root 882: if (GET_CODE (pattern) == USE
883: && GET_CODE (XEXP (pattern, 0)) == REG
1.1.1.5 root 884: && REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
1.1 root 885: break;
886:
887: /* Try to do some quick constant folding here.
888: This will save save execution time of the compiler,
889: as well time and space of the program if done here. */
890: if (GET_CODE (pattern) == SET
891: && SET_DEST (pattern) == cc0_rtx)
892: next = try_fold_cc0 (insn);
893:
894: if (next != 0)
895: {
896: insn = next;
897: }
898: else
899: {
900: copy = emit_insn (copy_rtx_and_substitute (pattern));
1.1.1.9 root 901: RTX_INTEGRATED_P (copy) = 1;
1.1 root 902: }
903: break;
904:
905: case JUMP_INSN:
906: follows_call = 0;
907: if (GET_CODE (PATTERN (insn)) == RETURN)
908: {
1.1.1.9 root 909: if (local_return_label == 0)
910: local_return_label = gen_label_rtx ();
911: emit_jump (local_return_label);
1.1 root 912: break;
913: }
914: copy = emit_jump_insn (copy_rtx_and_substitute (PATTERN (insn)));
1.1.1.9 root 915: RTX_INTEGRATED_P (copy) = 1;
1.1 root 916: break;
917:
918: case CALL_INSN:
1.1.1.6 root 919: #if 0
920: /* This should no longer be necessary now that references
921: to this function's return value are flagged to distinguish
922: them from other references to the same hard register. */
1.1 root 923: {
924: rtx newbod;
925: /* If the call's body is (set (reg...) (call...)),
926: the register is a function return register, but DON'T
927: translate it into INLINE_TARGET because it describes the
928: called function, not the caller's return value. */
929: if (GET_CODE (PATTERN (insn)) == SET)
930: newbod = gen_rtx (SET, VOIDmode, SET_DEST (PATTERN (insn)),
931: copy_rtx_and_substitute (SET_SRC (PATTERN (insn))));
1.1.1.6 root 932: else if (GET_CODE (PATTERN (insn)) == PARALLEL
933: && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
934: {
935: register int j;
936: rtx newelem;
937: newbod = gen_rtx (PARALLEL, VOIDmode,
938: rtvec_alloc (XVECLEN (PATTERN (insn), 0)));
939: newelem = gen_rtx (SET, VOIDmode,
940: SET_DEST (XVECEXP (PATTERN (insn), 0, 0)),
941: copy_rtx_and_substitute (SET_SRC (XVECEXP (PATTERN (insn), 0, 0))));
942: XVECEXP (newbod, 0, 0) = newelem;
943: for (j = 1; j < XVECLEN (newbod, 0); j++)
944: XVECEXP (newbod, 0, j)
945: = copy_rtx_and_substitute (XVECEXP (PATTERN (insn), 0, j));
946: }
1.1 root 947: else
948: newbod = copy_rtx_and_substitute (PATTERN (insn));
949: copy = emit_call_insn (newbod);
950: }
1.1.1.6 root 951: #else /* 1 */
952: copy = emit_call_insn (copy_rtx_and_substitute (PATTERN (insn)));
953: #endif /* 1 */
1.1.1.9 root 954: RTX_INTEGRATED_P (copy) = 1;
1.1 root 955: /* Special handling needed for the following INSN depending on
956: whether it copies the value from the fcn return reg. */
957: if (GET_CODE (PATTERN (insn)) == SET)
958: follows_call = SET_DEST (PATTERN (insn));
959: break;
960:
961: case CODE_LABEL:
1.1.1.6 root 962: copy = emit_label (label_map[CODE_LABEL_NUMBER (insn)]);
1.1 root 963: follows_call = 0;
964: break;
965:
966: case BARRIER:
1.1.1.6 root 967: copy = emit_barrier ();
1.1 root 968: break;
969:
970: case NOTE:
1.1.1.7 root 971: if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
972: copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
973: else
974: copy = 0;
1.1 root 975: break;
976:
977: default:
978: abort ();
979: break;
980: }
1.1.1.6 root 981:
982: insn_map[INSN_UID (insn)] = copy;
1.1 root 983: }
984:
1.1.1.9 root 985: if (local_return_label)
986: emit_label (local_return_label);
1.1 root 987:
988: /* Make copies of the decls of the symbols in the inline function, so that
989: the copies of the variables get declared in the current function. */
990: copy_decl_tree (DECL_INITIAL (fndecl), 0);
991:
992: /* End the scope containing the copied formal parameter variables. */
993:
1.1.1.10 root 994: expand_end_bindings (getdecls (), 1, 1);
1.1 root 995: poplevel (1, 1, 0);
996:
997: reg_map = NULL;
998: label_map = NULL;
999:
1000: if (ignore || TYPE_MODE (type) == VOIDmode)
1001: return 0;
1002:
1003: if (structure_value_addr)
1004: {
1005: if (target)
1006: return target;
1007: return gen_rtx (MEM, BLKmode,
1008: memory_address (BLKmode, structure_value_addr));
1009: }
1010:
1.1.1.3 root 1011: return target;
1.1 root 1012: }
1013:
1014: /* Given a chain of PARM_DECLs, ARGS, and a vector of RTL homes VEC,
1015: copy each decl into a VAR_DECL, push all of those decls
1016: and give each one the corresponding home. */
1017:
1018: static void
1019: copy_parm_decls (args, vec)
1020: tree args;
1021: rtx *vec;
1022: {
1023: register tree tail;
1024: register int i;
1025:
1026: for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++)
1027: {
1028: register tree decl = pushdecl (build_decl (VAR_DECL, DECL_NAME (tail),
1029: TREE_TYPE (tail)));
1.1.1.9 root 1030: /* These args would always appear unused, if not for this. */
1031: TREE_USED (decl) = 1;
1.1 root 1032: DECL_RTL (decl) = vec[i];
1033: }
1034: }
1035:
1036: /* Given a LET_STMT node, push decls and levels
1037: so as to construct in the current function a tree of contexts
1038: isomorphic to the one that is given. */
1039:
1040: static void
1041: copy_decl_tree (let, level)
1042: tree let;
1043: int level;
1044: {
1045: tree t;
1046:
1047: pushlevel (0);
1048:
1049: for (t = STMT_VARS (let); t; t = TREE_CHAIN (t))
1050: {
1051: tree d = build_decl (TREE_CODE (t), DECL_NAME (t), TREE_TYPE (t));
1052: DECL_SOURCE_LINE (d) = DECL_SOURCE_LINE (t);
1053: DECL_SOURCE_FILE (d) = DECL_SOURCE_FILE (t);
1054: if (DECL_RTL (t) != 0)
1.1.1.8 root 1055: {
1056: if (GET_CODE (DECL_RTL (t)) == MEM
1057: && CONSTANT_ADDRESS_P (XEXP (DECL_RTL (t), 0)))
1058: /* copy_rtx_and_substitute would call memory_address
1059: which would copy the address into a register.
1060: Then debugging-output wouldn't know how to handle it. */
1061: DECL_RTL (d) = DECL_RTL (t);
1062: else
1063: DECL_RTL (d) = copy_rtx_and_substitute (DECL_RTL (t));
1064: }
1.1 root 1065: TREE_EXTERNAL (d) = TREE_EXTERNAL (t);
1066: TREE_STATIC (d) = TREE_STATIC (t);
1067: TREE_PUBLIC (d) = TREE_PUBLIC (t);
1068: TREE_LITERAL (d) = TREE_LITERAL (t);
1069: TREE_ADDRESSABLE (d) = TREE_ADDRESSABLE (t);
1070: TREE_READONLY (d) = TREE_READONLY (t);
1071: TREE_VOLATILE (d) = TREE_VOLATILE (t);
1.1.1.9 root 1072: /* These args would always appear unused, if not for this. */
1073: TREE_USED (d) = 1;
1.1 root 1074: pushdecl (d);
1075: }
1076:
1077: for (t = STMT_BODY (let); t; t = TREE_CHAIN (t))
1078: copy_decl_tree (t, level + 1);
1079:
1080: poplevel (level > 0, 0, 0);
1081: }
1082:
1083: /* Create a new copy of an rtx.
1084: Recursively copies the operands of the rtx,
1085: except for those few rtx codes that are sharable. */
1086:
1087: static rtx
1088: copy_rtx_and_substitute (orig)
1089: register rtx orig;
1090: {
1091: register rtx copy, temp;
1092: register int i, j;
1093: register RTX_CODE code;
1094: register enum machine_mode mode;
1095: register char *format_ptr;
1096: int regno;
1097:
1098: if (orig == 0)
1099: return 0;
1100:
1101: code = GET_CODE (orig);
1102: mode = GET_MODE (orig);
1103:
1104: switch (code)
1105: {
1106: case REG:
1107: /* If a frame-pointer register shows up, then we
1108: must `fix' the reference. If the stack pointer
1109: register shows up, it must be part of stack-adjustments
1110: (*not* because we eliminated the frame pointer!).
1111: Small hard registers are returned as-is. Pseudo-registers
1112: go through their `reg_map'. */
1113: regno = REGNO (orig);
1114: if (regno < FIRST_PSEUDO_REGISTER)
1115: {
1.1.1.5 root 1116: if (REG_FUNCTION_VALUE_P (orig))
1.1.1.9 root 1117: {
1118: /* This is a reference to the function return value. If
1119: the function doesn't have a return value, error.
1120: If it does, it may not be the same mode as `inline_target'
1121: because SUBREG is not required for hard regs.
1122: If not, adjust mode of inline_target to fit the context. */
1123: if (inline_target == 0)
1124: abort ();
1125: if (mode == GET_MODE (inline_target))
1126: return inline_target;
1127: return gen_rtx (SUBREG, mode, inline_target, 0);
1128: }
1.1 root 1129: if (regno == FRAME_POINTER_REGNUM)
1130: return plus_constant (orig, fp_delta);
1131: return orig;
1132: }
1133: if (reg_map[regno] == NULL)
1134: reg_map[regno] = gen_reg_rtx (mode);
1135: return reg_map[regno];
1136:
1137: case CODE_LABEL:
1138: return label_map[CODE_LABEL_NUMBER (orig)];
1139:
1140: case LABEL_REF:
1141: copy = rtx_alloc (LABEL_REF);
1142: PUT_MODE (copy, mode);
1143: XEXP (copy, 0) = label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))];
1144: return copy;
1145:
1146: case PC:
1147: case CC0:
1148: case CONST_INT:
1149: case CONST_DOUBLE:
1150: case SYMBOL_REF:
1151: return orig;
1152:
1.1.1.11 root 1153: case ASM_OPERANDS:
1154: /* If a single asm insn contains multiple output operands
1155: then it contains multiple ASM_OPERANDS rtx's that share operand 3.
1156: We must make sure that the copied insn continues to share it. */
1157: if (orig_asm_operands_vector == XVEC (orig, 3))
1158: {
1159: copy = rtx_alloc (ASM_OPERANDS);
1160: XSTR (copy, 0) = XSTR (orig, 0);
1161: XSTR (copy, 1) = XSTR (orig, 1);
1162: XINT (copy, 2) = XINT (orig, 2);
1163: XVEC (copy, 3) = copy_asm_operands_vector;
1164: XVEC (copy, 4) = XVEC (orig, 4);
1165: return copy;
1166: }
1167: break;
1168:
1.1.1.5 root 1169: case CALL:
1170: /* This is given special treatment because the first
1171: operand of a CALL is a (MEM ...) which may get
1172: forced into a register for cse. This is undesirable
1173: if function-address cse isn't wanted or if we won't do cse. */
1174: #ifndef NO_FUNCTION_CSE
1175: if (! (optimize && ! flag_no_function_cse))
1176: #endif
1177: return gen_rtx (CALL, GET_MODE (orig),
1178: gen_rtx (MEM, GET_MODE (XEXP (orig, 0)),
1179: copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0))),
1180: copy_rtx_and_substitute (XEXP (orig, 1)));
1181: break;
1182:
1.1 root 1183: case PLUS:
1184: /* Note: the PLUS case is not nearly as careful as the MEM
1185: case in terms of preserving addresses. The reason for this
1186: is that it is expected that if a PLUS_EXPR turns out not
1187: to be a legitimate address, reload can fix that up, without
1188: doing major damage. However, a MEM rtx must preside
1189: over a legitimate address. The MEM case has lots of hair
1190: to deal with what happens when it sits on a PLUS... */
1191: /* Take care of the easy case quickly. */
1192: if (XEXP (orig, 0) == frame_pointer_rtx
1193: || XEXP (orig, 1) == frame_pointer_rtx
1194: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
1195: && (XEXP (orig, 0) == arg_pointer_rtx
1196: || XEXP (orig, 1) == arg_pointer_rtx)))
1197: {
1198: if (XEXP (orig, 0) == frame_pointer_rtx
1199: || XEXP (orig, 0) == arg_pointer_rtx)
1200: copy = XEXP (orig, 1);
1201: else
1202: copy = XEXP (orig, 0);
1203:
1204: if (GET_CODE (copy) == CONST_INT)
1205: {
1206: int c = INTVAL (copy);
1207:
1208: if (c > 0)
1209: {
1210: copy = parm_map[c / UNITS_PER_WORD];
1211: return XEXP (copy, 0);
1212: }
1213: return gen_rtx (PLUS, mode,
1214: frame_pointer_rtx,
1215: gen_rtx (CONST_INT, SImode,
1216: c + fp_delta));
1217: }
1218: copy = copy_rtx_and_substitute (copy);
1.1.1.6 root 1219: temp = force_reg (mode, gen_rtx (PLUS, mode, frame_pointer_rtx, copy));
1.1 root 1220: return plus_constant (temp, fp_delta);
1221: }
1222: else if (reg_mentioned_p (frame_pointer_rtx, orig)
1223: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
1224: && reg_mentioned_p (arg_pointer_rtx, orig)))
1225: {
1226: /* If we have a complex sum which has a frame pointer
1227: in it, and it was a legitimate address, then
1228: keep it that way. */
1229: if (memory_address_p (mode, orig))
1230: {
1231: if (GET_CODE (XEXP (orig, 0)) == CONST_INT)
1232: {
1233: copy = copy_rtx_and_substitute (XEXP (orig, 1));
1234: temp = plus_constant (copy, INTVAL (XEXP (orig, 0)));
1235: }
1236: else if (GET_CODE (XEXP (orig, 1)) == CONST_INT)
1237: {
1238: copy = copy_rtx_and_substitute (XEXP (orig, 0));
1239: temp = plus_constant (copy, INTVAL (XEXP (orig, 1)));
1240: }
1241: else
1242: {
1243: temp = gen_rtx (PLUS, GET_MODE (orig),
1244: copy_rtx_and_substitute (XEXP (orig, 0)),
1245: copy_rtx_and_substitute (XEXP (orig, 1)));
1246: }
1247: temp = memory_address (mode, temp);
1248: }
1249: else
1250: temp = gen_rtx (PLUS, GET_MODE (orig),
1251: copy_rtx_and_substitute (XEXP (orig, 0)),
1252: copy_rtx_and_substitute (XEXP (orig, 1)));
1253: }
1254: else
1255: temp = gen_rtx (PLUS, GET_MODE (orig),
1256: copy_rtx_and_substitute (XEXP (orig, 0)),
1257: copy_rtx_and_substitute (XEXP (orig, 1)));
1258:
1259: return temp;
1.1.1.7 root 1260:
1.1 root 1261: case MEM:
1262: /* Take care of easiest case here. */
1263: copy = XEXP (orig, 0);
1264: if (copy == frame_pointer_rtx || copy == arg_pointer_rtx)
1265: return gen_rtx (MEM, mode,
1266: plus_constant (frame_pointer_rtx, fp_delta));
1.1.1.6 root 1267:
1268: /* Allow a pushing-address even if that is not valid as an
1269: ordinary memory address. It indicates we are inlining a special
1.1.1.9 root 1270: push-insn. These must be copied; otherwise unshare_all_rtl
1271: might clobber them to point at temporary rtl of this function. */
1.1.1.6 root 1272: #ifdef STACK_GROWS_DOWNWARD
1273: if (GET_CODE (copy) == PRE_DEC && XEXP (copy, 0) == stack_pointer_rtx)
1.1.1.9 root 1274: return gen_rtx (MEM, mode, copy_rtx_and_substitute (copy));
1.1.1.6 root 1275: #else
1276: if (GET_CODE (copy) == PRE_INC && XEXP (copy, 0) == stack_pointer_rtx)
1.1.1.9 root 1277: return gen_rtx (MEM, mode, copy_rtx_and_substitute (copy));
1.1.1.6 root 1278: #endif
1279:
1.1.1.7 root 1280: /* If this is some other sort of address that isn't generally valid,
1281: break out all the registers referred to. */
1282: if (! memory_address_p (mode, copy))
1283: return gen_rtx (MEM, mode, copy_address (copy));
1284:
1.1 root 1285: if (GET_CODE (copy) == PLUS)
1286: {
1287: if (XEXP (copy, 0) == frame_pointer_rtx
1288: || XEXP (copy, 1) == frame_pointer_rtx
1289: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
1290: && (XEXP (copy, 0) == arg_pointer_rtx
1291: || XEXP (copy, 1) == arg_pointer_rtx)))
1292: {
1293: rtx reg;
1294: if (XEXP (copy, 0) == frame_pointer_rtx
1295: || XEXP (copy, 0) == arg_pointer_rtx)
1296: reg = XEXP (copy, 0), copy = XEXP (copy, 1);
1297: else
1298: reg = XEXP (copy, 1), copy = XEXP (copy, 0);
1299:
1300: if (GET_CODE (copy) == CONST_INT)
1301: {
1302: int c = INTVAL (copy);
1303:
1.1.1.7 root 1304: if (reg == arg_pointer_rtx && c >= first_parm_offset)
1.1 root 1305: {
1.1.1.10 root 1306: int index = c / UNITS_PER_WORD;
1307: int offset = c % UNITS_PER_WORD;
1308:
1309: /* If we are referring to the middle of a multiword parm,
1310: find the beginning of that parm.
1311: OFFSET gets the offset of the reference from
1312: the beginning of the parm. */
1313:
1314: while (parm_map[index] == 0)
1315: {
1316: index--;
1317: if (index < first_parm_offset / UNITS_PER_WORD)
1318: /* If this abort happens, it means we need
1319: to handle "decrementing" INDEX back far
1320: enough to start looking among the reg parms
1321: instead of the stack parms. What a mess! */
1322: abort ();
1323: offset += UNITS_PER_WORD;
1324: }
1325:
1326: copy = parm_map[index];
1327:
1.1.1.11 root 1328: #ifdef BYTES_BIG_ENDIAN
1.1.1.10 root 1329: /* Subtract from OFFSET the offset of where
1330: the actual parm value would start. */
1331: if (GET_MODE_SIZE (GET_MODE (copy)) < UNITS_PER_WORD)
1332: offset
1333: -= (UNITS_PER_WORD
1334: - GET_MODE_SIZE (GET_MODE (copy)));
1335: #endif
1.1 root 1336:
1337: /* If the MEM is only some of the bytes in the parm,
1.1.1.10 root 1338: effectively perform a SUBREG of the actual parm. */
1339: if ((GET_MODE (copy) != mode
1340: && GET_MODE (copy) != VOIDmode))
1341: {
1.1.1.11 root 1342: if (GET_CODE (copy) == MEM)
1343: return change_address (copy, mode,
1344: plus_constant (XEXP (copy, 0),
1345: offset));
1346: if (GET_CODE (copy) == REG)
1347: {
1348: /* Crash if the portion of the arg wanted
1349: is not the least significant.
1350: Functions with refs to other parts of a
1351: parameter should not be inline--
1352: see function_cannot_inline_p. */
1353: #ifdef BYTES_BIG_ENDIAN
1354: if (offset + GET_MODE_SIZE (mode)
1355: != GET_MODE_SIZE (GET_MODE (copy)))
1356: abort ();
1357: #else
1358: if (offset != 0)
1359: abort ();
1360: #endif
1361: return gen_rtx (SUBREG, mode, copy, 0);
1362: }
1363:
1364: abort ();
1.1.1.10 root 1365: }
1.1 root 1366: return copy;
1367: }
1368: temp = gen_rtx (PLUS, Pmode,
1369: frame_pointer_rtx,
1370: gen_rtx (CONST_INT, SImode,
1371: c + fp_delta));
1372: if (! memory_address_p (Pmode, temp))
1373: return gen_rtx (MEM, mode, plus_constant (inline_fp_rtx, c));
1374: }
1375: copy = copy_rtx_and_substitute (copy);
1376: temp = gen_rtx (PLUS, Pmode, frame_pointer_rtx, copy);
1377: temp = plus_constant (temp, fp_delta);
1378: temp = memory_address (Pmode, temp);
1379: }
1380: else if (reg_mentioned_p (frame_pointer_rtx, copy)
1381: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
1382: && reg_mentioned_p (arg_pointer_rtx, copy)))
1383: {
1384: if (GET_CODE (XEXP (copy, 0)) == CONST_INT)
1385: {
1386: temp = copy_rtx_and_substitute (XEXP (copy, 1));
1387: temp = plus_constant (temp, INTVAL (XEXP (copy, 0)));
1388: }
1389: else if (GET_CODE (XEXP (copy, 1)) == CONST_INT)
1390: {
1391: temp = copy_rtx_and_substitute (XEXP (copy, 0));
1392: temp = plus_constant (temp, INTVAL (XEXP (copy, 1)));
1393: }
1394: else
1395: {
1396: temp = gen_rtx (PLUS, GET_MODE (copy),
1397: copy_rtx_and_substitute (XEXP (copy, 0)),
1398: copy_rtx_and_substitute (XEXP (copy, 1)));
1399: }
1400: }
1401: else
1402: {
1403: if (GET_CODE (XEXP (copy, 1)) == CONST_INT)
1404: temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 0)),
1405: INTVAL (XEXP (copy, 1)));
1406: else if (GET_CODE (XEXP (copy, 0)) == CONST_INT)
1407: temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 1)),
1408: INTVAL (XEXP (copy, 0)));
1409: else
1410: {
1411: rtx left = copy_rtx_and_substitute (XEXP (copy, 0));
1412: rtx right = copy_rtx_and_substitute (XEXP (copy, 1));
1413:
1414: temp = gen_rtx (PLUS, GET_MODE (copy), left, right);
1415: }
1416: }
1417: }
1418: else
1419: temp = copy_rtx_and_substitute (copy);
1420:
1421: return change_address (orig, mode, temp);
1422:
1423: case RETURN:
1424: abort ();
1425: }
1426:
1427: copy = rtx_alloc (code);
1428: PUT_MODE (copy, mode);
1429: copy->in_struct = orig->in_struct;
1430: copy->volatil = orig->volatil;
1431: copy->unchanging = orig->unchanging;
1432:
1433: format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
1434:
1435: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
1436: {
1437: switch (*format_ptr++)
1438: {
1439: case '0':
1440: break;
1441:
1442: case 'e':
1443: XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i));
1444: break;
1445:
1.1.1.6 root 1446: case 'u':
1447: /* Change any references to old-insns to point to the
1448: corresponding copied insns. */
1.1.1.9 root 1449: XEXP (copy, i) = insn_map[INSN_UID (XEXP (orig, i))];
1450: break;
1.1.1.6 root 1451:
1.1 root 1452: case 'E':
1453: XVEC (copy, i) = XVEC (orig, i);
1.1.1.6 root 1454: if (XVEC (orig, i) != NULL && XVECLEN (orig, i) != 0)
1.1 root 1455: {
1456: XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
1457: for (j = 0; j < XVECLEN (copy, i); j++)
1458: XVECEXP (copy, i, j) = copy_rtx_and_substitute (XVECEXP (orig, i, j));
1459: }
1460: break;
1461:
1462: case 'i':
1463: XINT (copy, i) = XINT (orig, i);
1464: break;
1465:
1466: case 's':
1467: XSTR (copy, i) = XSTR (orig, i);
1468: break;
1469:
1470: default:
1471: abort ();
1472: }
1473: }
1.1.1.11 root 1474:
1475: if (code == ASM_OPERANDS && orig_asm_operands_vector == 0)
1476: {
1477: orig_asm_operands_vector = XVEC (orig, 3);
1478: copy_asm_operands_vector = XVEC (copy, 3);
1479: }
1480:
1.1 root 1481: return copy;
1482: }
1483:
1.1.1.7 root 1484: /* Like copy_rtx_and_substitute but produces different output, suitable
1485: for an ideosyncractic address that isn't memory_address_p.
1486: The output resembles the input except that REGs and MEMs are replaced
1487: with new psuedo registers. All the "real work" is done in separate
1488: insns which set up the values of these new registers. */
1489:
1490: static rtx
1491: copy_address (orig)
1492: register rtx orig;
1493: {
1.1.1.9 root 1494: register rtx copy;
1.1.1.7 root 1495: register int i, j;
1496: register RTX_CODE code;
1497: register enum machine_mode mode;
1498: register char *format_ptr;
1499:
1500: if (orig == 0)
1501: return 0;
1502:
1503: code = GET_CODE (orig);
1504: mode = GET_MODE (orig);
1505:
1506: switch (code)
1507: {
1508: case REG:
1.1.1.9 root 1509: if (REGNO (orig) != FRAME_POINTER_REGNUM)
1510: return copy_rtx_and_substitute (orig);
1511: return plus_constant (frame_pointer_rtx, fp_delta);
1512:
1513: case PLUS:
1514: if (GET_CODE (XEXP (orig, 0)) == REG
1515: && REGNO (XEXP (orig, 0)) == FRAME_POINTER_REGNUM)
1516: return plus_constant (orig, fp_delta);
1517: break;
1518:
1.1.1.7 root 1519: case MEM:
1.1.1.9 root 1520: return copy_to_reg (copy_rtx_and_substitute (orig));
1.1.1.7 root 1521:
1522: case CODE_LABEL:
1523: case LABEL_REF:
1.1.1.9 root 1524: return copy_rtx_and_substitute (orig);
1.1.1.7 root 1525:
1526: case PC:
1527: case CC0:
1528: case CONST_INT:
1529: case CONST_DOUBLE:
1530: case SYMBOL_REF:
1531: return orig;
1532: }
1533:
1534: copy = rtx_alloc (code);
1535: PUT_MODE (copy, mode);
1536: copy->in_struct = orig->in_struct;
1537: copy->volatil = orig->volatil;
1538: copy->unchanging = orig->unchanging;
1539:
1540: format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
1541:
1542: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
1543: {
1544: switch (*format_ptr++)
1545: {
1546: case '0':
1547: break;
1548:
1549: case 'e':
1550: XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i));
1551: break;
1552:
1553: case 'u':
1554: /* Change any references to old-insns to point to the
1555: corresponding copied insns. */
1.1.1.9 root 1556: XEXP (copy, i) = insn_map[INSN_UID (XEXP (orig, i))];
1557: break;
1.1.1.7 root 1558:
1559: case 'E':
1560: XVEC (copy, i) = XVEC (orig, i);
1561: if (XVEC (orig, i) != NULL && XVECLEN (orig, i) != 0)
1562: {
1563: XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
1564: for (j = 0; j < XVECLEN (copy, i); j++)
1565: XVECEXP (copy, i, j) = copy_rtx_and_substitute (XVECEXP (orig, i, j));
1566: }
1567: break;
1568:
1569: case 'i':
1570: XINT (copy, i) = XINT (orig, i);
1571: break;
1572:
1573: case 's':
1574: XSTR (copy, i) = XSTR (orig, i);
1575: break;
1576:
1577: default:
1578: abort ();
1579: }
1580: }
1581: return copy;
1582: }
1583:
1.1 root 1584: /* Attempt to simplify INSN while copying it from an inline fn,
1585: assuming it is a SET that sets CC0.
1586:
1587: If we simplify it, we emit the appropriate insns and return
1588: the last insn that we have handled (since we may handle the insn
1589: that follows INSN as well as INSN itself).
1590:
1591: Otherwise we do nothing and return zero. */
1592:
1593: static rtx
1594: try_fold_cc0 (insn)
1595: rtx insn;
1596: {
1597: rtx cnst = copy_rtx_and_substitute (SET_SRC (PATTERN (insn)));
1598: rtx pat, copy;
1599:
1600: if (CONSTANT_P (cnst)
1601: /* @@ Cautious: Don't know how many of these tests we need. */
1602: && NEXT_INSN (insn)
1603: && GET_CODE (pat = PATTERN (NEXT_INSN (insn))) == SET
1604: && SET_DEST (pat) == pc_rtx
1605: && GET_CODE (pat = SET_SRC (pat)) == IF_THEN_ELSE
1606: && GET_RTX_LENGTH (GET_CODE (XEXP (pat, 0))) == 2)
1607: {
1608: rtx cnst2;
1609: rtx cond = XEXP (pat, 0);
1610:
1611: if ((XEXP (cond, 0) == cc0_rtx
1612: && CONSTANT_P (XEXP (cond, 1))
1613: && (cnst2 = XEXP (cond, 1)))
1614: || (XEXP (cond, 1) == cc0_rtx
1615: && CONSTANT_P (XEXP (cond, 0))
1616: && (cnst2 = XEXP (cond, 0))))
1617: {
1618: copy = fold_out_const_cc0 (cond, XEXP (pat, 1), XEXP (pat, 2),
1619: cnst, cnst2);
1620: if (copy)
1621: {
1622: if (GET_CODE (copy) == LABEL_REF)
1623: {
1624: /* We will branch unconditionally to
1625: the label specified by COPY.
1626: Eliminate dead code by running down the
1627: list of insn until we see a CODE_LABEL.
1628: If the CODE_LABEL is the one specified
1629: by COPY, we win, and can delete all code
1630: up to (but not necessarily including)
1631: that label. Otherwise only win a little:
1632: emit the branch insn, and continue expanding. */
1633: rtx tmp = NEXT_INSN (insn);
1634: while (tmp && GET_CODE (tmp) != CODE_LABEL)
1635: tmp = NEXT_INSN (tmp);
1636: if (! tmp)
1637: abort ();
1638: if (label_map[CODE_LABEL_NUMBER (tmp)] == XEXP (copy, 0))
1639: {
1640: /* Big win. */
1641: return PREV_INSN (tmp);
1642: }
1643: else
1644: {
1645: /* Small win. Emit the unconditional branch,
1646: followed by a BARRIER, so that jump optimization
1647: will know what to do. */
1648: emit_jump (copy);
1649: return NEXT_INSN (insn);
1650: }
1651: }
1652: else if (copy == pc_rtx)
1653: {
1654: /* Do not take the branch, just fall through.
1655: Jump optimize should handle the elimination of
1656: dead code if appropriate. */
1657: return NEXT_INSN (insn);
1658: }
1659: else
1660: abort ();
1661: }
1662: }
1663: }
1664: return 0;
1665: }
1666:
1667: /* If (COND_RTX CNST1 CNST2) yield a result we can treat
1668: as being constant, return THEN_RTX if the result is always
1669: non-zero, and return ELSE_RTX otherwise. */
1670: static rtx
1671: fold_out_const_cc0 (cond_rtx, then_rtx, else_rtx, cnst1, cnst2)
1672: rtx cond_rtx, then_rtx, else_rtx;
1673: rtx cnst1, cnst2;
1674: {
1675: int value1, value2;
1676: int int1 = GET_CODE (cnst1) == CONST_INT;
1677: int int2 = GET_CODE (cnst2) == CONST_INT;
1678: if (int1)
1679: value1 = INTVAL (cnst1);
1680: else
1681: value1 = 1;
1682: if (int2)
1683: value2 = INTVAL (cnst2);
1684: else
1685: value2 = 1;
1686:
1687: switch (GET_CODE (cond_rtx))
1688: {
1689: case NE:
1690: if (int1 && int2)
1691: if (value1 != value2)
1692: return copy_rtx_and_substitute (then_rtx);
1693: else
1694: return copy_rtx_and_substitute (else_rtx);
1695: if (value1 == 0 || value2 == 0)
1696: return copy_rtx_and_substitute (then_rtx);
1697: if (int1 == 0 && int2 == 0)
1698: if (rtx_equal_p (cnst1, cnst2))
1699: return copy_rtx_and_substitute (else_rtx);
1700: break;
1701: case EQ:
1702: if (int1 && int2)
1703: if (value1 == value2)
1704: return copy_rtx_and_substitute (then_rtx);
1705: else
1706: return copy_rtx_and_substitute (else_rtx);
1707: if (value1 == 0 || value2 == 0)
1708: return copy_rtx_and_substitute (else_rtx);
1709: if (int1 == 0 && int2 == 0)
1710: if (rtx_equal_p (cnst1, cnst2))
1711: return copy_rtx_and_substitute (then_rtx);
1712: break;
1713: case GE:
1714: if (int1 && int2)
1715: if (value1 >= value2)
1716: return copy_rtx_and_substitute (then_rtx);
1717: else
1718: return copy_rtx_and_substitute (else_rtx);
1719: if (value1 == 0)
1720: return copy_rtx_and_substitute (else_rtx);
1721: if (value2 == 0)
1722: return copy_rtx_and_substitute (then_rtx);
1723: break;
1724: case GT:
1725: if (int1 && int2)
1726: if (value1 > value2)
1727: return copy_rtx_and_substitute (then_rtx);
1728: else
1729: return copy_rtx_and_substitute (else_rtx);
1730: if (value1 == 0)
1731: return copy_rtx_and_substitute (else_rtx);
1732: if (value2 == 0)
1733: return copy_rtx_and_substitute (then_rtx);
1734: break;
1735: case LE:
1736: if (int1 && int2)
1737: if (value1 <= value2)
1738: return copy_rtx_and_substitute (then_rtx);
1739: else
1740: return copy_rtx_and_substitute (else_rtx);
1741: if (value1 == 0)
1742: return copy_rtx_and_substitute (then_rtx);
1743: if (value2 == 0)
1744: return copy_rtx_and_substitute (else_rtx);
1745: break;
1746: case LT:
1747: if (int1 && int2)
1748: if (value1 < value2)
1749: return copy_rtx_and_substitute (then_rtx);
1750: else
1751: return copy_rtx_and_substitute (else_rtx);
1752: if (value1 == 0)
1753: return copy_rtx_and_substitute (then_rtx);
1754: if (value2 == 0)
1755: return copy_rtx_and_substitute (else_rtx);
1756: break;
1757: case GEU:
1758: if (int1 && int2)
1759: if ((unsigned)value1 >= (unsigned)value2)
1760: return copy_rtx_and_substitute (then_rtx);
1761: else
1762: return copy_rtx_and_substitute (else_rtx);
1763: if (value1 == 0)
1764: return copy_rtx_and_substitute (else_rtx);
1765: if (value2 == 0)
1766: return copy_rtx_and_substitute (then_rtx);
1767: break;
1768: case GTU:
1769: if (int1 && int2)
1770: if ((unsigned)value1 > (unsigned)value2)
1771: return copy_rtx_and_substitute (then_rtx);
1772: else
1773: return copy_rtx_and_substitute (else_rtx);
1774: if (value1 == 0)
1775: return copy_rtx_and_substitute (else_rtx);
1776: if (value2 == 0)
1777: return copy_rtx_and_substitute (then_rtx);
1778: break;
1779: case LEU:
1780: if (int1 && int2)
1781: if ((unsigned)value1 <= (unsigned)value2)
1782: return copy_rtx_and_substitute (then_rtx);
1783: else
1784: return copy_rtx_and_substitute (else_rtx);
1785: if (value1 == 0)
1786: return copy_rtx_and_substitute (then_rtx);
1787: if (value2 == 0)
1788: return copy_rtx_and_substitute (else_rtx);
1789: break;
1790: case LTU:
1791: if (int1 && int2)
1792: if ((unsigned)value1 < (unsigned)value2)
1793: return copy_rtx_and_substitute (then_rtx);
1794: else
1795: return copy_rtx_and_substitute (else_rtx);
1796: if (value1 == 0)
1797: return copy_rtx_and_substitute (then_rtx);
1798: if (value2 == 0)
1799: return copy_rtx_and_substitute (else_rtx);
1800: break;
1801: }
1802: /* Could not hack it. */
1803: return 0;
1804: }
1805:
1806: /* Output the assembly language code for the function FNDECL
1807: from its DECL_SAVED_INSNS. Used for inline functions that are output
1808: at end of compilation instead of where they came in the source. */
1809:
1810: void
1811: output_inline_function (fndecl)
1812: tree fndecl;
1813: {
1814: rtx head = DECL_SAVED_INSNS (fndecl);
1815: rtx last;
1816:
1817: temporary_allocation ();
1818:
1.1.1.4 root 1819: current_function_decl = fndecl;
1820:
1.1 root 1821: /* This call is only used to initialize global variables.
1822: The rtl code it emits will be discarded below. */
1823: expand_function_start (fndecl);
1824:
1825: /* Set stack frame size. */
1826: assign_stack_local (BLKmode, DECL_FRAME_SIZE (fndecl));
1827:
1828: restore_reg_data (FIRST_PARM_INSN (head));
1829:
1.1.1.10 root 1830: expand_function_end (DECL_SOURCE_FILE (fndecl), DECL_SOURCE_LINE (fndecl));
1.1 root 1831:
1832: for (last = head; NEXT_INSN (last); last = NEXT_INSN (last))
1833: ;
1834:
1835: set_new_first_and_last_insn (FIRST_PARM_INSN (head), last);
1836:
1837: /* Compile this function all the way down to assembly code. */
1838: rest_of_compilation (fndecl);
1839:
1.1.1.4 root 1840: current_function_decl = 0;
1841:
1.1 root 1842: permanent_allocation ();
1843: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.