aboutsummaryrefslogtreecommitdiff
path: root/gcc/function.c
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2015-09-27 09:02:00 +0000
committerAlexandre Oliva <aoliva@gcc.gnu.org>2015-09-27 09:02:00 +0000
commitf11a7b6d57f6fcba1bf2e5a0403dc49120195320 (patch)
tree0f5ba4acabc38f459581c262648b0feb65f83a32 /gcc/function.c
parentedfc19ab2bf68516aa9697d11949637af884148e (diff)
downloadgcc-f11a7b6d57f6fcba1bf2e5a0403dc49120195320.zip
gcc-f11a7b6d57f6fcba1bf2e5a0403dc49120195320.tar.gz
gcc-f11a7b6d57f6fcba1bf2e5a0403dc49120195320.tar.bz2
revert to assign_parms assignments using default defs
Revert the fragile and complicated changes to assign_parms designed to enable it to use RTL assigments chosen by cfgexpand, and instead have cfgexpand use the RTL assignments by assign_parms, keying them off of the default defs that are now necessarily introduced for each parm and result. The possible lack of a default def was already a problem, and the fallbacks in place were not enough, as shown by PR67312. We now have checking asserts in set_rtl that verify that we're assigning to each var a piece of RTL that matches the expectations set forth by use_register_for_decl. for gcc/ChangeLog PR rtl-optimization/64164 PR tree-optimization/67312 PR middle-end/67340 PR middle-end/67490 PR bootstrap/67597 * cfgexpand.c (parm_in_stack_slot_p): Remove. (ssa_default_def_partition): Remove. (get_rtl_for_parm_ssa_default_def): Remove. (set_rtl): Check that RTL assignments match expectations. Loop on SUBREGs, CONCATs and PARALLELs subexprs. Set only the default def location for params and results. Record SSA names or types in REG and MEM attrs, respectively. (set_parm_rtl): New. (expand_one_ssa_partition): Drop logic that assigned MEMs with unassigned addresses. (adjust_one_expanded_partition_var): Don't accept NULL RTL on deferred stack alloc vars. (expand_used_vars): Skip partitions holding parm default defs. Move adjust_one_expanded_partition_var loop... (pass_expand::execute): ... here. Drop redundant assert. Adjust comments before the final loop over all ssa names. Require assigned rtl of parms and results to match exactly. Reset its attributes to match them, not any other variables in the same partition. (expand_debug_expr): Use entry value for PARM's default defs only iff they have zero nondebug uses. * cfgexpand.h (parm_in_stack_slot_p): Remove. (get_rtl_for_parm_ssa_default_def): Remove. (set_parm_rtl): Declare. * doc/invoke.texi: Improve wording. * explow.c (promote_decl_mode): Fix promote_function_mode for result decls not by reference. (promote_ssa_mode): Disregard BLKmode from promote_decl, and bypass TYPE_MODE to get the actual vector mode. * function.c: Include tree-dfa.h. Revert 2015-08-14's and 2015-08-19's changes as follows. Drop include of basic-block.h and df.h. (rtl_for_parm): Remove. (maybe_reset_rtl_for_parm): Remove. (parm_in_unassigned_mem_p): Remove. (use_register_for_decl): Add logic for RESULT_DECLs matching assign_parms' behavior. (split_complex_args): Revert. (assign_parms_augmented_arg_list): Revert. Add comment referencing the logic above. (assign_parm_adjust_stack_rtl): Revert. (assign_parm_setup_block): Revert. Use set_parm_rtl instead of SET_DECL_RTL. Set up a REG if the parm demands so. (assign_parm_setup_reg): Revert. Consolidated SET_DECL_RTL calls into a single set_parm_rtl. Set up a temporary RTL temporarily for expand_assignment. (assign_parm_setup_stack): Revert. Use set_parm_rtl. (assign_parms_unsplit_complex): Revert. Use set_parm_rtl. (assign_bounds): Revert. (assign_parms): Revert. Use set_parm_rtl. (allocate_struct_function): Relayout result and parms of non-abstruct functions. (expand_function_start): Revert. Use set_parm_rtl. If the result is not a hard reg, create a pseudo from the promoted mode of the default def. Promote static chain mode. * tree-outof-ssa.c (remove_ssa_form): Drop unused partition_has_default_def. Set up partitions_for_parm_default_defs. (finish_out_of_ssa): Remove partition_has_default_def. Release partitions_for_parm_default_defs. * tree-outof-ssa.h (struct ssaexpand): Remove partition_has_default_def. Add partitions_for_parm_default_defs. * tree-ssa-coalesce.c: Include tree-dfa.h, tm_p.h and stor-layout.h. (build_ssa_conflict_graph): Fix conflict-detection of default defs of even unused default defs of params and results. (for_all_parms): New. (create_default_def): New. (register_default_def): New. (coalesce_with_default): New. (create_outofssa_var_map): Create default defs for all parms and results, and register their partitions. Add GIMPLE_RETURN operands as coalesce candidates with results. Add default defs of each parm or result as coalesce candidates with its other defs. Mark each result def, and each default def of parms, as used_in_copy. (gimple_can_coalesce_p): Call it. Call use_register_for_decl with the ssa names, even anonymous ones. Drop parm_in_stack_slot_p calls. Require same signedness and alignment. (coalesce_ssa_name): Add coalesce candidates for all defs of each parm and result, even unused ones. (parm_default_def_partition_arg): New type. (set_parm_default_def_partition): New. (get_parm_default_def_partitions): New. * tree-ssa-coalesce.h (get_parm_default_def_partitions): New. * tree-ssa-live.c (partition_view_init): Regard unused defs of parms and results as used. (verify_live_on_entry): Don't error out just because they're not live. for gcc/testsuite/ChangeLog PR rtl-optimization/64164 PR tree-optimization/67312 * gcc.dg/pr67312.c: New. From Zdenek Sojka. * gcc.target/i386/stackalign/return-4.c: Add -O. From-SVN: r228175
Diffstat (limited to 'gcc/function.c')
-rw-r--r--gcc/function.c477
1 files changed, 166 insertions, 311 deletions
diff --git a/gcc/function.c b/gcc/function.c
index 27feb3b..e7b8532 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -74,8 +74,6 @@ along with GCC; see the file COPYING3. If not see
#include "cfgbuild.h"
#include "cfgcleanup.h"
#include "cfgexpand.h"
-#include "basic-block.h"
-#include "df.h"
#include "params.h"
#include "bb-reorder.h"
#include "shrink-wrap.h"
@@ -83,6 +81,7 @@ along with GCC; see the file COPYING3. If not see
#include "rtl-iter.h"
#include "tree-chkp.h"
#include "rtl-chkp.h"
+#include "tree-dfa.h"
/* So we can assign to cfun in this file. */
#undef cfun
@@ -152,9 +151,6 @@ static bool contains (const_rtx, hash_table<insn_cache_hasher> *);
static void prepare_function_start (void);
static void do_clobber_return_reg (rtx, void *);
static void do_use_return_reg (rtx, void *);
-static rtx rtl_for_parm (struct assign_parm_data_all *, tree);
-static void maybe_reset_rtl_for_parm (tree);
-static bool parm_in_unassigned_mem_p (tree, rtx);
/* Stack of nested functions. */
@@ -2145,6 +2141,47 @@ use_register_for_decl (const_tree decl)
if (TREE_ADDRESSABLE (decl))
return false;
+ /* RESULT_DECLs are a bit special in that they're assigned without
+ regard to use_register_for_decl, but we generally only store in
+ them. If we coalesce their SSA NAMEs, we'd better return a
+ result that matches the assignment in expand_function_start. */
+ if (TREE_CODE (decl) == RESULT_DECL)
+ {
+ /* If it's not an aggregate, we're going to use a REG or a
+ PARALLEL containing a REG. */
+ if (!aggregate_value_p (decl, current_function_decl))
+ return true;
+
+ /* If expand_function_start determines the return value, we'll
+ use MEM if it's not by reference. */
+ if (cfun->returns_pcc_struct
+ || (targetm.calls.struct_value_rtx
+ (TREE_TYPE (current_function_decl), 1)))
+ return DECL_BY_REFERENCE (decl);
+
+ /* Otherwise, we're taking an extra all.function_result_decl
+ argument. It's set up in assign_parms_augmented_arg_list,
+ under the (negated) conditions above, and then it's used to
+ set up the RESULT_DECL rtl in assign_params, after looping
+ over all parameters. Now, if the RESULT_DECL is not by
+ reference, we'll use a MEM either way. */
+ if (!DECL_BY_REFERENCE (decl))
+ return false;
+
+ /* Otherwise, if RESULT_DECL is DECL_BY_REFERENCE, it will take
+ the function_result_decl's assignment. Since it's a pointer,
+ we can short-circuit a number of the tests below, and we must
+ duplicat e them because we don't have the
+ function_result_decl to test. */
+ if (!targetm.calls.allocate_stack_slots_for_args ())
+ return true;
+ /* We don't set DECL_IGNORED_P for the function_result_decl. */
+ if (optimize)
+ return true;
+ /* We don't set DECL_REGISTER for the function_result_decl. */
+ return false;
+ }
+
/* Decl is implicitly addressible by bound stores and loads
if it is an aggregate holding bounds. */
if (chkp_function_instrumented_p (current_function_decl)
@@ -2272,7 +2309,7 @@ assign_parms_initialize_all (struct assign_parm_data_all *all)
needed, else the old list. */
static void
-split_complex_args (struct assign_parm_data_all *all, vec<tree> *args)
+split_complex_args (vec<tree> *args)
{
unsigned i;
tree p;
@@ -2283,7 +2320,6 @@ split_complex_args (struct assign_parm_data_all *all, vec<tree> *args)
if (TREE_CODE (type) == COMPLEX_TYPE
&& targetm.calls.split_complex_arg (type))
{
- tree cparm = p;
tree decl;
tree subtype = TREE_TYPE (type);
bool addressable = TREE_ADDRESSABLE (p);
@@ -2302,9 +2338,6 @@ split_complex_args (struct assign_parm_data_all *all, vec<tree> *args)
DECL_ARTIFICIAL (p) = addressable;
DECL_IGNORED_P (p) = addressable;
TREE_ADDRESSABLE (p) = 0;
- /* Reset the RTL before layout_decl, or it may change the
- mode of the RTL of the original argument copied to P. */
- SET_DECL_RTL (p, NULL_RTX);
layout_decl (p, 0);
(*args)[i] = p;
@@ -2316,41 +2349,6 @@ split_complex_args (struct assign_parm_data_all *all, vec<tree> *args)
DECL_IGNORED_P (decl) = addressable;
layout_decl (decl, 0);
args->safe_insert (++i, decl);
-
- /* If we are expanding a function, rather than gimplifying
- it, propagate the RTL of the complex parm to the split
- declarations, and set their contexts so that
- maybe_reset_rtl_for_parm can recognize them and refrain
- from resetting their RTL. */
- if (currently_expanding_to_rtl)
- {
- maybe_reset_rtl_for_parm (cparm);
- rtx rtl = rtl_for_parm (all, cparm);
- if (rtl)
- {
- /* If this is parm is unassigned, assign it now: the
- newly-created decls wouldn't expect the need for
- assignment, and if they were assigned
- independently, they might not end up in adjacent
- slots, so unsplit wouldn't be able to fill in the
- unassigned address of the complex MEM. */
- if (parm_in_unassigned_mem_p (cparm, rtl))
- {
- int align = STACK_SLOT_ALIGNMENT
- (TREE_TYPE (cparm), GET_MODE (rtl), MEM_ALIGN (rtl));
- rtx loc = assign_stack_local
- (GET_MODE (rtl), GET_MODE_SIZE (GET_MODE (rtl)),
- align);
- XEXP (rtl, 0) = XEXP (loc, 0);
- }
-
- SET_DECL_RTL (p, read_complex_part (rtl, false));
- SET_DECL_RTL (decl, read_complex_part (rtl, true));
-
- DECL_CONTEXT (p) = cparm;
- DECL_CONTEXT (decl) = cparm;
- }
- }
}
}
}
@@ -2386,6 +2384,9 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all)
DECL_ARTIFICIAL (decl) = 1;
DECL_NAMELESS (decl) = 1;
TREE_CONSTANT (decl) = 1;
+ /* We don't set DECL_IGNORED_P or DECL_REGISTER here. If this
+ changes, the end of the RESULT_DECL handling block in
+ use_register_for_decl must be adjusted to match. */
DECL_CHAIN (decl) = all->orig_fnargs;
all->orig_fnargs = decl;
@@ -2413,7 +2414,7 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all)
/* If the target wants to split complex arguments into scalars, do so. */
if (targetm.calls.split_complex_arg)
- split_complex_args (all, &fnargs);
+ split_complex_args (&fnargs);
return fnargs;
}
@@ -2816,98 +2817,23 @@ assign_parm_remove_parallels (struct assign_parm_data_one *data)
data->entry_parm = entry_parm;
}
-/* Wrapper for use_register_for_decl, that special-cases the
- .result_ptr as the function's RESULT_DECL when the RESULT_DECL is
- passed by reference. */
-
-static bool
-use_register_for_parm_decl (struct assign_parm_data_all *all, tree parm)
-{
- if (parm == all->function_result_decl)
- {
- tree result = DECL_RESULT (current_function_decl);
-
- if (DECL_BY_REFERENCE (result))
- parm = result;
- }
-
- return use_register_for_decl (parm);
-}
-
-/* Wrapper for get_rtl_for_parm_ssa_default_def, that special-cases
- the .result_ptr as the function's RESULT_DECL when the RESULT_DECL
- is passed by reference. */
-
-static rtx
-rtl_for_parm (struct assign_parm_data_all *all, tree parm)
-{
- if (parm == all->function_result_decl)
- {
- tree result = DECL_RESULT (current_function_decl);
-
- if (!DECL_BY_REFERENCE (result))
- return NULL_RTX;
-
- parm = result;
- }
-
- return get_rtl_for_parm_ssa_default_def (parm);
-}
-
-/* Reset the location of PARM_DECLs and RESULT_DECLs that had
- SSA_NAMEs in multiple partitions, so that assign_parms will choose
- the default def, if it exists, or create new RTL to hold the unused
- entry value. If we are coalescing across variables, we want to
- reset the location too, because a parm without a default def
- (incoming value unused) might be coalesced with one with a default
- def, and then assign_parms would copy both incoming values to the
- same location, which might cause the wrong value to survive. */
-static void
-maybe_reset_rtl_for_parm (tree parm)
-{
- gcc_assert (TREE_CODE (parm) == PARM_DECL
- || TREE_CODE (parm) == RESULT_DECL);
-
- /* This is a split complex parameter, and its context was set to its
- original PARM_DECL in split_complex_args so that we could
- recognize it here and not reset its RTL. */
- if (DECL_CONTEXT (parm) && TREE_CODE (DECL_CONTEXT (parm)) == PARM_DECL)
- {
- DECL_CONTEXT (parm) = DECL_CONTEXT (DECL_CONTEXT (parm));
- return;
- }
-
- if ((flag_tree_coalesce_vars
- || (DECL_RTL_SET_P (parm) && DECL_RTL (parm) == pc_rtx))
- && is_gimple_reg (parm))
- SET_DECL_RTL (parm, NULL_RTX);
-}
-
/* A subroutine of assign_parms. Adjust DATA->STACK_RTL such that it's
always valid and properly aligned. */
static void
-assign_parm_adjust_stack_rtl (struct assign_parm_data_all *all, tree parm,
- struct assign_parm_data_one *data)
+assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
{
rtx stack_parm = data->stack_parm;
- /* If out-of-SSA assigned RTL to the parm default def, make sure we
- don't use what we might have computed before. */
- rtx ssa_assigned = rtl_for_parm (all, parm);
- if (ssa_assigned)
- stack_parm = NULL;
-
/* If we can't trust the parm stack slot to be aligned enough for its
ultimate type, don't use that slot after entry. We'll make another
stack slot, if we need one. */
- else if (stack_parm
- && ((STRICT_ALIGNMENT
- && (GET_MODE_ALIGNMENT (data->nominal_mode)
- > MEM_ALIGN (stack_parm)))
- || (data->nominal_type
- && TYPE_ALIGN (data->nominal_type) > MEM_ALIGN (stack_parm)
- && MEM_ALIGN (stack_parm) < PREFERRED_STACK_BOUNDARY)))
+ if (stack_parm
+ && ((STRICT_ALIGNMENT
+ && GET_MODE_ALIGNMENT (data->nominal_mode) > MEM_ALIGN (stack_parm))
+ || (data->nominal_type
+ && TYPE_ALIGN (data->nominal_type) > MEM_ALIGN (stack_parm)
+ && MEM_ALIGN (stack_parm) < PREFERRED_STACK_BOUNDARY)))
stack_parm = NULL;
/* If parm was passed in memory, and we need to convert it on entry,
@@ -2952,27 +2878,6 @@ assign_parm_setup_block_p (struct assign_parm_data_one *data)
return false;
}
-/* Return true if FROM_EXPAND is a MEM with an address to be filled in
- by assign_params. This should be the case if, and only if,
- parm_in_stack_slot_p holds for the parm DECL that expanded to
- FROM_EXPAND, so we check that, too. */
-
-static bool
-parm_in_unassigned_mem_p (tree decl, rtx from_expand)
-{
- bool result = MEM_P (from_expand) && !XEXP (from_expand, 0);
-
- gcc_assert (result == parm_in_stack_slot_p (decl)
- /* Maybe it was already assigned. That's ok, especially
- for split complex args. */
- || (!result && MEM_P (from_expand)
- && (XEXP (from_expand, 0) == virtual_stack_vars_rtx
- || (GET_CODE (XEXP (from_expand, 0)) == PLUS
- && XEXP (XEXP (from_expand, 0), 0) == virtual_stack_vars_rtx))));
-
- return result;
-}
-
/* A subroutine of assign_parms. Arrange for the parameter to be
present and valid in DATA->STACK_RTL. */
@@ -2982,38 +2887,39 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
{
rtx entry_parm = data->entry_parm;
rtx stack_parm = data->stack_parm;
+ rtx target_reg = NULL_RTX;
HOST_WIDE_INT size;
HOST_WIDE_INT size_stored;
if (GET_CODE (entry_parm) == PARALLEL)
entry_parm = emit_group_move_into_temps (entry_parm);
+ /* If we want the parameter in a pseudo, don't use a stack slot. */
+ if (is_gimple_reg (parm) && use_register_for_decl (parm))
+ {
+ tree def = ssa_default_def (cfun, parm);
+ gcc_assert (def);
+ machine_mode mode = promote_ssa_mode (def, NULL);
+ rtx reg = gen_reg_rtx (mode);
+ if (GET_CODE (reg) != CONCAT)
+ stack_parm = reg;
+ else
+ /* This will use or allocate a stack slot that we'd rather
+ avoid. FIXME: Could we avoid it in more cases? */
+ target_reg = reg;
+ data->stack_parm = NULL;
+ }
+
size = int_size_in_bytes (data->passed_type);
size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
-
if (stack_parm == 0)
{
DECL_ALIGN (parm) = MAX (DECL_ALIGN (parm), BITS_PER_WORD);
- rtx from_expand = rtl_for_parm (all, parm);
- if (from_expand && !parm_in_unassigned_mem_p (parm, from_expand))
- stack_parm = copy_rtx (from_expand);
- else
- {
- stack_parm = assign_stack_local (BLKmode, size_stored,
- DECL_ALIGN (parm));
- if (GET_MODE_SIZE (GET_MODE (entry_parm)) == size)
- PUT_MODE (stack_parm, GET_MODE (entry_parm));
- if (from_expand)
- {
- gcc_assert (GET_CODE (stack_parm) == MEM);
- gcc_assert (parm_in_unassigned_mem_p (parm, from_expand));
- XEXP (from_expand, 0) = XEXP (stack_parm, 0);
- PUT_MODE (from_expand, GET_MODE (stack_parm));
- stack_parm = copy_rtx (from_expand);
- }
- else
- set_mem_attributes (stack_parm, parm, 1);
- }
+ stack_parm = assign_stack_local (BLKmode, size_stored,
+ DECL_ALIGN (parm));
+ if (GET_MODE_SIZE (GET_MODE (entry_parm)) == size)
+ PUT_MODE (stack_parm, GET_MODE (entry_parm));
+ set_mem_attributes (stack_parm, parm, 1);
}
/* If a BLKmode arrives in registers, copy it to a stack slot. Handle
@@ -3054,11 +2960,6 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
else if (size == 0)
;
- /* MEM may be a REG if coalescing assigns the param's partition
- to a pseudo. */
- else if (REG_P (mem))
- emit_move_insn (mem, entry_parm);
-
/* If SIZE is that of a mode no bigger than a word, just use
that mode's store operation. */
else if (size <= UNITS_PER_WORD)
@@ -3113,10 +3014,14 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
tem = change_address (mem, word_mode, 0);
emit_move_insn (tem, x);
}
+ else if (!MEM_P (mem))
+ emit_move_insn (mem, entry_parm);
else
move_block_from_reg (REGNO (entry_parm), mem,
size_stored / UNITS_PER_WORD);
}
+ else if (!MEM_P (mem))
+ emit_move_insn (mem, entry_parm);
else
move_block_from_reg (REGNO (entry_parm), mem,
size_stored / UNITS_PER_WORD);
@@ -3131,8 +3036,14 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
end_sequence ();
}
+ if (target_reg)
+ {
+ emit_move_insn (target_reg, stack_parm);
+ stack_parm = target_reg;
+ }
+
data->stack_parm = stack_parm;
- SET_DECL_RTL (parm, stack_parm);
+ set_parm_rtl (parm, stack_parm);
}
/* A subroutine of assign_parms. Allocate a pseudo to hold the current
@@ -3148,6 +3059,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm));
bool did_conversion = false;
bool need_conversion, moved;
+ rtx rtl;
/* Store the parm in a pseudoregister during the function, but we may
need to do it in a wider mode. Using 2 here makes the result
@@ -3156,40 +3068,19 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
= promote_function_mode (data->nominal_type, data->nominal_mode, &unsignedp,
TREE_TYPE (current_function_decl), 2);
- rtx from_expand = parmreg = rtl_for_parm (all, parm);
-
- if (from_expand && !data->passed_pointer)
- {
- if (GET_MODE (parmreg) != promoted_nominal_mode)
- parmreg = gen_lowpart (promoted_nominal_mode, parmreg);
- }
- else if (!from_expand || parm_in_unassigned_mem_p (parm, from_expand))
- {
- parmreg = gen_reg_rtx (promoted_nominal_mode);
- if (!DECL_ARTIFICIAL (parm))
- mark_user_reg (parmreg);
-
- if (from_expand)
- {
- gcc_assert (data->passed_pointer);
- gcc_assert (GET_CODE (from_expand) == MEM
- && XEXP (from_expand, 0) == NULL_RTX);
- XEXP (from_expand, 0) = parmreg;
- }
- }
+ parmreg = gen_reg_rtx (promoted_nominal_mode);
+ if (!DECL_ARTIFICIAL (parm))
+ mark_user_reg (parmreg);
/* If this was an item that we received a pointer to,
- set DECL_RTL appropriately. */
- if (from_expand)
- SET_DECL_RTL (parm, from_expand);
- else if (data->passed_pointer)
+ set rtl appropriately. */
+ if (data->passed_pointer)
{
- rtx x = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data->passed_type)), parmreg);
- set_mem_attributes (x, parm, 1);
- SET_DECL_RTL (parm, x);
+ rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data->passed_type)), parmreg);
+ set_mem_attributes (rtl, parm, 1);
}
else
- SET_DECL_RTL (parm, parmreg);
+ rtl = parmreg;
assign_parm_remove_parallels (data);
@@ -3197,13 +3088,10 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
assign_parm_find_data_types and expand_expr_real_1. */
equiv_stack_parm = data->stack_parm;
- if (!equiv_stack_parm)
- equiv_stack_parm = data->entry_parm;
validated_mem = validize_mem (copy_rtx (data->entry_parm));
need_conversion = (data->nominal_mode != data->passed_mode
|| promoted_nominal_mode != data->promoted_mode);
- gcc_assert (!(need_conversion && data->passed_pointer && from_expand));
moved = false;
if (need_conversion
@@ -3327,7 +3215,9 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
/* TREE_USED gets set erroneously during expand_assignment. */
save_tree_used = TREE_USED (parm);
+ SET_DECL_RTL (parm, rtl);
expand_assignment (parm, make_tree (data->nominal_type, tempreg), false);
+ SET_DECL_RTL (parm, NULL_RTX);
TREE_USED (parm) = save_tree_used;
all->first_conversion_insn = get_insns ();
all->last_conversion_insn = get_last_insn ();
@@ -3335,28 +3225,16 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
did_conversion = true;
}
- /* We don't want to copy the incoming pointer to a parmreg expected
- to hold the value rather than the pointer. */
- else if (!data->passed_pointer || parmreg != from_expand)
+ else
emit_move_insn (parmreg, validated_mem);
/* If we were passed a pointer but the actual value can safely live
in a register, retrieve it and use it directly. */
- if (data->passed_pointer
- && (from_expand || TYPE_MODE (TREE_TYPE (parm)) != BLKmode))
+ if (data->passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode)
{
- rtx src = DECL_RTL (parm);
-
/* We can't use nominal_mode, because it will have been set to
Pmode above. We must use the actual mode of the parm. */
- if (from_expand)
- {
- parmreg = from_expand;
- gcc_assert (GET_MODE (parmreg) == TYPE_MODE (TREE_TYPE (parm)));
- src = gen_rtx_MEM (GET_MODE (parmreg), validated_mem);
- set_mem_attributes (src, parm, 1);
- }
- else if (use_register_for_decl (parm))
+ if (use_register_for_decl (parm))
{
parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
mark_user_reg (parmreg);
@@ -3373,14 +3251,14 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
set_mem_attributes (parmreg, parm, 1);
}
- if (GET_MODE (parmreg) != GET_MODE (src))
+ if (GET_MODE (parmreg) != GET_MODE (rtl))
{
- rtx tempreg = gen_reg_rtx (GET_MODE (src));
+ rtx tempreg = gen_reg_rtx (GET_MODE (rtl));
int unsigned_p = TYPE_UNSIGNED (TREE_TYPE (parm));
push_to_sequence2 (all->first_conversion_insn,
all->last_conversion_insn);
- emit_move_insn (tempreg, src);
+ emit_move_insn (tempreg, rtl);
tempreg = convert_to_mode (GET_MODE (parmreg), tempreg, unsigned_p);
emit_move_insn (parmreg, tempreg);
all->first_conversion_insn = get_insns ();
@@ -3389,18 +3267,18 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
did_conversion = true;
}
- else if (GET_MODE (parmreg) == BLKmode)
- gcc_assert (parm_in_stack_slot_p (parm));
else
- emit_move_insn (parmreg, src);
+ emit_move_insn (parmreg, rtl);
- SET_DECL_RTL (parm, parmreg);
+ rtl = parmreg;
/* STACK_PARM is the pointer, not the parm, and PARMREG is
now the parm. */
- data->stack_parm = equiv_stack_parm = NULL;
+ data->stack_parm = NULL;
}
+ set_parm_rtl (parm, rtl);
+
/* Mark the register as eliminable if we did no conversion and it was
copied from memory at a fixed offset, and the arg pointer was not
copied to a pseudo-reg. If the arg pointer is a pseudo reg or the
@@ -3408,11 +3286,11 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
make here would screw up life analysis for it. */
if (data->nominal_mode == data->passed_mode
&& !did_conversion
- && equiv_stack_parm != 0
- && MEM_P (equiv_stack_parm)
+ && data->stack_parm != 0
+ && MEM_P (data->stack_parm)
&& data->locate.offset.var == 0
&& reg_mentioned_p (virtual_incoming_args_rtx,
- XEXP (equiv_stack_parm, 0)))
+ XEXP (data->stack_parm, 0)))
{
rtx_insn *linsn = get_last_insn ();
rtx_insn *sinsn;
@@ -3425,8 +3303,8 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
= GET_MODE_INNER (GET_MODE (parmreg));
int regnor = REGNO (XEXP (parmreg, 0));
int regnoi = REGNO (XEXP (parmreg, 1));
- rtx stackr = adjust_address_nv (equiv_stack_parm, submode, 0);
- rtx stacki = adjust_address_nv (equiv_stack_parm, submode,
+ rtx stackr = adjust_address_nv (data->stack_parm, submode, 0);
+ rtx stacki = adjust_address_nv (data->stack_parm, submode,
GET_MODE_SIZE (submode));
/* Scan backwards for the set of the real and
@@ -3444,7 +3322,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
set_unique_reg_note (sinsn, REG_EQUIV, stackr);
}
}
- else
+ else
set_dst_reg_note (linsn, REG_EQUIV, equiv_stack_parm, parmreg);
}
@@ -3496,16 +3374,6 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
if (data->entry_parm != data->stack_parm)
{
rtx src, dest;
- rtx from_expand = NULL_RTX;
-
- if (data->stack_parm == 0)
- {
- from_expand = rtl_for_parm (all, parm);
- if (from_expand)
- gcc_assert (GET_MODE (from_expand) == GET_MODE (data->entry_parm));
- if (from_expand && !parm_in_unassigned_mem_p (parm, from_expand))
- data->stack_parm = from_expand;
- }
if (data->stack_parm == 0)
{
@@ -3516,16 +3384,7 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
= assign_stack_local (GET_MODE (data->entry_parm),
GET_MODE_SIZE (GET_MODE (data->entry_parm)),
align);
- if (!from_expand)
- set_mem_attributes (data->stack_parm, parm, 1);
- else
- {
- gcc_assert (GET_CODE (data->stack_parm) == MEM);
- gcc_assert (parm_in_unassigned_mem_p (parm, from_expand));
- XEXP (from_expand, 0) = XEXP (data->stack_parm, 0);
- PUT_MODE (from_expand, GET_MODE (data->stack_parm));
- data->stack_parm = copy_rtx (from_expand);
- }
+ set_mem_attributes (data->stack_parm, parm, 1);
}
dest = validize_mem (copy_rtx (data->stack_parm));
@@ -3554,7 +3413,7 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
end_sequence ();
}
- SET_DECL_RTL (parm, data->stack_parm);
+ set_parm_rtl (parm, data->stack_parm);
}
/* A subroutine of assign_parms. If the ABI splits complex arguments, then
@@ -3580,21 +3439,11 @@ assign_parms_unsplit_complex (struct assign_parm_data_all *all,
imag = DECL_RTL (fnargs[i + 1]);
if (inner != GET_MODE (real))
{
- real = simplify_gen_subreg (inner, real, GET_MODE (real),
- subreg_lowpart_offset
- (inner, GET_MODE (real)));
- imag = simplify_gen_subreg (inner, imag, GET_MODE (imag),
- subreg_lowpart_offset
- (inner, GET_MODE (imag)));
+ real = gen_lowpart_SUBREG (inner, real);
+ imag = gen_lowpart_SUBREG (inner, imag);
}
- if ((tmp = rtl_for_parm (all, parm)) != NULL_RTX
- && rtx_equal_p (real,
- read_complex_part (tmp, false))
- && rtx_equal_p (imag,
- read_complex_part (tmp, true)))
- ; /* We now have the right rtl in tmp. */
- else if (TREE_ADDRESSABLE (parm))
+ if (TREE_ADDRESSABLE (parm))
{
rtx rmem, imem;
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (parm));
@@ -3618,7 +3467,7 @@ assign_parms_unsplit_complex (struct assign_parm_data_all *all,
}
else
tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
- SET_DECL_RTL (parm, tmp);
+ set_parm_rtl (parm, tmp);
real = DECL_INCOMING_RTL (fnargs[i]);
imag = DECL_INCOMING_RTL (fnargs[i + 1]);
@@ -3740,7 +3589,7 @@ assign_bounds (vec<bounds_parm_data> &bndargs,
assign_parm_setup_block (&all, pbdata->bounds_parm,
&pbdata->parm_data);
else if (pbdata->parm_data.passed_pointer
- || use_register_for_parm_decl (&all, pbdata->bounds_parm))
+ || use_register_for_decl (pbdata->bounds_parm))
assign_parm_setup_reg (&all, pbdata->bounds_parm,
&pbdata->parm_data);
else
@@ -3784,8 +3633,6 @@ assign_parms (tree fndecl)
DECL_INCOMING_RTL (parm) = DECL_RTL (parm);
continue;
}
- else
- maybe_reset_rtl_for_parm (parm);
/* Estimate stack alignment from parameter alignment. */
if (SUPPORTS_STACK_ALIGNMENT)
@@ -3835,7 +3682,7 @@ assign_parms (tree fndecl)
else
set_decl_incoming_rtl (parm, data.entry_parm, false);
- assign_parm_adjust_stack_rtl (&all, parm, &data);
+ assign_parm_adjust_stack_rtl (&data);
/* Bounds should be loaded in the particular order to
have registers allocated correctly. Collect info about
@@ -3856,8 +3703,7 @@ assign_parms (tree fndecl)
{
if (assign_parm_setup_block_p (&data))
assign_parm_setup_block (&all, parm, &data);
- else if (data.passed_pointer
- || use_register_for_parm_decl (&all, parm))
+ else if (data.passed_pointer || use_register_for_decl (parm))
assign_parm_setup_reg (&all, parm, &data);
else
assign_parm_setup_stack (&all, parm, &data);
@@ -3954,7 +3800,7 @@ assign_parms (tree fndecl)
DECL_HAS_VALUE_EXPR_P (result) = 1;
- SET_DECL_RTL (result, x);
+ set_parm_rtl (result, x);
}
/* We have aligned all the args, so add space for the pretend args. */
@@ -4986,6 +4832,18 @@ allocate_struct_function (tree fndecl, bool abstract_p)
if (fndecl != NULL_TREE)
{
tree result = DECL_RESULT (fndecl);
+
+ if (!abstract_p)
+ {
+ /* Now that we have activated any function-specific attributes
+ that might affect layout, particularly vector modes, relayout
+ each of the parameters and the result. */
+ relayout_decl (result);
+ for (tree parm = DECL_ARGUMENTS (fndecl); parm;
+ parm = DECL_CHAIN (parm))
+ relayout_decl (parm);
+ }
+
if (!abstract_p && aggregate_value_p (result, fndecl))
{
#ifdef PCC_STATIC_STRUCT_RETURN
@@ -5189,7 +5047,6 @@ expand_function_start (tree subr)
/* Decide whether to return the value in memory or in a register. */
tree res = DECL_RESULT (subr);
- maybe_reset_rtl_for_parm (res);
if (aggregate_value_p (res, subr))
{
/* Returning something that won't go in a register. */
@@ -5210,10 +5067,7 @@ expand_function_start (tree subr)
it. */
if (sv)
{
- if (DECL_BY_REFERENCE (res))
- value_address = get_rtl_for_parm_ssa_default_def (res);
- if (!value_address)
- value_address = gen_reg_rtx (Pmode);
+ value_address = gen_reg_rtx (Pmode);
emit_move_insn (value_address, sv);
}
}
@@ -5222,33 +5076,35 @@ expand_function_start (tree subr)
rtx x = value_address;
if (!DECL_BY_REFERENCE (res))
{
- x = get_rtl_for_parm_ssa_default_def (res);
- if (!x)
- {
- x = gen_rtx_MEM (DECL_MODE (res), value_address);
- set_mem_attributes (x, res, 1);
- }
+ x = gen_rtx_MEM (DECL_MODE (res), x);
+ set_mem_attributes (x, res, 1);
}
- SET_DECL_RTL (res, x);
+ set_parm_rtl (res, x);
}
}
else if (DECL_MODE (res) == VOIDmode)
/* If return mode is void, this decl rtl should not be used. */
- SET_DECL_RTL (res, NULL_RTX);
- else
+ set_parm_rtl (res, NULL_RTX);
+ else
{
/* Compute the return values into a pseudo reg, which we will copy
into the true return register after the cleanups are done. */
tree return_type = TREE_TYPE (res);
- rtx x = get_rtl_for_parm_ssa_default_def (res);
- if (x)
- /* Use it. */;
+ /* If we may coalesce this result, make sure it has the expected
+ mode. */
+ if (flag_tree_coalesce_vars && is_gimple_reg (res))
+ {
+ tree def = ssa_default_def (cfun, res);
+ gcc_assert (def);
+ machine_mode mode = promote_ssa_mode (def, NULL);
+ set_parm_rtl (res, gen_reg_rtx (mode));
+ }
else if (TYPE_MODE (return_type) != BLKmode
&& targetm.calls.return_in_msb (return_type))
/* expand_function_end will insert the appropriate padding in
this case. Use the return value's natural (unpadded) mode
within the function proper. */
- x = gen_reg_rtx (TYPE_MODE (return_type));
+ set_parm_rtl (res, gen_reg_rtx (TYPE_MODE (return_type)));
else
{
/* In order to figure out what mode to use for the pseudo, we
@@ -5259,16 +5115,14 @@ expand_function_start (tree subr)
/* Structures that are returned in registers are not
aggregate_value_p, so we may see a PARALLEL or a REG. */
if (REG_P (hard_reg))
- x = gen_reg_rtx (GET_MODE (hard_reg));
+ set_parm_rtl (res, gen_reg_rtx (GET_MODE (hard_reg)));
else
{
gcc_assert (GET_CODE (hard_reg) == PARALLEL);
- x = gen_group_rtx (hard_reg);
+ set_parm_rtl (res, gen_group_rtx (hard_reg));
}
}
- SET_DECL_RTL (res, x);
-
/* Set DECL_REGISTER flag so that expand_function_end will copy the
result to the real return register(s). */
DECL_REGISTER (res) = 1;
@@ -5291,22 +5145,23 @@ expand_function_start (tree subr)
{
tree parm = cfun->static_chain_decl;
rtx local, chain;
- rtx_insn *insn;
+ rtx_insn *insn;
+ int unsignedp;
- local = get_rtl_for_parm_ssa_default_def (parm);
- if (!local)
- local = gen_reg_rtx (Pmode);
+ local = gen_reg_rtx (promote_decl_mode (parm, &unsignedp));
chain = targetm.calls.static_chain (current_function_decl, true);
set_decl_incoming_rtl (parm, chain, false);
- SET_DECL_RTL (parm, local);
+ set_parm_rtl (parm, local);
mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
- if (GET_MODE (local) != Pmode)
- local = convert_to_mode (Pmode, local,
- TYPE_UNSIGNED (TREE_TYPE (parm)));
-
- insn = emit_move_insn (local, chain);
+ if (GET_MODE (local) != GET_MODE (chain))
+ {
+ convert_move (local, chain, unsignedp);
+ insn = get_last_insn ();
+ }
+ else
+ insn = emit_move_insn (local, chain);
/* Mark the register as eliminable, similar to parameters. */
if (MEM_P (chain)