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