summaryrefslogtreecommitdiff
path: root/gcc/function.c
diff options
context:
space:
mode:
authoraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>2015-07-23 15:34:49 +0000
committeraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>2015-07-23 15:34:49 +0000
commitf22255e7ef07a280349238d5df0efd1543e7f5f0 (patch)
treea9c61ffefc2d6f986e382145e78555dd4adb2863 /gcc/function.c
parent9324fa03efa03bdb8ba19c6b49c3898ba9a5fb22 (diff)
downloadgcc-f22255e7ef07a280349238d5df0efd1543e7f5f0.tar.gz
[PR64164] Drop copyrename, use coalescible partition as base when optimizing.
for gcc/ChangeLog PR rtl-optimization/64164 * Makefile.in (OBJS): Drop tree-ssa-copyrename.o. * tree-ssa-copyrename.c: Removed. * opts.c (default_options_table): Drop -ftree-copyrename. Add -ftree-coalesce-vars. * passes.def: Drop all occurrences of pass_rename_ssa_copies. * common.opt (ftree-copyrename): Ignore. (ftree-coalesce-inlined-vars): Likewise. * doc/invoke.texi: Remove the ignored options above. * gimple-expr.h (gimple_can_coalesce_p): Move declaration * tree-ssa-coalesce.h: ... here. * tree-ssa-uncprop.c: Include tree-ssa-coalesce.h and other headers required by it. * gimple-expr.c (gimple_can_coalesce_p): Allow coalescing across variables when flag_tree_coalesce_vars. Check register use and promoted modes to allow coalescing. Moved to tree-ssa-coalesce.c. * tree-ssa-live.c (struct tree_int_map_hasher): Move along with its member functions to tree-ssa-coalesce.c. (var_map_base_init): Likewise. Renamed to compute_samebase_partition_bases. (partition_view_normal): Drop want_bases parameter. (partition_view_bitmap): Likewise. * tree-ssa-live.h: Adjust declarations. * tree-ssa-coalesce.c: Include explow.h. (build_ssa_conflict_graph): Process PARM_ and RESULT_DECLs's default defs at the entry point. (dump_part_var_map): New. (compute_optimized_partition_bases): New, called by... (coalesce_ssa_name): ... when flag_tree_coalesce_vars, instead of compute_samebase_partition_bases. Adjust. * alias.c (nonoverlapping_memrefs_p): Disregard gimple-regs. * cfgexpand.c (leader_merge): New. (get_rtl_for_parm_ssa_default_def): New. (set_rtl): Merge exprs and attrs, even for MEMs and non-SSA vars. Update DECL_RTL for PARM_DECLs and RESULT_DECLs too. (expand_one_stack_var_at): Handle anonymous SSA_NAMEs. Drop redundant MEM attr setting. (expand_one_stack_var_1): Handle anonymous SSA_NAMEs. Renamed from... (expand_one_stack_var): ... this. New wrapper to check and skip already expanded SSA partitions. (record_alignment_for_reg_var): New, factored out of... (expand_one_var): ... this. (expand_one_ssa_partition): New. (adjust_one_expanded_partition_var): New. (expand_one_register_var): Check and skip already expanded SSA partitions. (expand_used_vars): Don't create DECLs for anonymous SSA names. Expand all SSA partitions, then adjust all SSA names. (pass::execute): Replace the loops that set SA.partition_to_pseudo from partition leaders and cleared DECL_RTL for multi-location variables, and that which used to rename vars and set attrs, with one that clears DECL_RTL and checks that PARMs and RESULTs default_defs match DECL_RTL. * cfgexpand.h (get_rtl_for_parm_ssa_default_def): Declare. * emit-rtl.c (set_reg_attrs_for_parm): Handle NULL decl. * explow.c (promote_ssa_mode): New. * explow.h (promote_ssa_mode): Declare. * expr.c (expand_expr_real_1): Handle anonymous SSA_NAMEs. * function.c: Include cfgexpand.h. (use_register_for_decl): Handle SSA_NAMEs, anonymous or not. (use_register_for_parm_decl): Wrapper for the above to special-case the result_ptr. (rtl_for_parm): Ditto for get_rtl_for_parm_ssa_default_def. (split_complex_args): Take assign_parm_data_all argument. Pass it to rtl_for_parm. Set up rtl and context for split args. (assign_parms_augmented_arg_list): Adjust. (maybe_reset_rtl_for_parm): Reset DECL_RTL of parms with multiple locations. Recognize split complex args. (assign_parm_adjust_stack_rtl): Add all and parm arguments, for rtl_for_parm. For SSA-assigned parms, zero stack_parm. (assign_parm_setup_block): Prefer SSA-assigned location. (assign_parm_setup_reg): Likewise. Use entry_parm for equiv if stack_parm is NULL. (assign_parm_setup_stack): Prefer SSA-assigned location. (assign_parms): Maybe reset DECL_RTL of params. Adjust stack rtl before testing for pointer bounds. Special-case result_ptr. (expand_function_start): Maybe reset DECL_RTL of result. Prefer SSA-assigned location for result and static chain. Factor out DECL_RESULT and SET_DECL_RTL. * tree-outof-ssa.c (insert_value_copy_on_edge): Handle anonymous SSA names. Use promote_ssa_mode. (get_temp_reg): Likewise. (remove_ssa_form): Adjust. * stor-layout.c (layout_decl): Don't set mem attributes of non-MEMs. * var-tracking.c (dataflow_set_clear_at_call): Take call_insn and get its reg_usage for reg invalidation. (compute_bb_dataflow): Pass it insn. (emit_notes_in_bb): Likewise. for gcc/testsuite/ChangeLog * gcc.dg/guality/pr54200.c: Add -fno-tree-coalesce-vars. * gcc.dg/ssp-1.c: Make counter a register. * gcc.dg/ssp-2.c: Likewise. * gcc.dg/torture/parm-coalesce.c: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@226113 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/function.c')
-rw-r--r--gcc/function.c275
1 files changed, 225 insertions, 50 deletions
diff --git a/gcc/function.c b/gcc/function.c
index f9d11bf4506..c3d00cd2899 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -72,6 +72,9 @@ along with GCC; see the file COPYING3. If not see
#include "cfganal.h"
#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"
@@ -148,6 +151,8 @@ 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);
+
/* Stack of nested functions. */
/* Keep track of the cfun stack. */
@@ -2105,6 +2110,30 @@ aggregate_value_p (const_tree exp, const_tree fntype)
bool
use_register_for_decl (const_tree decl)
{
+ if (TREE_CODE (decl) == SSA_NAME)
+ {
+ /* We often try to use the SSA_NAME, instead of its underlying
+ decl, to get type information and guide decisions, to avoid
+ differences of behavior between anonymous and named
+ variables, but in this one case we have to go for the actual
+ variable if there is one. The main reason is that, at least
+ at -O0, we want to place user variables on the stack, but we
+ don't mind using pseudos for anonymous or ignored temps.
+ Should we take the SSA_NAME, we'd conclude all SSA_NAMEs
+ should go in pseudos, whereas their corresponding variables
+ might have to go on the stack. So, disregarding the decl
+ here would negatively impact debug info at -O0, enable
+ coalescing between SSA_NAMEs that ought to get different
+ stack/pseudo assignments, and get the incoming argument
+ processing thoroughly confused by PARM_DECLs expected to live
+ in stack slots but assigned to pseudos. */
+ if (!SSA_NAME_VAR (decl))
+ return TYPE_MODE (TREE_TYPE (decl)) != BLKmode
+ && !(flag_float_store && FLOAT_TYPE_P (TREE_TYPE (decl)));
+
+ decl = SSA_NAME_VAR (decl);
+ }
+
if (!targetm.calls.allocate_stack_slots_for_args ())
return true;
@@ -2240,7 +2269,7 @@ assign_parms_initialize_all (struct assign_parm_data_all *all)
needed, else the old list. */
static void
-split_complex_args (vec<tree> *args)
+split_complex_args (struct assign_parm_data_all *all, vec<tree> *args)
{
unsigned i;
tree p;
@@ -2251,6 +2280,7 @@ split_complex_args (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);
@@ -2269,6 +2299,9 @@ split_complex_args (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;
@@ -2280,6 +2313,25 @@ split_complex_args (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)
+ {
+ rtx rtl = rtl_for_parm (all, cparm);
+ gcc_assert (!rtl || GET_CODE (rtl) == CONCAT);
+ if (rtl)
+ {
+ SET_DECL_RTL (p, XEXP (rtl, 0));
+ SET_DECL_RTL (decl, XEXP (rtl, 1));
+
+ DECL_CONTEXT (p) = cparm;
+ DECL_CONTEXT (decl) = cparm;
+ }
+ }
}
}
}
@@ -2342,7 +2394,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 (&fnargs);
+ split_complex_args (all, &fnargs);
return fnargs;
}
@@ -2745,23 +2797,98 @@ 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_one *data)
+assign_parm_adjust_stack_rtl (struct assign_parm_data_all *all, tree parm,
+ 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. */
- 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)))
+ 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)))
stack_parm = NULL;
/* If parm was passed in memory, and we need to convert it on entry,
@@ -2823,14 +2950,21 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
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);
- 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);
+ stack_parm = rtl_for_parm (all, parm);
+ if (stack_parm)
+ stack_parm = copy_rtx (stack_parm);
+ 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));
+ set_mem_attributes (stack_parm, parm, 1);
+ }
}
/* If a BLKmode arrives in registers, copy it to a stack slot. Handle
@@ -2968,10 +3102,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);
- parmreg = gen_reg_rtx (promoted_nominal_mode);
+ rtx from_expand = rtl_for_parm (all, parm);
- if (!DECL_ARTIFICIAL (parm))
- mark_user_reg (parmreg);
+ if (from_expand && !data->passed_pointer)
+ {
+ parmreg = from_expand;
+ gcc_assert (GET_MODE (parmreg) == promoted_nominal_mode);
+ }
+ else
+ {
+ 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. */
@@ -2990,6 +3133,8 @@ 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
@@ -3130,11 +3275,17 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
/* 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 && TYPE_MODE (TREE_TYPE (parm)) != BLKmode)
+ if (data->passed_pointer
+ && (from_expand || TYPE_MODE (TREE_TYPE (parm)) != BLKmode))
{
/* 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 (use_register_for_decl (parm))
+ if (from_expand)
+ {
+ parmreg = from_expand;
+ gcc_assert (GET_MODE (parmreg) == TYPE_MODE (TREE_TYPE (parm)));
+ }
+ else if (use_register_for_decl (parm))
{
parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
mark_user_reg (parmreg);
@@ -3174,7 +3325,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
/* STACK_PARM is the pointer, not the parm, and PARMREG is
now the parm. */
- data->stack_parm = NULL;
+ data->stack_parm = equiv_stack_parm = NULL;
}
/* Mark the register as eliminable if we did no conversion and it was
@@ -3184,11 +3335,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
- && data->stack_parm != 0
- && MEM_P (data->stack_parm)
+ && equiv_stack_parm != 0
+ && MEM_P (equiv_stack_parm)
&& data->locate.offset.var == 0
&& reg_mentioned_p (virtual_incoming_args_rtx,
- XEXP (data->stack_parm, 0)))
+ XEXP (equiv_stack_parm, 0)))
{
rtx_insn *linsn = get_last_insn ();
rtx_insn *sinsn;
@@ -3201,8 +3352,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 (data->stack_parm, submode, 0);
- rtx stacki = adjust_address_nv (data->stack_parm, submode,
+ rtx stackr = adjust_address_nv (equiv_stack_parm, submode, 0);
+ rtx stacki = adjust_address_nv (equiv_stack_parm, submode,
GET_MODE_SIZE (submode));
/* Scan backwards for the set of the real and
@@ -3275,6 +3426,13 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
if (data->stack_parm == 0)
{
+ rtx x = data->stack_parm = rtl_for_parm (all, parm);
+ if (x)
+ gcc_assert (GET_MODE (x) == GET_MODE (data->entry_parm));
+ }
+
+ if (data->stack_parm == 0)
+ {
int align = STACK_SLOT_ALIGNMENT (data->passed_type,
GET_MODE (data->entry_parm),
TYPE_ALIGN (data->passed_type));
@@ -3531,6 +3689,8 @@ 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)
@@ -3580,7 +3740,9 @@ assign_parms (tree fndecl)
else
set_decl_incoming_rtl (parm, data.entry_parm, false);
- /* Boudns should be loaded in the particular order to
+ assign_parm_adjust_stack_rtl (&all, parm, &data);
+
+ /* Bounds should be loaded in the particular order to
have registers allocated correctly. Collect info about
input bounds and load them later. */
if (POINTER_BOUNDS_TYPE_P (data.passed_type))
@@ -3597,11 +3759,10 @@ assign_parms (tree fndecl)
}
else
{
- assign_parm_adjust_stack_rtl (&data);
-
if (assign_parm_setup_block_p (&data))
assign_parm_setup_block (&all, parm, &data);
- else if (data.passed_pointer || use_register_for_decl (parm))
+ else if (data.passed_pointer
+ || use_register_for_parm_decl (&all, parm))
assign_parm_setup_reg (&all, parm, &data);
else
assign_parm_setup_stack (&all, parm, &data);
@@ -4932,7 +5093,9 @@ expand_function_start (tree subr)
before any library calls that assign parms might generate. */
/* Decide whether to return the value in memory or in a register. */
- if (aggregate_value_p (DECL_RESULT (subr), subr))
+ 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. */
rtx value_address = 0;
@@ -4940,7 +5103,7 @@ expand_function_start (tree subr)
#ifdef PCC_STATIC_STRUCT_RETURN
if (cfun->returns_pcc_struct)
{
- int size = int_size_in_bytes (TREE_TYPE (DECL_RESULT (subr)));
+ int size = int_size_in_bytes (TREE_TYPE (res));
value_address = assemble_static_space (size);
}
else
@@ -4952,36 +5115,45 @@ expand_function_start (tree subr)
it. */
if (sv)
{
- value_address = gen_reg_rtx (Pmode);
+ if (DECL_BY_REFERENCE (res))
+ value_address = get_rtl_for_parm_ssa_default_def (res);
+ if (!value_address)
+ value_address = gen_reg_rtx (Pmode);
emit_move_insn (value_address, sv);
}
}
if (value_address)
{
rtx x = value_address;
- if (!DECL_BY_REFERENCE (DECL_RESULT (subr)))
+ if (!DECL_BY_REFERENCE (res))
{
- x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), x);
- set_mem_attributes (x, DECL_RESULT (subr), 1);
+ 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);
+ }
}
- SET_DECL_RTL (DECL_RESULT (subr), x);
+ SET_DECL_RTL (res, x);
}
}
- else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
+ else if (DECL_MODE (res) == VOIDmode)
/* If return mode is void, this decl rtl should not be used. */
- SET_DECL_RTL (DECL_RESULT (subr), NULL_RTX);
+ SET_DECL_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 (DECL_RESULT (subr));
- if (TYPE_MODE (return_type) != BLKmode
- && targetm.calls.return_in_msb (return_type))
+ tree return_type = TREE_TYPE (res);
+ rtx x = get_rtl_for_parm_ssa_default_def (res);
+ if (x)
+ /* Use it. */;
+ 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. */
- SET_DECL_RTL (DECL_RESULT (subr),
- gen_reg_rtx (TYPE_MODE (return_type)));
+ x = gen_reg_rtx (TYPE_MODE (return_type));
else
{
/* In order to figure out what mode to use for the pseudo, we
@@ -4992,25 +5164,26 @@ 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))
- SET_DECL_RTL (DECL_RESULT (subr),
- gen_reg_rtx (GET_MODE (hard_reg)));
+ x = gen_reg_rtx (GET_MODE (hard_reg));
else
{
gcc_assert (GET_CODE (hard_reg) == PARALLEL);
- SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
+ x = 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 (DECL_RESULT (subr)) = 1;
+ DECL_REGISTER (res) = 1;
if (chkp_function_instrumented_p (current_function_decl))
{
- tree return_type = TREE_TYPE (DECL_RESULT (subr));
+ tree return_type = TREE_TYPE (res);
rtx bounds = targetm.calls.chkp_function_value_bounds (return_type,
subr, 1);
- SET_DECL_BOUNDS_RTL (DECL_RESULT (subr), bounds);
+ SET_DECL_BOUNDS_RTL (res, bounds);
}
}
@@ -5025,7 +5198,9 @@ expand_function_start (tree subr)
rtx local, chain;
rtx_insn *insn;
- local = gen_reg_rtx (Pmode);
+ local = get_rtl_for_parm_ssa_default_def (parm);
+ if (!local)
+ local = gen_reg_rtx (Pmode);
chain = targetm.calls.static_chain (current_function_decl, true);
set_decl_incoming_rtl (parm, chain, false);