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