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