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