aboutsummaryrefslogtreecommitdiff
path: root/gcc/function.c
diff options
context:
space:
mode:
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)