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