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