mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-25 16:50:49 +08:00
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:
parent
6e2993bf5b
commit
bef5d8b61f
@ -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.
|
||||
|
68
gcc/calls.c
68
gcc/calls.c
@ -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))
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
30
gcc/stmt.c
30
gcc/stmt.c
@ -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
|
||||
{
|
||||
|
@ -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.
|
||||
|
10
gcc/testsuite/gcc.c-torture/execute/20041124-1.c
Normal file
10
gcc/testsuite/gcc.c-torture/execute/20041124-1.c
Normal 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user