Commit bef5d8b6 by Richard Sandiford Committed by Richard Sandiford

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
parent 6e2993bf
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> 2004-11-24 Matt Austern <austern@apple.com>
* recog.c (recog_memoized_1): Remove. * recog.c (recog_memoized_1): Remove.
......
...@@ -147,7 +147,6 @@ static int check_sibcall_argument_overlap (rtx, struct arg_data *, int); ...@@ -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 *, static int combine_pending_stack_adjustment_and_call (int, struct args_size *,
unsigned int); unsigned int);
static bool shift_returned_value (tree, rtx *);
static tree split_complex_values (tree); static tree split_complex_values (tree);
static tree split_complex_types (tree); static tree split_complex_types (tree);
...@@ -1715,39 +1714,27 @@ check_sibcall_argument_overlap (rtx insn, struct arg_data *arg, int mark_stored_ ...@@ -1715,39 +1714,27 @@ check_sibcall_argument_overlap (rtx insn, struct arg_data *arg, int mark_stored_
return insn != NULL_RTX; return insn != NULL_RTX;
} }
/* If function value *VALUE was returned at the most significant end of a /* Given that a function returns a value of mode MODE at the most
register, shift it towards the least significant end and convert it to significant end of hard register VALUE, shift VALUE left or right
TYPE's mode. Return true and update *VALUE if some action was needed. 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 bool
to have mode BLKmode. */ shift_return_value (enum machine_mode mode, bool left_p, rtx value)
static bool
shift_returned_value (tree type, rtx *value)
{ {
if (targetm.calls.return_in_msb (type)) HOST_WIDE_INT shift;
{
HOST_WIDE_INT shift;
shift = (GET_MODE_BITSIZE (GET_MODE (*value)) gcc_assert (REG_P (value) && HARD_REGISTER_P (value));
- BITS_PER_UNIT * int_size_in_bytes (type)); shift = GET_MODE_BITSIZE (GET_MODE (value)) - GET_MODE_BITSIZE (mode);
if (shift > 0) if (shift == 0)
{ return false;
/* Shift the value into the low part of the register. */
*value = expand_binop (GET_MODE (*value), lshr_optab, *value, /* Use ashr rather than lshr for right shifts. This is for the benefit
GEN_INT (shift), 0, 1, OPTAB_WIDEN); of the MIPS port, which requires SImode values to be sign-extended
when stored in 64-bit registers. */
/* Truncate it to the type's mode, or its integer equivalent. if (!force_expand_binop (GET_MODE (value), left_p ? ashl_optab : ashr_optab,
This is subject to TRULY_NOOP_TRUNCATION. */ value, GEN_INT (shift), value, 1, OPTAB_WIDEN))
*value = convert_to_mode (int_mode_for_mode (TYPE_MODE (type)), gcc_unreachable ();
*value, 0); return true;
/* Now convert it to the final form. */
*value = gen_lowpart (TYPE_MODE (type), *value);
return true;
}
}
return false;
} }
/* Remove all REG_EQUIV notes found in the insn chain. */ /* Remove all REG_EQUIV notes found in the insn chain. */
...@@ -2660,6 +2647,20 @@ expand_call (tree exp, rtx target, int ignore) ...@@ -2660,6 +2647,20 @@ expand_call (tree exp, rtx target, int ignore)
next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage, next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
flags, & args_so_far); 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. /* If call is cse'able, make appropriate pair of reg-notes around it.
Test valreg so we don't crash; may safely ignore `const' Test valreg so we don't crash; may safely ignore `const'
if return type is void. Disable for PARALLEL return values, because if return type is void. Disable for PARALLEL return values, because
...@@ -2851,12 +2852,7 @@ expand_call (tree exp, rtx target, int ignore) ...@@ -2851,12 +2852,7 @@ expand_call (tree exp, rtx target, int ignore)
sibcall_failure = 1; sibcall_failure = 1;
} }
else else
{ target = copy_to_reg (valreg);
if (shift_returned_value (TREE_TYPE (exp), &valreg))
sibcall_failure = 1;
target = copy_to_reg (valreg);
}
if (targetm.calls.promote_function_return(funtype)) if (targetm.calls.promote_function_return(funtype))
{ {
......
...@@ -551,6 +551,8 @@ extern rtx hard_function_value (tree, tree, int); ...@@ -551,6 +551,8 @@ extern rtx hard_function_value (tree, tree, int);
extern rtx prepare_call_address (rtx, rtx, rtx *, int, 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 rtx expand_call (tree, rtx, int);
extern void fixup_tail_calls (void); extern void fixup_tail_calls (void);
......
...@@ -4059,22 +4059,31 @@ expand_function_start (tree subr) ...@@ -4059,22 +4059,31 @@ expand_function_start (tree subr)
{ {
/* Compute the return values into a pseudo reg, which we will copy /* Compute the return values into a pseudo reg, which we will copy
into the true return register after the cleanups are done. */ into the true return register after the cleanups are done. */
tree return_type = TREE_TYPE (DECL_RESULT (subr));
/* In order to figure out what mode to use for the pseudo, we if (TYPE_MODE (return_type) != BLKmode
figure out what the mode of the eventual return register will && targetm.calls.return_in_msb (return_type))
actually be, and use that. */ /* expand_function_end will insert the appropriate padding in
rtx hard_reg this case. Use the return value's natural (unpadded) mode
= hard_function_value (TREE_TYPE (DECL_RESULT (subr)), within the function proper. */
subr, 1); SET_DECL_RTL (DECL_RESULT (subr),
gen_reg_rtx (TYPE_MODE (return_type)));
/* 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 else
{ {
gcc_assert (GET_CODE (hard_reg) == PARALLEL); /* In order to figure out what mode to use for the pseudo, we
SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg)); 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 /* Set DECL_REGISTER flag so that expand_function_end will copy the
...@@ -4368,10 +4377,22 @@ expand_function_end (void) ...@@ -4368,10 +4377,22 @@ expand_function_end (void)
if (GET_MODE (real_decl_rtl) == BLKmode) if (GET_MODE (real_decl_rtl) == BLKmode)
PUT_MODE (real_decl_rtl, GET_MODE (decl_rtl)); 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 /* If a named return value dumped decl_return to memory, then
we may need to re-do the PROMOTE_MODE signed/unsigned we may need to re-do the PROMOTE_MODE signed/unsigned
extension. */ 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)); int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result));
......
...@@ -427,7 +427,7 @@ simplify_expand_binop (enum machine_mode mode, optab binoptab, ...@@ -427,7 +427,7 @@ simplify_expand_binop (enum machine_mode mode, optab binoptab,
/* Like simplify_expand_binop, but always put the result in TARGET. /* Like simplify_expand_binop, but always put the result in TARGET.
Return true if the expansion succeeded. */ Return true if the expansion succeeded. */
static bool bool
force_expand_binop (enum machine_mode mode, optab binoptab, force_expand_binop (enum machine_mode mode, optab binoptab,
rtx op0, rtx op1, rtx target, int unsignedp, rtx op0, rtx op1, rtx target, int unsignedp,
enum optab_methods methods) enum optab_methods methods)
......
...@@ -425,6 +425,9 @@ extern rtx expand_ternary_op (enum machine_mode mode, optab ternary_optab, ...@@ -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, extern rtx expand_binop (enum machine_mode, optab, rtx, rtx, rtx, int,
enum optab_methods); 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. */ /* Expand a binary operation with both signed and unsigned forms. */
extern rtx sign_expand_binop (enum machine_mode, optab, optab, rtx, rtx, extern rtx sign_expand_binop (enum machine_mode, optab, optab, rtx, rtx,
rtx, int, enum optab_methods); rtx, int, enum optab_methods);
......
...@@ -110,7 +110,6 @@ static bool check_operand_nalternatives (tree, tree); ...@@ -110,7 +110,6 @@ static bool check_operand_nalternatives (tree, tree);
static bool check_unique_operand_names (tree, tree); static bool check_unique_operand_names (tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree); static char *resolve_operand_name_1 (char *, tree, tree);
static void expand_null_return_1 (void); static void expand_null_return_1 (void);
static rtx shift_return_value (rtx);
static void expand_value_return (rtx); static void expand_value_return (rtx);
static void do_jump_if_equal (rtx, rtx, rtx, int); static void do_jump_if_equal (rtx, rtx, rtx, int);
static int estimate_case_costs (case_node_ptr); static int estimate_case_costs (case_node_ptr);
...@@ -1500,33 +1499,6 @@ expand_naked_return (void) ...@@ -1500,33 +1499,6 @@ expand_naked_return (void)
emit_jump (end_label); 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. */ /* Generate RTL to return from the current function, with value VAL. */
static void static void
...@@ -1737,7 +1709,7 @@ expand_return (tree retval) ...@@ -1737,7 +1709,7 @@ expand_return (tree retval)
val = expand_expr (retval_rhs, val, GET_MODE (val), 0); val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
val = force_not_mem (val); val = force_not_mem (val);
/* Return the calculated value. */ /* Return the calculated value. */
expand_value_return (shift_return_value (val)); expand_value_return (val);
} }
else else
{ {
......
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> 2004-11-24 Mark Mitchell <mark@codesourcery.com>
* g++.dg/template/deduce3.C: New test. * g++.dg/template/deduce3.C: New test.
......
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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment