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