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