summaryrefslogtreecommitdiff
path: root/gcc/integrate.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/integrate.c')
-rw-r--r--gcc/integrate.c1847
1 files changed, 20 insertions, 1827 deletions
diff --git a/gcc/integrate.c b/gcc/integrate.c
index 3a58f2cda04..de897176ea0 100644
--- a/gcc/integrate.c
+++ b/gcc/integrate.c
@@ -41,26 +41,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "function.h"
#include "toplev.h"
#include "intl.h"
-#include "loop.h"
#include "params.h"
#include "ggc.h"
#include "target.h"
#include "langhooks.h"
-/* Similar, but round to the next highest integer that meets the
- alignment. */
+/* Round to the next highest integer that meets the alignment. */
#define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
-
-/* Default max number of insns a function can have and still be inline.
- This is overridden on RISC machines. */
-#ifndef INTEGRATE_THRESHOLD
-/* Inlining small functions might save more space then not inlining at
- all. Assume 1 instruction for the call and 1.5 insns per argument. */
-#define INTEGRATE_THRESHOLD(DECL) \
- (optimize_size \
- ? (1 + (3 * list_length (DECL_ARGUMENTS (DECL))) / 2) \
- : (8 * (8 + list_length (DECL_ARGUMENTS (DECL)))))
-#endif
/* Private type used by {get/has}_func_hard_reg_initial_val. */
@@ -74,29 +61,10 @@ typedef struct initial_value_struct GTY(()) {
initial_value_pair * GTY ((length ("%h.num_entries"))) entries;
} initial_value_struct;
-static void setup_initial_hard_reg_value_integration (struct function *,
- struct inline_remap *);
-
-static rtvec initialize_for_inline (tree);
-static void note_modified_parmregs (rtx, rtx, void *);
-static void integrate_parm_decls (tree, struct inline_remap *, rtvec);
-static tree integrate_decl_tree (tree, struct inline_remap *);
static void subst_constants (rtx *, rtx, struct inline_remap *, int);
static void set_block_origin_self (tree);
static void set_block_abstract_flags (tree, int);
-static void process_reg_param (struct inline_remap *, rtx, rtx);
static void mark_stores (rtx, rtx, void *);
-static void save_parm_insns (rtx, rtx);
-static void copy_insn_list (rtx, struct inline_remap *, rtx);
-static void copy_insn_notes (rtx, struct inline_remap *, int);
-static int compare_blocks (const void *, const void *);
-static int find_block (const void *, const void *);
-
-/* Used by copy_rtx_and_substitute; this indicates whether the function is
- called for the purpose of inlining or some other purpose (i.e. loop
- unrolling). This affects how constant pool references are handled.
- This variable contains the FUNCTION_DECL for the inlined function. */
-static struct function *inlining = 0;
/* Returns the Ith entry in the label_map contained in MAP. If the
Ith entry has not yet been set, return a fresh label. This function
@@ -136,195 +104,7 @@ function_attribute_inlinable_p (tree fndecl)
return true;
}
-
-/* Zero if the current function (whose FUNCTION_DECL is FNDECL)
- is safe and reasonable to integrate into other functions.
- Nonzero means value is a warning msgid with a single %s
- for the function's name. */
-
-const char *
-function_cannot_inline_p (tree fndecl)
-{
- rtx insn;
- tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
-
- /* For functions marked as inline increase the maximum size to
- MAX_INLINE_INSNS_RTL (--param max-inline-insn-rtl=<n>). For
- regular functions use the limit given by INTEGRATE_THRESHOLD.
- Note that the RTL inliner is not used by the languages that use
- the tree inliner (C, C++). */
-
- int max_insns = (DECL_INLINE (fndecl))
- ? (MAX_INLINE_INSNS_RTL
- + 8 * list_length (DECL_ARGUMENTS (fndecl)))
- : INTEGRATE_THRESHOLD (fndecl);
-
- int ninsns = 0;
- tree parms;
-
- if (DECL_UNINLINABLE (fndecl))
- return N_("function cannot be inline");
-
- /* No inlines with varargs. */
- if (last && TREE_VALUE (last) != void_type_node)
- return N_("varargs function cannot be inline");
-
- if (current_function_calls_alloca)
- return N_("function using alloca cannot be inline");
-
- if (current_function_calls_longjmp)
- return N_("function using longjmp cannot be inline");
-
- if (current_function_calls_setjmp)
- return N_("function using setjmp cannot be inline");
-
- if (current_function_calls_eh_return)
- return N_("function uses __builtin_eh_return");
-
- if (current_function_contains_functions)
- return N_("function with nested functions cannot be inline");
-
- if (forced_labels)
- return
- N_("function with label addresses used in initializers cannot inline");
-
- if (current_function_cannot_inline)
- return current_function_cannot_inline;
-
- /* If it's not even close, don't even look. */
- if (get_max_uid () > 3 * max_insns)
- return N_("function too large to be inline");
-
-#if 0
- /* Don't inline functions which do not specify a function prototype and
- have BLKmode argument or take the address of a parameter. */
- for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
- {
- if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode)
- TREE_ADDRESSABLE (parms) = 1;
- if (last == NULL_TREE && TREE_ADDRESSABLE (parms))
- return N_("no prototype, and parameter address used; cannot be inline");
- }
-#endif
-
- /* We can't inline functions that return structures
- the old-fashioned PCC way, copying into a static block. */
- if (current_function_returns_pcc_struct)
- return N_("inline functions not supported for this return value type");
-
- /* We can't inline functions that return structures of varying size. */
- if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE
- && int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0)
- return N_("function with varying-size return value cannot be inline");
-
- /* Cannot inline a function with a varying size argument or one that
- receives a transparent union. */
- for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
- {
- if (int_size_in_bytes (TREE_TYPE (parms)) < 0)
- return N_("function with varying-size parameter cannot be inline");
- else if (TREE_CODE (TREE_TYPE (parms)) == UNION_TYPE
- && TYPE_TRANSPARENT_UNION (TREE_TYPE (parms)))
- return N_("function with transparent unit parameter cannot be inline");
- }
-
- if (get_max_uid () > max_insns)
- {
- for (ninsns = 0, insn = get_first_nonparm_insn ();
- insn && ninsns < max_insns;
- insn = NEXT_INSN (insn))
- if (INSN_P (insn))
- ninsns++;
-
- if (ninsns >= max_insns)
- return N_("function too large to be inline");
- }
-
- /* We will not inline a function which uses computed goto. The addresses of
- its local labels, which may be tucked into global storage, are of course
- not constant across instantiations, which causes unexpected behavior. */
- if (current_function_has_computed_jump)
- return N_("function with computed jump cannot inline");
-
- /* We cannot inline a nested function that jumps to a nonlocal label. */
- if (current_function_has_nonlocal_goto)
- return N_("function with nonlocal goto cannot be inline");
-
- /* We can't inline functions that return a PARALLEL rtx. */
- if (DECL_RTL_SET_P (DECL_RESULT (fndecl)))
- {
- rtx result = DECL_RTL (DECL_RESULT (fndecl));
- if (GET_CODE (result) == PARALLEL)
- return N_("inline functions not supported for this return value type");
- }
-
- /* If the function has a target specific attribute attached to it,
- then we assume that we should not inline it. This can be overridden
- by the target if it defines TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. */
- if (!function_attribute_inlinable_p (fndecl))
- return N_("function with target specific attribute(s) cannot be inlined");
-
- return NULL;
-}
-/* Map pseudo reg number into the PARM_DECL for the parm living in the reg.
- Zero for a reg that isn't a parm's home.
- Only reg numbers less than max_parm_reg are mapped here. */
-static tree *parmdecl_map;
-
-/* In save_for_inline, nonzero if past the parm-initialization insns. */
-static int in_nonparm_insns;
-
-/* Subroutine for `save_for_inline'. Performs initialization
- needed to save FNDECL's insns and info for future inline expansion. */
-
-static rtvec
-initialize_for_inline (tree fndecl)
-{
- int i;
- rtvec arg_vector;
- tree parms;
-
- /* Clear out PARMDECL_MAP. It was allocated in the caller's frame. */
- memset (parmdecl_map, 0, max_parm_reg * sizeof (tree));
- arg_vector = rtvec_alloc (list_length (DECL_ARGUMENTS (fndecl)));
-
- for (parms = DECL_ARGUMENTS (fndecl), i = 0;
- parms;
- parms = TREE_CHAIN (parms), i++)
- {
- rtx p = DECL_RTL (parms);
-
- /* If we have (mem (addressof (mem ...))), use the inner MEM since
- otherwise the copy_rtx call below will not unshare the MEM since
- it shares ADDRESSOF. */
- if (GET_CODE (p) == MEM && GET_CODE (XEXP (p, 0)) == ADDRESSOF
- && GET_CODE (XEXP (XEXP (p, 0), 0)) == MEM)
- p = XEXP (XEXP (p, 0), 0);
-
- RTVEC_ELT (arg_vector, i) = p;
-
- if (GET_CODE (p) == REG)
- parmdecl_map[REGNO (p)] = parms;
- else if (GET_CODE (p) == CONCAT)
- {
- rtx preal = gen_realpart (GET_MODE (XEXP (p, 0)), p);
- rtx pimag = gen_imagpart (GET_MODE (preal), p);
-
- if (GET_CODE (preal) == REG)
- parmdecl_map[REGNO (preal)] = parms;
- if (GET_CODE (pimag) == REG)
- parmdecl_map[REGNO (pimag)] = parms;
- }
-
- /* This flag is cleared later
- if the function ever modifies the value of the parm. */
- TREE_READONLY (parms) = 1;
- }
-
- return arg_vector;
-}
-
/* Copy NODE (which must be a DECL, but not a PARM_DECL). The DECL
originally was in the FROM_FN, but now it will be in the
TO_FN. */
@@ -379,7 +159,10 @@ copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn)
address has been taken; it's for internal bookkeeping in
expand_goto_internal. */
if (TREE_CODE (copy) == LABEL_DECL)
- TREE_ADDRESSABLE (copy) = 0;
+ {
+ TREE_ADDRESSABLE (copy) = 0;
+ DECL_TOO_LATE (copy) = 0;
+ }
}
/* Set the DECL_ABSTRACT_ORIGIN so the debugging routines know what
@@ -412,1439 +195,13 @@ copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn)
return copy;
}
-
-/* Make the insns and PARM_DECLs of the current function permanent
- and record other information in DECL_STRUCT_FUNCTION to allow
- inlining of this function in subsequent calls.
-
- This routine need not copy any insns because we are not going
- to immediately compile the insns in the insn chain. There
- are two cases when we would compile the insns for FNDECL:
- (1) when FNDECL is expanded inline, and (2) when FNDECL needs to
- be output at the end of other compilation, because somebody took
- its address. In the first case, the insns of FNDECL are copied
- as it is expanded inline, so FNDECL's saved insns are not
- modified. In the second case, FNDECL is used for the last time,
- so modifying the rtl is not a problem.
-
- We don't have to worry about FNDECL being inline expanded by
- other functions which are written at the end of compilation
- because flag_no_inline is turned on when we begin writing
- functions at the end of compilation. */
-
-void
-save_for_inline (tree fndecl)
-{
- rtx insn;
- rtvec argvec;
- rtx first_nonparm_insn;
-
- /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL.
- Later we set TREE_READONLY to 0 if the parm is modified inside the fn.
- Also set up ARG_VECTOR, which holds the unmodified DECL_RTX values
- for the parms, prior to elimination of virtual registers.
- These values are needed for substituting parms properly. */
- if (! flag_no_inline)
- parmdecl_map = xmalloc (max_parm_reg * sizeof (tree));
-
- /* Make and emit a return-label if we have not already done so. */
-
- if (return_label == 0)
- {
- return_label = gen_label_rtx ();
- emit_label (return_label);
- }
-
- if (! flag_no_inline)
- argvec = initialize_for_inline (fndecl);
- else
- argvec = NULL;
-
- /* Delete basic block notes created by early run of find_basic_block.
- The notes would be later used by find_basic_blocks to reuse the memory
- for basic_block structures on already freed obstack. */
- for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK)
- delete_related_insns (insn);
-
- /* If there are insns that copy parms from the stack into pseudo registers,
- those insns are not copied. `expand_inline_function' must
- emit the correct code to handle such things. */
-
- insn = get_insns ();
- if (GET_CODE (insn) != NOTE)
- abort ();
-
- if (! flag_no_inline)
- {
- /* Get the insn which signals the end of parameter setup code. */
- first_nonparm_insn = get_first_nonparm_insn ();
-
- /* Now just scan the chain of insns to see what happens to our
- PARM_DECLs. If a PARM_DECL is used but never modified, we
- can substitute its rtl directly when expanding inline (and
- perform constant folding when its incoming value is
- constant). Otherwise, we have to copy its value into a new
- register and track the new register's life. */
- in_nonparm_insns = 0;
- save_parm_insns (insn, first_nonparm_insn);
-
- cfun->inl_max_label_num = max_label_num ();
- cfun->inl_last_parm_insn = cfun->x_last_parm_insn;
- cfun->original_arg_vector = argvec;
- }
- cfun->original_decl_initial = DECL_INITIAL (fndecl);
- cfun->no_debugging_symbols = (write_symbols == NO_DEBUG);
- cfun->saved_for_inline = 1;
-
- /* Clean up. */
- if (! flag_no_inline)
- free (parmdecl_map);
-}
-
-/* Scan the chain of insns to see what happens to our PARM_DECLs. If a
- PARM_DECL is used but never modified, we can substitute its rtl directly
- when expanding inline (and perform constant folding when its incoming
- value is constant). Otherwise, we have to copy its value into a new
- register and track the new register's life. */
-
-static void
-save_parm_insns (rtx insn, rtx first_nonparm_insn)
-{
- if (insn == NULL_RTX)
- return;
-
- for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
- {
- if (insn == first_nonparm_insn)
- in_nonparm_insns = 1;
-
- if (INSN_P (insn))
- {
- /* Record what interesting things happen to our parameters. */
- note_stores (PATTERN (insn), note_modified_parmregs, NULL);
-
- /* If this is a CALL_PLACEHOLDER insn then we need to look into the
- three attached sequences: normal call, sibling call and tail
- recursion. */
- if (GET_CODE (insn) == CALL_INSN
- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
- {
- int i;
-
- for (i = 0; i < 3; i++)
- save_parm_insns (XEXP (PATTERN (insn), i),
- first_nonparm_insn);
- }
- }
- }
-}
-/* Note whether a parameter is modified or not. */
-
-static void
-note_modified_parmregs (rtx reg, rtx x ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (reg) == REG && in_nonparm_insns
- && REGNO (reg) < max_parm_reg
- && REGNO (reg) >= FIRST_PSEUDO_REGISTER
- && parmdecl_map[REGNO (reg)] != 0)
- TREE_READONLY (parmdecl_map[REGNO (reg)]) = 0;
-}
-
/* Unfortunately, we need a global copy of const_equiv map for communication
with a function called from note_stores. Be *very* careful that this
is used properly in the presence of recursion. */
varray_type global_const_equiv_varray;
-
-#define FIXED_BASE_PLUS_P(X) \
- (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
- && GET_CODE (XEXP (X, 0)) == REG \
- && REGNO (XEXP (X, 0)) >= FIRST_VIRTUAL_REGISTER \
- && REGNO (XEXP (X, 0)) <= LAST_VIRTUAL_REGISTER)
-/* Called to set up a mapping for the case where a parameter is in a
- register. If it is read-only and our argument is a constant, set up the
- constant equivalence.
-
- If LOC is REG_USERVAR_P, the usual case, COPY must also have that flag set
- if it is a register.
-
- Also, don't allow hard registers here; they might not be valid when
- substituted into insns. */
-static void
-process_reg_param (struct inline_remap *map, rtx loc, rtx copy)
-{
- if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)
- || (GET_CODE (copy) == REG && REG_USERVAR_P (loc)
- && ! REG_USERVAR_P (copy))
- || (GET_CODE (copy) == REG
- && REGNO (copy) < FIRST_PSEUDO_REGISTER))
- {
- rtx temp = copy_to_mode_reg (GET_MODE (loc), copy);
- REG_USERVAR_P (temp) = REG_USERVAR_P (loc);
- if (CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy))
- SET_CONST_EQUIV_DATA (map, temp, copy, CONST_AGE_PARM);
- copy = temp;
- }
- map->reg_map[REGNO (loc)] = copy;
-}
-
-/* Compare two BLOCKs for qsort. The key we sort on is the
- BLOCK_ABSTRACT_ORIGIN of the blocks. We cannot just subtract the
- two pointers, because it may overflow sizeof(int). */
-
-static int
-compare_blocks (const void *v1, const void *v2)
-{
- tree b1 = *((const tree *) v1);
- tree b2 = *((const tree *) v2);
- char *p1 = (char *) BLOCK_ABSTRACT_ORIGIN (b1);
- char *p2 = (char *) BLOCK_ABSTRACT_ORIGIN (b2);
-
- if (p1 == p2)
- return 0;
- return p1 < p2 ? -1 : 1;
-}
-
-/* Compare two BLOCKs for bsearch. The first pointer corresponds to
- an original block; the second to a remapped equivalent. */
-
-static int
-find_block (const void *v1, const void *v2)
-{
- const union tree_node *b1 = (const union tree_node *) v1;
- tree b2 = *((const tree *) v2);
- char *p1 = (char *) b1;
- char *p2 = (char *) BLOCK_ABSTRACT_ORIGIN (b2);
-
- if (p1 == p2)
- return 0;
- return p1 < p2 ? -1 : 1;
-}
-
-/* Integrate the procedure defined by FNDECL. Note that this function
- may wind up calling itself. Since the static variables are not
- reentrant, we do not assign them until after the possibility
- of recursion is eliminated.
-
- If IGNORE is nonzero, do not produce a value.
- Otherwise store the value in TARGET if it is nonzero and that is convenient.
-
- Value is:
- (rtx)-1 if we could not substitute the function
- 0 if we substituted it and it does not produce a value
- else an rtx for where the value is stored. */
-
-rtx
-expand_inline_function (tree fndecl, tree parms, rtx target, int ignore,
- tree type, rtx structure_value_addr)
-{
- struct function *inlining_previous;
- struct function *inl_f = DECL_STRUCT_FUNCTION (fndecl);
- tree formal, actual, block;
- rtx parm_insns = inl_f->emit->x_first_insn;
- rtx insns = (inl_f->inl_last_parm_insn
- ? NEXT_INSN (inl_f->inl_last_parm_insn)
- : parm_insns);
- tree *arg_trees;
- rtx *arg_vals;
- int max_regno;
- int i;
- int min_labelno = inl_f->emit->x_first_label_num;
- int max_labelno = inl_f->inl_max_label_num;
- int nargs;
- rtx loc;
- rtx stack_save = 0;
- rtx temp;
- struct inline_remap *map = 0;
- rtvec arg_vector = inl_f->original_arg_vector;
- rtx static_chain_value = 0;
- int inl_max_uid;
- int eh_region_offset;
-
- /* The pointer used to track the true location of the memory used
- for MAP->LABEL_MAP. */
- rtx *real_label_map = 0;
-
- /* Allow for equivalences of the pseudos we make for virtual fp and ap. */
- max_regno = inl_f->emit->x_reg_rtx_no + 3;
- if (max_regno < FIRST_PSEUDO_REGISTER)
- abort ();
-
- /* Pull out the decl for the function definition; fndecl may be a
- local declaration, which would break DECL_ABSTRACT_ORIGIN. */
- fndecl = inl_f->decl;
-
- nargs = list_length (DECL_ARGUMENTS (fndecl));
-
- if (cfun->preferred_stack_boundary < inl_f->preferred_stack_boundary)
- cfun->preferred_stack_boundary = inl_f->preferred_stack_boundary;
-
- /* Check that the parms type match and that sufficient arguments were
- passed. Since the appropriate conversions or default promotions have
- already been applied, the machine modes should match exactly. */
-
- for (formal = DECL_ARGUMENTS (fndecl), actual = parms;
- formal;
- formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual))
- {
- tree arg;
- enum machine_mode mode;
-
- if (actual == 0)
- return (rtx) (size_t) -1;
-
- arg = TREE_VALUE (actual);
- mode = TYPE_MODE (DECL_ARG_TYPE (formal));
-
- if (arg == error_mark_node
- || mode != TYPE_MODE (TREE_TYPE (arg))
- /* If they are block mode, the types should match exactly.
- They don't match exactly if TREE_TYPE (FORMAL) == ERROR_MARK_NODE,
- which could happen if the parameter has incomplete type. */
- || (mode == BLKmode
- && (TYPE_MAIN_VARIANT (TREE_TYPE (arg))
- != TYPE_MAIN_VARIANT (TREE_TYPE (formal)))))
- return (rtx) (size_t) -1;
- }
-
- /* If there is a TARGET which is a readonly BLKmode MEM and DECL_RESULT
- is also a mem, we are going to lose the readonly on the stores, so don't
- inline. */
- if (target != 0 && GET_CODE (target) == MEM && GET_MODE (target) == BLKmode
- && RTX_UNCHANGING_P (target) && DECL_RTL_SET_P (DECL_RESULT (fndecl))
- && GET_CODE (DECL_RTL (DECL_RESULT (fndecl))) == MEM)
- return (rtx) (size_t) -1;
-
- /* Extra arguments are valid, but will be ignored below, so we must
- evaluate them here for side-effects. */
- for (; actual; actual = TREE_CHAIN (actual))
- expand_expr (TREE_VALUE (actual), const0_rtx,
- TYPE_MODE (TREE_TYPE (TREE_VALUE (actual))), 0);
-
- /* Expand the function arguments. Do this first so that any
- new registers get created before we allocate the maps. */
-
- arg_vals = xmalloc (nargs * sizeof (rtx));
- arg_trees = xmalloc (nargs * sizeof (tree));
-
- for (formal = DECL_ARGUMENTS (fndecl), actual = parms, i = 0;
- formal;
- formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual), i++)
- {
- /* Actual parameter, converted to the type of the argument within the
- function. */
- tree arg = convert (TREE_TYPE (formal), TREE_VALUE (actual));
- /* Mode of the variable used within the function. */
- enum machine_mode mode = TYPE_MODE (TREE_TYPE (formal));
- int invisiref = 0;
-
- arg_trees[i] = arg;
- loc = RTVEC_ELT (arg_vector, i);
-
- /* If this is an object passed by invisible reference, we copy the
- object into a stack slot and save its address. If this will go
- into memory, we do nothing now. Otherwise, we just expand the
- argument. */
- if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG
- && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)
- {
- rtx stack_slot = assign_temp (TREE_TYPE (arg), 1, 1, 1);
-
- store_expr (arg, stack_slot, 0);
- arg_vals[i] = XEXP (stack_slot, 0);
- invisiref = 1;
- }
- else if (GET_CODE (loc) != MEM)
- {
- if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg)))
- {
- int unsignedp = TYPE_UNSIGNED (TREE_TYPE (formal));
- enum machine_mode pmode = TYPE_MODE (TREE_TYPE (formal));
-
- pmode = promote_mode (TREE_TYPE (formal), pmode,
- &unsignedp, 0);
-
- if (GET_MODE (loc) != pmode)
- abort ();
-
- /* The mode if LOC and ARG can differ if LOC was a variable
- that had its mode promoted. */
- arg_vals[i] = convert_modes (pmode,
- TYPE_MODE (TREE_TYPE (arg)),
- expand_expr (arg, NULL_RTX, mode,
- EXPAND_SUM),
- unsignedp);
- }
- else
- arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
- }
- else
- arg_vals[i] = 0;
-
- /* If the formal type was const but the actual was not, we might
- end up here with an rtx wrongly tagged unchanging in the caller's
- context. Fix that. */
- if (arg_vals[i] != 0
- && (GET_CODE (arg_vals[i]) == REG || GET_CODE (arg_vals[i]) == MEM)
- && ! TREE_READONLY (TREE_VALUE (actual)))
- RTX_UNCHANGING_P (arg_vals[i]) = 0;
-
- if (arg_vals[i] != 0
- && (! TREE_READONLY (formal)
- /* If the parameter is not read-only, copy our argument through
- a register. Also, we cannot use ARG_VALS[I] if it overlaps
- TARGET in any way. In the inline function, they will likely
- be two different pseudos, and `safe_from_p' will make all
- sorts of smart assumptions about their not conflicting.
- But if ARG_VALS[I] overlaps TARGET, these assumptions are
- wrong, so put ARG_VALS[I] into a fresh register.
- Don't worry about invisible references, since their stack
- temps will never overlap the target. */
- || (target != 0
- && ! invisiref
- && (GET_CODE (arg_vals[i]) == REG
- || GET_CODE (arg_vals[i]) == SUBREG
- || GET_CODE (arg_vals[i]) == MEM)
- && reg_overlap_mentioned_p (arg_vals[i], target))
- /* ??? We must always copy a SUBREG into a REG, because it might
- get substituted into an address, and not all ports correctly
- handle SUBREGs in addresses. */
- || (GET_CODE (arg_vals[i]) == SUBREG)))
- arg_vals[i] = copy_to_mode_reg (GET_MODE (loc), arg_vals[i]);
-
- if (arg_vals[i] != 0 && GET_CODE (arg_vals[i]) == REG
- && POINTER_TYPE_P (TREE_TYPE (formal)))
- mark_reg_pointer (arg_vals[i],
- TYPE_ALIGN (TREE_TYPE (TREE_TYPE (formal))));
- }
-
- /* Allocate the structures we use to remap things. */
-
- map = xcalloc (1, sizeof (struct inline_remap));
- map->fndecl = fndecl;
-
- VARRAY_TREE_INIT (map->block_map, 10, "block_map");
- map->reg_map = xcalloc (max_regno, sizeof (rtx));
-
- /* We used to use alloca here, but the size of what it would try to
- allocate would occasionally cause it to exceed the stack limit and
- cause unpredictable core dumps. */
- real_label_map = xmalloc ((max_labelno) * sizeof (rtx));
- map->label_map = real_label_map;
- map->local_return_label = NULL_RTX;
-
- inl_max_uid = (inl_f->emit->x_cur_insn_uid + 1);
- map->insn_map = xcalloc (inl_max_uid, sizeof (rtx));
- map->min_insnno = 0;
- map->max_insnno = inl_max_uid;
-
- map->integrating = 1;
- map->compare_src = NULL_RTX;
- map->compare_mode = VOIDmode;
-
- /* const_equiv_varray maps pseudos in our routine to constants, so
- it needs to be large enough for all our pseudos. This is the
- number we are currently using plus the number in the called
- routine, plus 15 for each arg, five to compute the virtual frame
- pointer, and five for the return value. This should be enough
- for most cases. We do not reference entries outside the range of
- the map.
-
- ??? These numbers are quite arbitrary and were obtained by
- experimentation. At some point, we should try to allocate the
- table after all the parameters are set up so we can more accurately
- estimate the number of pseudos we will need. */
-
- VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray,
- (max_reg_num ()
- + (max_regno - FIRST_PSEUDO_REGISTER)
- + 15 * nargs
- + 10),
- "expand_inline_function");
- map->const_age = 0;
-
- /* Record the current insn in case we have to set up pointers to frame
- and argument memory blocks. If there are no insns yet, add a dummy
- insn that can be used as an insertion point. */
- map->insns_at_start = get_last_insn ();
- if (map->insns_at_start == 0)
- map->insns_at_start = emit_note (NOTE_INSN_DELETED);
-
- map->regno_pointer_align = inl_f->emit->regno_pointer_align;
- map->x_regno_reg_rtx = inl_f->emit->x_regno_reg_rtx;
-
- /* Update the outgoing argument size to allow for those in the inlined
- function. */
- if (inl_f->outgoing_args_size > current_function_outgoing_args_size)
- current_function_outgoing_args_size = inl_f->outgoing_args_size;
-
- /* If the inline function needs to make PIC references, that means
- that this function's PIC offset table must be used. */
- if (inl_f->uses_pic_offset_table)
- current_function_uses_pic_offset_table = 1;
-
- /* If this function needs a context, set it up. */
- if (inl_f->needs_context)
- static_chain_value = lookup_static_chain (fndecl);
-
- /* If the inlined function calls __builtin_constant_p, then we'll
- need to call purge_builtin_constant_p on this function. */
- if (inl_f->calls_constant_p)
- current_function_calls_constant_p = 1;
-
- if (GET_CODE (parm_insns) == NOTE
- && NOTE_LINE_NUMBER (parm_insns) > 0)
- {
- rtx note = emit_note_copy (parm_insns);
-
- if (note)
- RTX_INTEGRATED_P (note) = 1;
- }
-
- /* Process each argument. For each, set up things so that the function's
- reference to the argument will refer to the argument being passed.
- We only replace REG with REG here. Any simplifications are done
- via const_equiv_map.
-
- We make two passes: In the first, we deal with parameters that will
- be placed into registers, since we need to ensure that the allocated
- register number fits in const_equiv_map. Then we store all non-register
- parameters into their memory location. */
-
- /* Don't try to free temp stack slots here, because we may put one of the
- parameters into a temp stack slot. */
-
- for (i = 0; i < nargs; i++)
- {
- rtx copy = arg_vals[i];
-
- loc = RTVEC_ELT (arg_vector, i);
-
- /* There are three cases, each handled separately. */
- if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG
- && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)
- {
- /* This must be an object passed by invisible reference (it could
- also be a variable-sized object, but we forbid inlining functions
- with variable-sized arguments). COPY is the address of the
- actual value (this computation will cause it to be copied). We
- map that address for the register, noting the actual address as
- an equivalent in case it can be substituted into the insns. */
-
- if (GET_CODE (copy) != REG)
- {
- temp = copy_addr_to_reg (copy);
- if (CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy))
- SET_CONST_EQUIV_DATA (map, temp, copy, CONST_AGE_PARM);
- copy = temp;
- }
- map->reg_map[REGNO (XEXP (loc, 0))] = copy;
- }
- else if (GET_CODE (loc) == MEM)
- {
- /* This is the case of a parameter that lives in memory. It
- will live in the block we allocate in the called routine's
- frame that simulates the incoming argument area. Do nothing
- with the parameter now; we will call store_expr later. In
- this case, however, we must ensure that the virtual stack and
- incoming arg rtx values are expanded now so that we can be
- sure we have enough slots in the const equiv map since the
- store_expr call can easily blow the size estimate. */
- if (DECL_STRUCT_FUNCTION (fndecl)->args_size != 0)
- copy_rtx_and_substitute (virtual_incoming_args_rtx, map, 0);
- }
- else if (GET_CODE (loc) == REG)
- process_reg_param (map, loc, copy);
- else if (GET_CODE (loc) == CONCAT)
- {
- rtx locreal = gen_realpart (GET_MODE (XEXP (loc, 0)), loc);
- rtx locimag = gen_imagpart (GET_MODE (XEXP (loc, 0)), loc);
- rtx copyreal = gen_realpart (GET_MODE (locreal), copy);
- rtx copyimag = gen_imagpart (GET_MODE (locimag), copy);
-
- process_reg_param (map, locreal, copyreal);
- process_reg_param (map, locimag, copyimag);
- }
- else
- abort ();
- }
-
- /* Tell copy_rtx_and_substitute to handle constant pool SYMBOL_REFs
- specially. This function can be called recursively, so we need to
- save the previous value. */
- inlining_previous = inlining;
- inlining = inl_f;
-
- /* Now do the parameters that will be placed in memory. */
-
- for (formal = DECL_ARGUMENTS (fndecl), i = 0;
- formal; formal = TREE_CHAIN (formal), i++)
- {
- loc = RTVEC_ELT (arg_vector, i);
-
- if (GET_CODE (loc) == MEM
- /* Exclude case handled above. */
- && ! (GET_CODE (XEXP (loc, 0)) == REG
- && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER))
- {
- rtx note = emit_line_note (DECL_SOURCE_LOCATION (formal));
-
- if (note)
- RTX_INTEGRATED_P (note) = 1;
-
- /* Compute the address in the area we reserved and store the
- value there. */
- temp = copy_rtx_and_substitute (loc, map, 1);
- subst_constants (&temp, NULL_RTX, map, 1);
- apply_change_group ();
- if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0)))
- temp = change_address (temp, VOIDmode, XEXP (temp, 0));
- store_expr (arg_trees[i], temp, 0);
- }
- }
-
- /* Deal with the places that the function puts its result.
- We are driven by what is placed into DECL_RESULT.
-
- Initially, we assume that we don't have anything special handling for
- REG_FUNCTION_RETURN_VALUE_P. */
-
- map->inline_target = 0;
- loc = (DECL_RTL_SET_P (DECL_RESULT (fndecl))
- ? DECL_RTL (DECL_RESULT (fndecl)) : NULL_RTX);
-
- if (TYPE_MODE (type) == VOIDmode)
- /* There is no return value to worry about. */
- ;
- else if (GET_CODE (loc) == MEM)
- {
- if (GET_CODE (XEXP (loc, 0)) == ADDRESSOF)
- {
- temp = copy_rtx_and_substitute (loc, map, 1);
- subst_constants (&temp, NULL_RTX, map, 1);
- apply_change_group ();
- target = temp;
- }
- else
- {
- if (! structure_value_addr
- || ! aggregate_value_p (DECL_RESULT (fndecl), fndecl))
- abort ();
-
- /* Pass the function the address in which to return a structure
- value. Note that a constructor can cause someone to call us
- with STRUCTURE_VALUE_ADDR, but the initialization takes place
- via the first parameter, rather than the struct return address.
-
- We have two cases: If the address is a simple register
- indirect, use the mapping mechanism to point that register to
- our structure return address. Otherwise, store the structure
- return value into the place that it will be referenced from. */
-
- if (GET_CODE (XEXP (loc, 0)) == REG)
- {
- temp = force_operand (structure_value_addr, NULL_RTX);
- temp = force_reg (Pmode, temp);
- /* A virtual register might be invalid in an insn, because
- it can cause trouble in reload. Since we don't have access
- to the expanders at map translation time, make sure we have
- a proper register now.
- If a virtual register is actually valid, cse or combine
- can put it into the mapped insns. */
- if (REGNO (temp) >= FIRST_VIRTUAL_REGISTER
- && REGNO (temp) <= LAST_VIRTUAL_REGISTER)
- temp = copy_to_mode_reg (Pmode, temp);
- map->reg_map[REGNO (XEXP (loc, 0))] = temp;
-
- if (CONSTANT_P (structure_value_addr)
- || GET_CODE (structure_value_addr) == ADDRESSOF
- || (GET_CODE (structure_value_addr) == PLUS
- && (XEXP (structure_value_addr, 0)
- == virtual_stack_vars_rtx)
- && (GET_CODE (XEXP (structure_value_addr, 1))
- == CONST_INT)))
- {
- SET_CONST_EQUIV_DATA (map, temp, structure_value_addr,
- CONST_AGE_PARM);
- }
- }
- else
- {
- temp = copy_rtx_and_substitute (loc, map, 1);
- subst_constants (&temp, NULL_RTX, map, 0);
- apply_change_group ();
- emit_move_insn (temp, structure_value_addr);
- }
- }
- }
- else if (ignore)
- /* We will ignore the result value, so don't look at its structure.
- Note that preparations for an aggregate return value
- do need to be made (above) even if it will be ignored. */
- ;
- else if (GET_CODE (loc) == REG)
- {
- /* The function returns an object in a register and we use the return
- value. Set up our target for remapping. */
-
- /* Machine mode function was declared to return. */
- enum machine_mode departing_mode = TYPE_MODE (type);
- /* (Possibly wider) machine mode it actually computes
- (for the sake of callers that fail to declare it right).
- We have to use the mode of the result's RTL, rather than
- its type, since expand_function_start may have promoted it. */
- enum machine_mode arriving_mode
- = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
- rtx reg_to_map;
-
- /* Don't use MEMs as direct targets because on some machines
- substituting a MEM for a REG makes invalid insns.
- Let the combiner substitute the MEM if that is valid. */
- if (target == 0 || GET_CODE (target) != REG
- || GET_MODE (target) != departing_mode)
- {
- /* Don't make BLKmode registers. If this looks like
- a BLKmode object being returned in a register, get
- the mode from that, otherwise abort. */
- if (departing_mode == BLKmode)
- {
- if (REG == GET_CODE (DECL_RTL (DECL_RESULT (fndecl))))
- {
- departing_mode = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
- arriving_mode = departing_mode;
- }
- else
- abort ();
- }
-
- target = gen_reg_rtx (departing_mode);
- }
-
- /* If function's value was promoted before return,
- avoid machine mode mismatch when we substitute INLINE_TARGET.
- But TARGET is what we will return to the caller. */
- if (arriving_mode != departing_mode)
- {
- /* Avoid creating a paradoxical subreg wider than
- BITS_PER_WORD, since that is illegal. */
- if (GET_MODE_BITSIZE (arriving_mode) > BITS_PER_WORD)
- {
- if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (departing_mode),
- GET_MODE_BITSIZE (arriving_mode)))
- /* Maybe could be handled by using convert_move () ? */
- abort ();
- reg_to_map = gen_reg_rtx (arriving_mode);
- target = gen_lowpart (departing_mode, reg_to_map);
- }
- else
- reg_to_map = gen_rtx_SUBREG (arriving_mode, target, 0);
- }
- else
- reg_to_map = target;
-
- /* Usually, the result value is the machine's return register.
- Sometimes it may be a pseudo. Handle both cases. */
- if (REG_FUNCTION_VALUE_P (loc))
- map->inline_target = reg_to_map;
- else
- map->reg_map[REGNO (loc)] = reg_to_map;
- }
- else if (GET_CODE (loc) == CONCAT)
- {
- enum machine_mode departing_mode = TYPE_MODE (type);
- enum machine_mode arriving_mode
- = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
-
- if (departing_mode != arriving_mode)
- abort ();
- if (GET_CODE (XEXP (loc, 0)) != REG
- || GET_CODE (XEXP (loc, 1)) != REG)
- abort ();
-
- /* Don't use MEMs as direct targets because on some machines
- substituting a MEM for a REG makes invalid insns.
- Let the combiner substitute the MEM if that is valid. */
- if (target == 0 || GET_CODE (target) != REG
- || GET_MODE (target) != departing_mode)
- target = gen_reg_rtx (departing_mode);
-
- if (GET_CODE (target) != CONCAT)
- abort ();
-
- map->reg_map[REGNO (XEXP (loc, 0))] = XEXP (target, 0);
- map->reg_map[REGNO (XEXP (loc, 1))] = XEXP (target, 1);
- }
- else
- abort ();
-
- /* Remap the exception handler data pointer from one to the other. */
- temp = get_exception_pointer (inl_f);
- if (temp)
- map->reg_map[REGNO (temp)] = get_exception_pointer (cfun);
-
- /* Initialize label_map. get_label_from_map will actually make
- the labels. */
- memset (&map->label_map[min_labelno], 0,
- (max_labelno - min_labelno) * sizeof (rtx));
-
- /* Make copies of the decls of the symbols in the inline function, so that
- the copies of the variables get declared in the current function. Set
- up things so that lookup_static_chain knows that to interpret registers
- in SAVE_EXPRs for TYPE_SIZEs as local. */
- inline_function_decl = fndecl;
- integrate_parm_decls (DECL_ARGUMENTS (fndecl), map, arg_vector);
- block = integrate_decl_tree (inl_f->original_decl_initial, map);
- BLOCK_ABSTRACT_ORIGIN (block) = DECL_ORIGIN (fndecl);
- inline_function_decl = 0;
-
- /* Make a fresh binding contour that we can easily remove. Do this after
- expanding our arguments so cleanups are properly scoped. */
- expand_start_bindings_and_block (0, block);
-
- /* Sort the block-map so that it will be easy to find remapped
- blocks later. */
- qsort (&VARRAY_TREE (map->block_map, 0),
- map->block_map->elements_used,
- sizeof (tree),
- compare_blocks);
-
- /* Perform postincrements before actually calling the function. */
- emit_queue ();
-
- /* Clean up stack so that variables might have smaller offsets. */
- do_pending_stack_adjust ();
-
- /* Save a copy of the location of const_equiv_varray for
- mark_stores, called via note_stores. */
- global_const_equiv_varray = map->const_equiv_varray;
-
- /* If the called function does an alloca, save and restore the
- stack pointer around the call. This saves stack space, but
- also is required if this inline is being done between two
- pushes. */
- if (inl_f->calls_alloca)
- emit_stack_save (SAVE_BLOCK, &stack_save, NULL_RTX);
-
- /* Map pseudos used for initial hard reg values. */
- setup_initial_hard_reg_value_integration (inl_f, map);
-
- /* Now copy the insns one by one. */
- copy_insn_list (insns, map, static_chain_value);
-
- /* Duplicate the EH regions. This will create an offset from the
- region numbers in the function we're inlining to the region
- numbers in the calling function. This must wait until after
- copy_insn_list, as we need the insn map to be complete. */
- eh_region_offset = duplicate_eh_regions (inl_f, map);
-
- /* Now copy the REG_NOTES for those insns. */
- copy_insn_notes (insns, map, eh_region_offset);
-
- /* If the insn sequence required one, emit the return label. */
- if (map->local_return_label)
- emit_label (map->local_return_label);
-
- /* Restore the stack pointer if we saved it above. */
- if (inl_f->calls_alloca)
- emit_stack_restore (SAVE_BLOCK, stack_save, NULL_RTX);
-
- if (! cfun->x_whole_function_mode_p)
- /* In statement-at-a-time mode, we just tell the front-end to add
- this block to the list of blocks at this binding level. We
- can't do it the way it's done for function-at-a-time mode the
- superblocks have not been created yet. */
- lang_hooks.decls.insert_block (block);
- else
- {
- BLOCK_CHAIN (block)
- = BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
- BLOCK_CHAIN (DECL_INITIAL (current_function_decl)) = block;
- }
-
- /* End the scope containing the copied formal parameter variables
- and copied LABEL_DECLs. We pass NULL_TREE for the variables list
- here so that expand_end_bindings will not check for unused
- variables. That's already been checked for when the inlined
- function was defined. */
- expand_end_bindings (NULL_TREE, 1, 1);
-
- /* Must mark the line number note after inlined functions as a repeat, so
- that the test coverage code can avoid counting the call twice. This
- just tells the code to ignore the immediately following line note, since
- there already exists a copy of this note before the expanded inline call.
- This line number note is still needed for debugging though, so we can't
- delete it. */
- if (flag_test_coverage)
- emit_note (NOTE_INSN_REPEATED_LINE_NUMBER);
-
- emit_line_note (input_location);
-
- /* If the function returns a BLKmode object in a register, copy it
- out of the temp register into a BLKmode memory object. */
- if (target
- && TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
- && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl)), fndecl))
- target = copy_blkmode_from_reg (0, target, TREE_TYPE (TREE_TYPE (fndecl)));
-
- if (structure_value_addr)
- {
- target = gen_rtx_MEM (TYPE_MODE (type),
- memory_address (TYPE_MODE (type),
- structure_value_addr));
- set_mem_attributes (target, type, 1);
- }
-
- /* Make sure we free the things we explicitly allocated with xmalloc. */
- if (real_label_map)
- free (real_label_map);
- VARRAY_FREE (map->const_equiv_varray);
- free (map->reg_map);
- free (map->insn_map);
- free (map);
- free (arg_vals);
- free (arg_trees);
-
- inlining = inlining_previous;
-
- return target;
-}
-
-/* Make copies of each insn in the given list using the mapping
- computed in expand_inline_function. This function may call itself for
- insns containing sequences.
-
- Copying is done in two passes, first the insns and then their REG_NOTES.
-
- If static_chain_value is nonzero, it represents the context-pointer
- register for the function. */
-
-static void
-copy_insn_list (rtx insns, struct inline_remap *map, rtx static_chain_value)
-{
- int i;
- rtx insn;
- rtx temp;
-#ifdef HAVE_cc0
- rtx cc0_insn = 0;
-#endif
- rtx static_chain_mem = 0;
-
- /* Copy the insns one by one. Do this in two passes, first the insns and
- then their REG_NOTES. */
-
- /* This loop is very similar to the loop in copy_loop_body in unroll.c. */
-
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- {
- rtx copy, pattern, set;
-
- map->orig_asm_operands_vector = 0;
-
- switch (GET_CODE (insn))
- {
- case INSN:
- pattern = PATTERN (insn);
- set = single_set (insn);
- copy = 0;
- if (GET_CODE (pattern) == USE
- && GET_CODE (XEXP (pattern, 0)) == REG
- && REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
- /* The (USE (REG n)) at return from the function should
- be ignored since we are changing (REG n) into
- inline_target. */
- break;
-
- /* Ignore setting a function value that we don't want to use. */
- if (map->inline_target == 0
- && set != 0
- && GET_CODE (SET_DEST (set)) == REG
- && REG_FUNCTION_VALUE_P (SET_DEST (set)))
- {
- if (volatile_refs_p (SET_SRC (set)))
- {
- rtx new_set;
-
- /* If we must not delete the source,
- load it into a new temporary. */
- copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0));
-
- new_set = single_set (copy);
- if (new_set == 0)
- abort ();
-
- SET_DEST (new_set)
- = gen_reg_rtx (GET_MODE (SET_DEST (new_set)));
- }
- /* If the source and destination are the same and it
- has a note on it, keep the insn. */
- else if (rtx_equal_p (SET_DEST (set), SET_SRC (set))
- && REG_NOTES (insn) != 0)
- copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0));
- else
- break;
- }
-
- /* Similarly if an ignored return value is clobbered. */
- else if (map->inline_target == 0
- && GET_CODE (pattern) == CLOBBER
- && GET_CODE (XEXP (pattern, 0)) == REG
- && REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
- break;
-
- /* Look for the address of the static chain slot. The
- rtx_equal_p comparisons against the
- static_chain_incoming_rtx below may fail if the static
- chain is in memory and the address specified is not
- "legitimate". This happens on Xtensa where the static
- chain is at a negative offset from argp and where only
- positive offsets are legitimate. When the RTL is
- generated, the address is "legitimized" by copying it
- into a register, causing the rtx_equal_p comparisons to
- fail. This workaround looks for code that sets a
- register to the address of the static chain. Subsequent
- memory references via that register can then be
- identified as static chain references. We assume that
- the register is only assigned once, and that the static
- chain address is only live in one register at a time. */
-
- else if (static_chain_value != 0
- && set != 0
- && GET_CODE (static_chain_incoming_rtx) == MEM
- && GET_CODE (SET_DEST (set)) == REG
- && rtx_equal_p (SET_SRC (set),
- XEXP (static_chain_incoming_rtx, 0)))
- {
- static_chain_mem =
- gen_rtx_MEM (GET_MODE (static_chain_incoming_rtx),
- SET_DEST (set));
-
- /* Emit the instruction in case it is used for something
- other than setting the static chain; if it's not used,
- it can always be removed as dead code */
- copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0));
- }
-
- /* If this is setting the static chain rtx, omit it. */
- else if (static_chain_value != 0
- && set != 0
- && (rtx_equal_p (SET_DEST (set),
- static_chain_incoming_rtx)
- || (static_chain_mem
- && rtx_equal_p (SET_DEST (set), static_chain_mem))))
- break;
-
- /* If this is setting the static chain pseudo, set it from
- the value we want to give it instead. */
- else if (static_chain_value != 0
- && set != 0
- && (rtx_equal_p (SET_SRC (set),
- static_chain_incoming_rtx)
- || (static_chain_mem
- && rtx_equal_p (SET_SRC (set), static_chain_mem))))
- {
- rtx newdest = copy_rtx_and_substitute (SET_DEST (set), map, 1);
-
- copy = emit_move_insn (newdest, static_chain_value);
- if (GET_CODE (static_chain_incoming_rtx) != MEM)
- static_chain_value = 0;
- }
-
- /* If this is setting the virtual stack vars register, this must
- be the code at the handler for a builtin longjmp. The value
- saved in the setjmp buffer will be the address of the frame
- we've made for this inlined instance within our frame. But we
- know the offset of that value so we can use it to reconstruct
- our virtual stack vars register from that value. If we are
- copying it from the stack pointer, leave it unchanged. */
- else if (set != 0
- && rtx_equal_p (SET_DEST (set), virtual_stack_vars_rtx))
- {
- HOST_WIDE_INT offset;
- temp = map->reg_map[REGNO (SET_DEST (set))];
- temp = VARRAY_CONST_EQUIV (map->const_equiv_varray,
- REGNO (temp)).rtx;
-
- if (rtx_equal_p (temp, virtual_stack_vars_rtx))
- offset = 0;
- else if (GET_CODE (temp) == PLUS
- && rtx_equal_p (XEXP (temp, 0), virtual_stack_vars_rtx)
- && GET_CODE (XEXP (temp, 1)) == CONST_INT)
- offset = INTVAL (XEXP (temp, 1));
- else
- abort ();
-
- if (rtx_equal_p (SET_SRC (set), stack_pointer_rtx))
- temp = SET_SRC (set);
- else
- temp = force_operand (plus_constant (SET_SRC (set),
- - offset),
- NULL_RTX);
-
- copy = emit_move_insn (virtual_stack_vars_rtx, temp);
- }
-
- else
- copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0));
- /* REG_NOTES will be copied later. */
-
-#ifdef HAVE_cc0
- /* If this insn is setting CC0, it may need to look at
- the insn that uses CC0 to see what type of insn it is.
- In that case, the call to recog via validate_change will
- fail. So don't substitute constants here. Instead,
- do it when we emit the following insn.
-
- For example, see the pyr.md file. That machine has signed and
- unsigned compares. The compare patterns must check the
- following branch insn to see which what kind of compare to
- emit.
-
- If the previous insn set CC0, substitute constants on it as
- well. */
- if (sets_cc0_p (PATTERN (copy)) != 0)
- cc0_insn = copy;
- else
- {
- if (cc0_insn)
- try_constants (cc0_insn, map);
- cc0_insn = 0;
- try_constants (copy, map);
- }
-#else
- try_constants (copy, map);
-#endif
- INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
- break;
-
- case JUMP_INSN:
- if (map->integrating && returnjump_p (insn))
- {
- if (map->local_return_label == 0)
- map->local_return_label = gen_label_rtx ();
- pattern = gen_jump (map->local_return_label);
- }
- else
- pattern = copy_rtx_and_substitute (PATTERN (insn), map, 0);
-
- copy = emit_jump_insn (pattern);
-
-#ifdef HAVE_cc0
- if (cc0_insn)
- try_constants (cc0_insn, map);
- cc0_insn = 0;
-#endif
- try_constants (copy, map);
- INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
-
- /* If this used to be a conditional jump insn but whose branch
- direction is now know, we must do something special. */
- if (any_condjump_p (insn) && onlyjump_p (insn) && map->last_pc_value)
- {
-#ifdef HAVE_cc0
- /* If the previous insn set cc0 for us, delete it. */
- if (only_sets_cc0_p (PREV_INSN (copy)))
- delete_related_insns (PREV_INSN (copy));
-#endif
-
- /* If this is now a no-op, delete it. */
- if (map->last_pc_value == pc_rtx)
- {
- delete_related_insns (copy);
- copy = 0;
- }
- else
- /* Otherwise, this is unconditional jump so we must put a
- BARRIER after it. We could do some dead code elimination
- here, but jump.c will do it just as well. */
- emit_barrier ();
- }
- break;
-
- case CALL_INSN:
- /* If this is a CALL_PLACEHOLDER insn then we need to copy the
- three attached sequences: normal call, sibling call and tail
- recursion. */
- if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
- {
- rtx sequence[3];
- rtx tail_label;
-
- for (i = 0; i < 3; i++)
- {
- rtx seq;
-
- sequence[i] = NULL_RTX;
- seq = XEXP (PATTERN (insn), i);
- if (seq)
- {
- start_sequence ();
- copy_insn_list (seq, map, static_chain_value);
- sequence[i] = get_insns ();
- end_sequence ();
- }
- }
-
- /* Find the new tail recursion label.
- It will already be substituted into sequence[2]. */
- tail_label = copy_rtx_and_substitute (XEXP (PATTERN (insn), 3),
- map, 0);
-
- copy = emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode,
- sequence[0],
- sequence[1],
- sequence[2],
- tail_label));
- break;
- }
-
- pattern = copy_rtx_and_substitute (PATTERN (insn), map, 0);
- copy = emit_call_insn (pattern);
-
- SIBLING_CALL_P (copy) = SIBLING_CALL_P (insn);
- CONST_OR_PURE_CALL_P (copy) = CONST_OR_PURE_CALL_P (insn);
- INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
-
- /* Because the USAGE information potentially contains objects other
- than hard registers, we need to copy it. */
-
- CALL_INSN_FUNCTION_USAGE (copy)
- = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn),
- map, 0);
-
-#ifdef HAVE_cc0
- if (cc0_insn)
- try_constants (cc0_insn, map);
- cc0_insn = 0;
-#endif
- try_constants (copy, map);
-
- /* Be lazy and assume CALL_INSNs clobber all hard registers. */
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- VARRAY_CONST_EQUIV (map->const_equiv_varray, i).rtx = 0;
- break;
-
- case CODE_LABEL:
- copy = emit_label (get_label_from_map (map,
- CODE_LABEL_NUMBER (insn)));
- LABEL_NAME (copy) = LABEL_NAME (insn);
- map->const_age++;
- break;
-
- case BARRIER:
- copy = emit_barrier ();
- break;
-
- case NOTE:
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)
- {
- copy = emit_label (get_label_from_map (map,
- CODE_LABEL_NUMBER (insn)));
- LABEL_NAME (copy) = NOTE_SOURCE_FILE (insn);
- map->const_age++;
- break;
- }
-
- /* NOTE_INSN_FUNCTION_END and NOTE_INSN_FUNCTION_BEG are
- discarded because it is important to have only one of
- each in the current function.
-
- NOTE_INSN_DELETED notes aren't useful. */
-
- if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
- && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
- && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
- {
- copy = emit_note_copy (insn);
- if (!copy)
- /*Copied a line note, but line numbering is off*/;
- else if ((NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_BEG
- || NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_END)
- && NOTE_BLOCK (insn))
- {
- tree *mapped_block_p;
-
- mapped_block_p
- = bsearch (NOTE_BLOCK (insn),
- &VARRAY_TREE (map->block_map, 0),
- map->block_map->elements_used,
- sizeof (tree),
- find_block);
-
- if (!mapped_block_p)
- abort ();
- else
- NOTE_BLOCK (copy) = *mapped_block_p;
- }
- else if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EXPECTED_VALUE)
- NOTE_EXPECTED_VALUE (copy)
- = copy_rtx_and_substitute (NOTE_EXPECTED_VALUE (insn),
- map, 0);
- }
- else
- copy = 0;
- break;
-
- default:
- abort ();
- }
-
- if (copy)
- RTX_INTEGRATED_P (copy) = 1;
-
- map->insn_map[INSN_UID (insn)] = copy;
- }
-}
-
-/* Copy the REG_NOTES. Increment const_age, so that only constants
- from parameters can be substituted in. These are the only ones
- that are valid across the entire function. */
-
-static void
-copy_insn_notes (rtx insns, struct inline_remap *map, int eh_region_offset)
-{
- rtx insn, new_insn;
-
- map->const_age++;
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- {
- if (! INSN_P (insn))
- continue;
-
- new_insn = map->insn_map[INSN_UID (insn)];
- if (! new_insn)
- continue;
-
- if (REG_NOTES (insn))
- {
- rtx next, note = copy_rtx_and_substitute (REG_NOTES (insn), map, 0);
-
- /* We must also do subst_constants, in case one of our parameters
- has const type and constant value. */
- subst_constants (&note, NULL_RTX, map, 0);
- apply_change_group ();
- REG_NOTES (new_insn) = note;
-
- /* Delete any REG_LABEL notes from the chain. Remap any
- REG_EH_REGION notes. */
- for (; note; note = next)
- {
- next = XEXP (note, 1);
- if (REG_NOTE_KIND (note) == REG_LABEL)
- remove_note (new_insn, note);
- else if (REG_NOTE_KIND (note) == REG_EH_REGION
- && INTVAL (XEXP (note, 0)) > 0)
- XEXP (note, 0) = GEN_INT (INTVAL (XEXP (note, 0))
- + eh_region_offset);
- }
- }
-
- if (GET_CODE (insn) == CALL_INSN
- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
- {
- int i;
- for (i = 0; i < 3; i++)
- copy_insn_notes (XEXP (PATTERN (insn), i), map, eh_region_offset);
- }
-
- if (GET_CODE (insn) == JUMP_INSN
- && GET_CODE (PATTERN (insn)) == RESX)
- XINT (PATTERN (new_insn), 0) += eh_region_offset;
- }
-}
-
-/* Given a chain of PARM_DECLs, ARGS, copy each decl into a VAR_DECL,
- push all of those decls and give each one the corresponding home. */
-
-static void
-integrate_parm_decls (tree args, struct inline_remap *map, rtvec arg_vector)
-{
- tree tail;
- int i;
-
- for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++)
- {
- tree decl = copy_decl_for_inlining (tail, map->fndecl,
- current_function_decl);
- rtx new_decl_rtl
- = copy_rtx_and_substitute (RTVEC_ELT (arg_vector, i), map, 1);
-
- /* We really should be setting DECL_INCOMING_RTL to something reasonable
- here, but that's going to require some more work. */
- /* DECL_INCOMING_RTL (decl) = ?; */
- /* Fully instantiate the address with the equivalent form so that the
- debugging information contains the actual register, instead of the
- virtual register. Do this by not passing an insn to
- subst_constants. */
- subst_constants (&new_decl_rtl, NULL_RTX, map, 1);
- apply_change_group ();
- SET_DECL_RTL (decl, new_decl_rtl);
- }
-}
-
-/* Given a BLOCK node LET, push decls and levels so as to construct in the
- current function a tree of contexts isomorphic to the one that is given.
-
- MAP, if nonzero, is a pointer to an inline_remap map which indicates how
- registers used in the DECL_RTL field should be remapped. If it is zero,
- no mapping is necessary. */
-
-static tree
-integrate_decl_tree (tree let, struct inline_remap *map)
-{
- tree t;
- tree new_block;
- tree *next;
-
- new_block = make_node (BLOCK);
- VARRAY_PUSH_TREE (map->block_map, new_block);
- next = &BLOCK_VARS (new_block);
-
- for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
- {
- tree d;
-
- d = copy_decl_for_inlining (t, map->fndecl, current_function_decl);
-
- if (DECL_RTL_SET_P (t))
- {
- rtx r;
-
- SET_DECL_RTL (d, copy_rtx_and_substitute (DECL_RTL (t), map, 1));
-
- /* Fully instantiate the address with the equivalent form so that the
- debugging information contains the actual register, instead of the
- virtual register. Do this by not passing an insn to
- subst_constants. */
- r = DECL_RTL (d);
- subst_constants (&r, NULL_RTX, map, 1);
- SET_DECL_RTL (d, r);
-
- apply_change_group ();
- }
-
- /* Add this declaration to the list of variables in the new
- block. */
- *next = d;
- next = &TREE_CHAIN (d);
- }
-
- next = &BLOCK_SUBBLOCKS (new_block);
- for (t = BLOCK_SUBBLOCKS (let); t; t = BLOCK_CHAIN (t))
- {
- *next = integrate_decl_tree (t, map);
- BLOCK_SUPERCONTEXT (*next) = new_block;
- next = &BLOCK_CHAIN (*next);
- }
-
- TREE_USED (new_block) = TREE_USED (let);
- BLOCK_ABSTRACT_ORIGIN (new_block) = let;
-
- return new_block;
-}
-
/* Create a new copy of an rtx. Recursively copies the operands of the rtx,
except for those few rtx codes that are sharable.
@@ -1884,10 +241,7 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs)
Small hard registers are returned as-is. Pseudo-registers
go through their `reg_map'. */
regno = REGNO (orig);
- if (regno <= LAST_VIRTUAL_REGISTER
- || (map->integrating
- && DECL_STRUCT_FUNCTION (map->fndecl)->internal_arg_pointer
- == orig))
+ if (regno <= LAST_VIRTUAL_REGISTER)
{
/* Some hard registers are also mapped,
but others are not translated. */
@@ -1942,10 +296,7 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs)
emit_insn_after (seq, map->insns_at_start);
return temp;
}
- else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM
- || (map->integrating
- && (DECL_STRUCT_FUNCTION (map->fndecl)->internal_arg_pointer
- == orig)))
+ else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
{
/* Do the same for a block to contain any arguments referenced
in memory. */
@@ -1977,44 +328,17 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs)
}
else if (REG_FUNCTION_VALUE_P (orig))
{
- /* This is a reference to the function return value. If
- the function doesn't have a return value, error. If the
- mode doesn't agree, and it ain't BLKmode, make a SUBREG. */
- if (map->inline_target == 0)
- {
- if (rtx_equal_function_value_matters)
- /* This is an ignored return value. We must not
- leave it in with REG_FUNCTION_VALUE_P set, since
- that would confuse subsequent inlining of the
- current function into a later function. */
- return gen_rtx_REG (GET_MODE (orig), regno);
- else
- /* Must be unrolling loops or replicating code if we
- reach here, so return the register unchanged. */
- return orig;
- }
- else if (GET_MODE (map->inline_target) != BLKmode
- && mode != GET_MODE (map->inline_target))
- return gen_lowpart (mode, map->inline_target);
+ if (rtx_equal_function_value_matters)
+ /* This is an ignored return value. We must not
+ leave it in with REG_FUNCTION_VALUE_P set, since
+ that would confuse subsequent inlining of the
+ current function into a later function. */
+ return gen_rtx_REG (GET_MODE (orig), regno);
else
- return map->inline_target;
- }
-#if defined (LEAF_REGISTERS) && defined (LEAF_REG_REMAP)
- /* If leaf_renumber_regs_insn() might remap this register to
- some other number, make sure we don't share it with the
- inlined function, otherwise delayed optimization of the
- inlined function may change it in place, breaking our
- reference to it. We may still shared it within the
- function, so create an entry for this register in the
- reg_map. */
- if (map->integrating && regno < FIRST_PSEUDO_REGISTER
- && LEAF_REGISTERS[regno] && LEAF_REG_REMAP (regno) != regno)
- {
- if (!map->leaf_reg_map[regno][mode])
- map->leaf_reg_map[regno][mode] = gen_rtx_REG (mode, regno);
- return map->leaf_reg_map[regno][mode];
+ /* Must be unrolling loops or replicating code if we
+ reach here, so return the register unchanged. */
+ return orig;
}
-#endif
else
return orig;
@@ -2136,44 +460,14 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs)
remapped label. Otherwise, symbols are returned unchanged. */
if (CONSTANT_POOL_ADDRESS_P (orig))
{
- struct function *f = inlining ? inlining : cfun;
+ struct function *f = cfun;
rtx constant = get_pool_constant_for_function (f, orig);
- enum machine_mode const_mode = get_pool_mode_for_function (f, orig);
- if (inlining)
- {
- rtx temp = force_const_mem (const_mode,
- copy_rtx_and_substitute (constant,
- map, 0));
-
-#if 0
- /* Legitimizing the address here is incorrect.
-
- Since we had a SYMBOL_REF before, we can assume it is valid
- to have one in this position in the insn.
-
- Also, change_address may create new registers. These
- registers will not have valid reg_map entries. This can
- cause try_constants() to fail because assumes that all
- registers in the rtx have valid reg_map entries, and it may
- end up replacing one of these new registers with junk. */
-
- if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0)))
- temp = change_address (temp, GET_MODE (temp), XEXP (temp, 0));
-#endif
-
- temp = XEXP (temp, 0);
- temp = convert_memory_address (GET_MODE (orig), temp);
- return temp;
- }
- else if (GET_CODE (constant) == LABEL_REF)
+ if (GET_CODE (constant) == LABEL_REF)
return XEXP (force_const_mem
(GET_MODE (orig),
copy_rtx_and_substitute (constant, map, for_lhs)),
0);
}
- else if (TREE_CONSTANT_POOL_ADDRESS_P (orig) && inlining)
- notice_rtl_inlining_of_deferred_constant ();
-
return orig;
case CONST_DOUBLE:
@@ -2192,10 +486,6 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs)
CONST_DOUBLE_HIGH (orig), VOIDmode);
case CONST:
- /* Make new constant pool entry for a constant
- that was in the pool of the inline function. */
- if (RTX_INTEGRATED_P (orig))
- abort ();
break;
case ASM_OPERANDS:
@@ -2244,7 +534,8 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs)
break;
#if 0
- /* Must be ifdefed out for loop unrolling to work. */
+ /* Must be ifdefed out for loop unrolling to work. */
+ /* ??? Is this for the old or the new unroller? */
case RETURN:
abort ();
#endif
@@ -2284,46 +575,9 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs)
break;
case MEM:
- if (inlining
- && GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (orig, 0)))
- {
- enum machine_mode const_mode
- = get_pool_mode_for_function (inlining, XEXP (orig, 0));
- rtx constant
- = get_pool_constant_for_function (inlining, XEXP (orig, 0));
-
- constant = copy_rtx_and_substitute (constant, map, 0);
-
- /* If this was an address of a constant pool entry that itself
- had to be placed in the constant pool, it might not be a
- valid address. So the recursive call might have turned it
- into a register. In that case, it isn't a constant any
- more, so return it. This has the potential of changing a
- MEM into a REG, but we'll assume that it safe. */
- if (! CONSTANT_P (constant))
- return constant;
-
- return validize_mem (force_const_mem (const_mode, constant));
- }
-
copy = gen_rtx_MEM (mode, copy_rtx_and_substitute (XEXP (orig, 0),
map, 0));
MEM_COPY_ATTRIBUTES (copy, orig);
-
- /* If inlining and this is not for the LHS, turn off RTX_UNCHANGING_P
- since this may be an indirect reference to a parameter and the
- actual may not be readonly. */
- if (inlining && !for_lhs)
- RTX_UNCHANGING_P (copy) = 0;
-
- /* If inlining, squish aliasing data that references the subroutine's
- parameter list, since that's no longer applicable. */
- if (inlining && MEM_EXPR (copy)
- && TREE_CODE (MEM_EXPR (copy)) == INDIRECT_REF
- && TREE_CODE (TREE_OPERAND (MEM_EXPR (copy), 0)) == PARM_DECL)
- set_mem_expr (copy, NULL_TREE);
-
return copy;
default:
@@ -2951,52 +1205,6 @@ set_decl_abstract_flags (tree decl, int setting)
}
}
-/* Output the assembly language code for the function FNDECL from
- its DECL_STRUCT_FUNCTION. Used for inline functions that are output
- at end of compilation instead of where they came in the source. */
-
-static GTY(()) struct function *old_cfun;
-
-void
-output_inline_function (tree fndecl)
-{
- enum debug_info_type old_write_symbols = write_symbols;
- const struct gcc_debug_hooks *const old_debug_hooks = debug_hooks;
- struct function *f = DECL_STRUCT_FUNCTION (fndecl);
-
- old_cfun = cfun;
- cfun = f;
- current_function_decl = fndecl;
-
- set_new_last_label_num (f->inl_max_label_num);
-
- /* We're not deferring this any longer. */
- DECL_DEFER_OUTPUT (fndecl) = 0;
-
- /* If requested, suppress debugging information. */
- if (f->no_debugging_symbols)
- {
- write_symbols = NO_DEBUG;
- debug_hooks = &do_nothing_debug_hooks;
- }
-
- /* Make sure warnings emitted by the optimizers (e.g. control reaches
- end of non-void function) is not wildly incorrect. */
- input_location = DECL_SOURCE_LOCATION (fndecl);
-
- /* Compile this function all the way down to assembly code. As a
- side effect this destroys the saved RTL representation, but
- that's okay, because we don't need to inline this anymore. */
- rest_of_compilation (fndecl);
- DECL_INLINE (fndecl) = 0;
-
- cfun = old_cfun;
- current_function_decl = old_cfun ? old_cfun->decl : 0;
- write_symbols = old_write_symbols;
- debug_hooks = old_debug_hooks;
-}
-
-
/* Functions to keep track of the values hard regs had at the start of
the function. */
@@ -3076,21 +1284,6 @@ has_hard_reg_initial_val (enum machine_mode mode, int regno)
return has_func_hard_reg_initial_val (cfun, gen_rtx_REG (mode, regno));
}
-static void
-setup_initial_hard_reg_value_integration (struct function *inl_f, struct inline_remap *remap)
-{
- struct initial_value_struct *ivs = inl_f->hard_reg_initial_vals;
- int i;
-
- if (ivs == 0)
- return;
-
- for (i = 0; i < ivs->num_entries; i ++)
- remap->reg_map[REGNO (ivs->entries[i].pseudo)]
- = get_func_hard_reg_initial_val (cfun, ivs->entries[i].hard_reg);
-}
-
-
void
emit_initial_value_sets (void)
{