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