aboutsummaryrefslogtreecommitdiff
path: root/gcc/integrate.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/integrate.c')
-rw-r--r--gcc/integrate.c294
1 files changed, 206 insertions, 88 deletions
diff --git a/gcc/integrate.c b/gcc/integrate.c
index cf2200e..e0374e1 100644
--- a/gcc/integrate.c
+++ b/gcc/integrate.c
@@ -66,19 +66,22 @@ extern struct obstack *function_maybepermanent_obstack;
static rtvec initialize_for_inline PARAMS ((tree));
static void note_modified_parmregs PARAMS ((rtx, rtx, void *));
static void integrate_parm_decls PARAMS ((tree, struct inline_remap *,
- rtvec));
+ rtvec));
static tree integrate_decl_tree PARAMS ((tree,
- struct inline_remap *));
+ struct inline_remap *));
static void subst_constants PARAMS ((rtx *, rtx,
- struct inline_remap *, int));
+ struct inline_remap *, int));
static void set_block_origin_self PARAMS ((tree));
static void set_decl_origin_self PARAMS ((tree));
static void set_block_abstract_flags PARAMS ((tree, int));
static void process_reg_param PARAMS ((struct inline_remap *, rtx,
- rtx));
+ rtx));
void set_decl_abstract_flags PARAMS ((tree, int));
static rtx expand_inline_function_eh_labelmap PARAMS ((rtx));
static void mark_stores PARAMS ((rtx, rtx, void *));
+static void save_parm_insns PARAMS ((rtx, rtx));
+static void copy_insn_list PARAMS ((rtx, struct inline_remap *,
+ rtx));
static int compare_blocks PARAMS ((const PTR, const PTR));
static int find_block PARAMS ((const PTR, const PTR));
@@ -423,16 +426,7 @@ save_for_inline_nocopy (fndecl)
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;
- for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
- {
- if (insn == first_nonparm_insn)
- in_nonparm_insns = 1;
-
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
- /* Record what interesting things happen to our parameters. */
- note_stores (PATTERN (insn), note_modified_parmregs, NULL);
- }
+ save_parm_insns (insn, first_nonparm_insn);
/* We have now allocated all that needs to be allocated permanently
on the rtx obstack. Set our high-water mark, so that we
@@ -449,6 +443,48 @@ save_for_inline_nocopy (fndecl)
/* Clean up. */
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 (insn, first_nonparm_insn)
+ rtx insn;
+ rtx first_nonparm_insn;
+{
+ in_nonparm_insns = 0;
+
+ 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 (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ /* 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. */
@@ -577,13 +613,11 @@ expand_inline_function (fndecl, parms, target, ignore, type,
: parm_insns);
tree *arg_trees;
rtx *arg_vals;
- rtx insn;
int max_regno;
register int i;
int min_labelno = inl_f->emit->x_first_label_num;
int max_labelno = inl_f->inl_max_label_num;
int nargs;
- rtx local_return_label = 0;
rtx loc;
rtx stack_save = 0;
rtx temp;
@@ -1089,7 +1123,100 @@ expand_inline_function (fndecl, parms, target, ignore, type,
if (inl_f->calls_alloca)
emit_stack_save (SAVE_BLOCK, &stack_save, NULL_RTX);
- /* Now copy the insns one by one. Do this in two passes, first the insns and
+ /* Now copy the insns one by one. */
+ copy_insn_list (insns, map, static_chain_value);
+
+ /* 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. */
+ 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 (0, NOTE_REPEATED_LINE_NUMBER);
+
+ emit_line_note (input_filename, lineno);
+
+ /* 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))))
+ 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));
+ MEM_SET_IN_STRUCT_P (target, 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);
+ VARRAY_FREE (map->block_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,
+ just like save_for_inline.
+
+ If static_chain_value is non-zero, it represents the context-pointer
+ register for the function. */
+
+static void
+copy_insn_list (insns, map, static_chain_value)
+ rtx insns;
+ struct inline_remap *map;
+ rtx static_chain_value;
+{
+ register int i;
+ rtx insn;
+ rtx temp;
+ rtx local_return_label = NULL_RTX;
+#ifdef HAVE_cc0
+ rtx cc0_insn = 0;
+#endif
+
+ /* Copy the insns one by one. Do this in two passes, first the insns and
then their REG_NOTES, just like save_for_inline. */
/* This loop is very similar to the loop in copy_loop_body in unroll.c. */
@@ -1283,11 +1410,50 @@ expand_inline_function (fndecl, parms, target, ignore, type,
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);
+
/* 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);
@@ -1299,7 +1465,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
#endif
try_constants (copy, map);
- /* Be lazy and assume CALL_INSNs clobber all hard registers. */
+ /* 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;
@@ -1316,14 +1482,23 @@ expand_inline_function (fndecl, parms, target, ignore, type,
break;
case NOTE:
- /* It is important to discard function-end and function-beg notes,
- so we have only one of each in the current function.
- Also, NOTE_INSN_DELETED notes aren't useful (save_for_inline
+ /* 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 (save_for_inline
deleted these in the copy used for continuing compilation,
- not the copy used for inlining). */
+ not the copy used for inlining).
+
+ NOTE_INSN_BASIC_BLOCK is discarded because the saved bb
+ pointer (which will soon be dangling) confuses flow's
+ attempts to preserve bb structures during the compilation
+ of a function. */
+
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
- && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)
{
copy = emit_note (NOTE_SOURCE_FILE (insn),
NOTE_LINE_NUMBER (insn));
@@ -1403,71 +1578,6 @@ expand_inline_function (fndecl, parms, target, ignore, type,
if (local_return_label)
emit_label (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. */
- 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 (0, NOTE_REPEATED_LINE_NUMBER);
-
- emit_line_note (input_filename, lineno);
-
- /* 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))))
- 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));
- MEM_SET_IN_STRUCT_P (target, 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);
- VARRAY_FREE (map->block_map);
- free (map->insn_map);
- free (map);
- free (arg_vals);
- free (arg_trees);
-
- inlining = inlining_previous;
-
- return target;
}
/* Given a chain of PARM_DECLs, ARGS, copy each decl into a VAR_DECL,
@@ -1790,6 +1900,13 @@ copy_rtx_and_substitute (orig, map, for_lhs)
= LABEL_PRESERVE_P (orig);
return get_label_from_map (map, CODE_LABEL_NUMBER (orig));
+ /* We need to handle "deleted" labels that appear in the DECL_RTL
+ of a LABEL_DECL. */
+ case NOTE:
+ if (NOTE_LINE_NUMBER (orig) == NOTE_INSN_DELETED_LABEL)
+ return map->insn_map[INSN_UID (orig)];
+ break;
+
case LABEL_REF:
copy
= gen_rtx_LABEL_REF
@@ -2348,6 +2465,7 @@ subst_constants (loc, insn, map, memonly)
case 'i':
case 's':
case 'w':
+ case 'n':
case 't':
break;