optabs.h (force_expand_binop): Declare.

* optabs.h (force_expand_binop): Declare.
	* optabs.c (force_expand_binop): Export.
	* stmt.c (shift_return_value): Delete.
	(expand_return): Don't call it.
	* expr.h (shift_return_value): Declare.
	* calls.c (shift_returned_value): Delete in favor of...
	(shift_return_value): ...this new function.  Leave the caller to check
	for non-BLKmode values passed in the msb of a register.  Take said mode
	and a shift direction as argument.  Operate on the hard function value,
	not a pseudo.
	(expand_call): Adjust accordingly.
	* function.c (expand_function_start): If a non-BLKmode return value
	is padded at the last significant end of the return register, use the
	return value's natural mode for the DECL_RESULT, not the mode of the
	padded register.
	(expand_function_end): Shift the same sort of return values left by
	the appropriate amount.

From-SVN: r91187
This commit is contained in:
Richard Sandiford 2004-11-24 18:50:26 +00:00 committed by Richard Sandiford
parent 6e2993bf5b
commit bef5d8b61f
9 changed files with 109 additions and 81 deletions

View File

@ -1,3 +1,23 @@
2004-11-24 Richard Sandiford <rsandifo@redhat.com>
* optabs.h (force_expand_binop): Declare.
* optabs.c (force_expand_binop): Export.
* stmt.c (shift_return_value): Delete.
(expand_return): Don't call it.
* expr.h (shift_return_value): Declare.
* calls.c (shift_returned_value): Delete in favor of...
(shift_return_value): ...this new function. Leave the caller to check
for non-BLKmode values passed in the msb of a register. Take said mode
and a shift direction as argument. Operate on the hard function value,
not a pseudo.
(expand_call): Adjust accordingly.
* function.c (expand_function_start): If a non-BLKmode return value
is padded at the last significant end of the return register, use the
return value's natural mode for the DECL_RESULT, not the mode of the
padded register.
(expand_function_end): Shift the same sort of return values left by
the appropriate amount.
2004-11-24 Matt Austern <austern@apple.com>
* recog.c (recog_memoized_1): Remove.

View File

@ -147,7 +147,6 @@ static int check_sibcall_argument_overlap (rtx, struct arg_data *, int);
static int combine_pending_stack_adjustment_and_call (int, struct args_size *,
unsigned int);
static bool shift_returned_value (tree, rtx *);
static tree split_complex_values (tree);
static tree split_complex_types (tree);
@ -1715,39 +1714,27 @@ check_sibcall_argument_overlap (rtx insn, struct arg_data *arg, int mark_stored_
return insn != NULL_RTX;
}
/* If function value *VALUE was returned at the most significant end of a
register, shift it towards the least significant end and convert it to
TYPE's mode. Return true and update *VALUE if some action was needed.
/* Given that a function returns a value of mode MODE at the most
significant end of hard register VALUE, shift VALUE left or right
as specified by LEFT_P. Return true if some action was needed. */
TYPE is the type of the function's return value, which is known not
to have mode BLKmode. */
static bool
shift_returned_value (tree type, rtx *value)
bool
shift_return_value (enum machine_mode mode, bool left_p, rtx value)
{
if (targetm.calls.return_in_msb (type))
{
HOST_WIDE_INT shift;
HOST_WIDE_INT shift;
shift = (GET_MODE_BITSIZE (GET_MODE (*value))
- BITS_PER_UNIT * int_size_in_bytes (type));
if (shift > 0)
{
/* Shift the value into the low part of the register. */
*value = expand_binop (GET_MODE (*value), lshr_optab, *value,
GEN_INT (shift), 0, 1, OPTAB_WIDEN);
gcc_assert (REG_P (value) && HARD_REGISTER_P (value));
shift = GET_MODE_BITSIZE (GET_MODE (value)) - GET_MODE_BITSIZE (mode);
if (shift == 0)
return false;
/* Truncate it to the type's mode, or its integer equivalent.
This is subject to TRULY_NOOP_TRUNCATION. */
*value = convert_to_mode (int_mode_for_mode (TYPE_MODE (type)),
*value, 0);
/* Now convert it to the final form. */
*value = gen_lowpart (TYPE_MODE (type), *value);
return true;
}
}
return false;
/* Use ashr rather than lshr for right shifts. This is for the benefit
of the MIPS port, which requires SImode values to be sign-extended
when stored in 64-bit registers. */
if (!force_expand_binop (GET_MODE (value), left_p ? ashl_optab : ashr_optab,
value, GEN_INT (shift), value, 1, OPTAB_WIDEN))
gcc_unreachable ();
return true;
}
/* Remove all REG_EQUIV notes found in the insn chain. */
@ -2660,6 +2647,20 @@ expand_call (tree exp, rtx target, int ignore)
next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
flags, & args_so_far);
/* If a non-BLKmode value is returned at the most significant end
of a register, shift the register right by the appropriate amount
and update VALREG accordingly. BLKmode values are handled by the
group load/store machinery below. */
if (!structure_value_addr
&& !pcc_struct_value
&& TYPE_MODE (TREE_TYPE (exp)) != BLKmode
&& targetm.calls.return_in_msb (TREE_TYPE (exp)))
{
if (shift_return_value (TYPE_MODE (TREE_TYPE (exp)), false, valreg))
sibcall_failure = 1;
valreg = gen_rtx_REG (TYPE_MODE (TREE_TYPE (exp)), REGNO (valreg));
}
/* If call is cse'able, make appropriate pair of reg-notes around it.
Test valreg so we don't crash; may safely ignore `const'
if return type is void. Disable for PARALLEL return values, because
@ -2851,12 +2852,7 @@ expand_call (tree exp, rtx target, int ignore)
sibcall_failure = 1;
}
else
{
if (shift_returned_value (TREE_TYPE (exp), &valreg))
sibcall_failure = 1;
target = copy_to_reg (valreg);
}
target = copy_to_reg (valreg);
if (targetm.calls.promote_function_return(funtype))
{

View File

@ -551,6 +551,8 @@ extern rtx hard_function_value (tree, tree, int);
extern rtx prepare_call_address (rtx, rtx, rtx *, int, int);
extern bool shift_return_value (enum machine_mode, bool, rtx);
extern rtx expand_call (tree, rtx, int);
extern void fixup_tail_calls (void);

View File

@ -4059,22 +4059,31 @@ expand_function_start (tree subr)
{
/* Compute the return values into a pseudo reg, which we will copy
into the true return register after the cleanups are done. */
/* In order to figure out what mode to use for the pseudo, we
figure out what the mode of the eventual return register will
actually be, and use that. */
rtx hard_reg
= hard_function_value (TREE_TYPE (DECL_RESULT (subr)),
subr, 1);
/* 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)));
tree return_type = TREE_TYPE (DECL_RESULT (subr));
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)));
else
{
gcc_assert (GET_CODE (hard_reg) == PARALLEL);
SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
/* In order to figure out what mode to use for the pseudo, we
figure out what the mode of the eventual return register will
actually be, and use that. */
rtx hard_reg = hard_function_value (return_type, subr, 1);
/* 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)));
else
{
gcc_assert (GET_CODE (hard_reg) == PARALLEL);
SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
}
}
/* Set DECL_REGISTER flag so that expand_function_end will copy the
@ -4368,10 +4377,22 @@ expand_function_end (void)
if (GET_MODE (real_decl_rtl) == BLKmode)
PUT_MODE (real_decl_rtl, GET_MODE (decl_rtl));
/* If a non-BLKmode return value should be padded at the least
significant end of the register, shift it left by the appropriate
amount. BLKmode results are handled using the group load/store
machinery. */
if (TYPE_MODE (TREE_TYPE (decl_result)) != BLKmode
&& targetm.calls.return_in_msb (TREE_TYPE (decl_result)))
{
emit_move_insn (gen_rtx_REG (GET_MODE (decl_rtl),
REGNO (real_decl_rtl)),
decl_rtl);
shift_return_value (GET_MODE (decl_rtl), true, real_decl_rtl);
}
/* If a named return value dumped decl_return to memory, then
we may need to re-do the PROMOTE_MODE signed/unsigned
extension. */
if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
else if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
{
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result));

View File

@ -427,7 +427,7 @@ simplify_expand_binop (enum machine_mode mode, optab binoptab,
/* Like simplify_expand_binop, but always put the result in TARGET.
Return true if the expansion succeeded. */
static bool
bool
force_expand_binop (enum machine_mode mode, optab binoptab,
rtx op0, rtx op1, rtx target, int unsignedp,
enum optab_methods methods)

View File

@ -425,6 +425,9 @@ extern rtx expand_ternary_op (enum machine_mode mode, optab ternary_optab,
extern rtx expand_binop (enum machine_mode, optab, rtx, rtx, rtx, int,
enum optab_methods);
extern bool force_expand_binop (enum machine_mode, optab, rtx, rtx, rtx, int,
enum optab_methods);
/* Expand a binary operation with both signed and unsigned forms. */
extern rtx sign_expand_binop (enum machine_mode, optab, optab, rtx, rtx,
rtx, int, enum optab_methods);

View File

@ -110,7 +110,6 @@ static bool check_operand_nalternatives (tree, tree);
static bool check_unique_operand_names (tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree);
static void expand_null_return_1 (void);
static rtx shift_return_value (rtx);
static void expand_value_return (rtx);
static void do_jump_if_equal (rtx, rtx, rtx, int);
static int estimate_case_costs (case_node_ptr);
@ -1500,33 +1499,6 @@ expand_naked_return (void)
emit_jump (end_label);
}
/* If the current function returns values in the most significant part
of a register, shift return value VAL appropriately. The mode of
the function's return type is known not to be BLKmode. */
static rtx
shift_return_value (rtx val)
{
tree type;
type = TREE_TYPE (DECL_RESULT (current_function_decl));
if (targetm.calls.return_in_msb (type))
{
rtx target;
HOST_WIDE_INT shift;
target = DECL_RTL (DECL_RESULT (current_function_decl));
shift = (GET_MODE_BITSIZE (GET_MODE (target))
- BITS_PER_UNIT * int_size_in_bytes (type));
if (shift > 0)
val = expand_shift (LSHIFT_EXPR, GET_MODE (target),
gen_lowpart (GET_MODE (target), val),
build_int_cst (NULL_TREE, shift), target, 1);
}
return val;
}
/* Generate RTL to return from the current function, with value VAL. */
static void
@ -1737,7 +1709,7 @@ expand_return (tree retval)
val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
val = force_not_mem (val);
/* Return the calculated value. */
expand_value_return (shift_return_value (val));
expand_value_return (val);
}
else
{

View File

@ -1,3 +1,7 @@
2004-11-24 Richard Sandiford <rsandifo@redhat.com>
* gcc.c-torture/execute/20041124-1.c: New test.
2004-11-24 Mark Mitchell <mark@codesourcery.com>
* g++.dg/template/deduce3.C: New test.

View File

@ -0,0 +1,10 @@
struct s { _Complex unsigned short x; };
struct s gs = { 100 + 200i };
struct s __attribute__((noinline)) foo (void) { return gs; }
int main ()
{
if (foo ().x != gs.x)
abort ();
exit (0);
}