diff options
author | Richard Sandiford <rsandifo@redhat.com> | 2004-11-24 18:50:26 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2004-11-24 18:50:26 +0000 |
commit | bef5d8b61f6732bec53128324913bfa8a5093a07 (patch) | |
tree | b60ced5605459fa37b62bcb5a6c1cced24e7b3fd | |
parent | 6e2993bf5b71c17c2b60e0dec787750f44925e66 (diff) | |
download | gcc-bef5d8b61f6732bec53128324913bfa8a5093a07.zip gcc-bef5d8b61f6732bec53128324913bfa8a5093a07.tar.gz gcc-bef5d8b61f6732bec53128324913bfa8a5093a07.tar.bz2 |
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
-rw-r--r-- | gcc/ChangeLog | 20 | ||||
-rw-r--r-- | gcc/calls.c | 70 | ||||
-rw-r--r-- | gcc/expr.h | 2 | ||||
-rw-r--r-- | gcc/function.c | 51 | ||||
-rw-r--r-- | gcc/optabs.c | 2 | ||||
-rw-r--r-- | gcc/optabs.h | 3 | ||||
-rw-r--r-- | gcc/stmt.c | 30 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20041124-1.c | 10 |
9 files changed, 110 insertions, 82 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d2ffdac..3b2def7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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. diff --git a/gcc/calls.c b/gcc/calls.c index 44806d4c..3c4d13e 100644 --- a/gcc/calls.c +++ b/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); - - /* 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; + 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; + + /* 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); diff --git a/gcc/function.c b/gcc/function.c index da78d3f..1021fc2 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -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)); diff --git a/gcc/optabs.c b/gcc/optabs.c index 1887772..14f2b72 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -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) diff --git a/gcc/optabs.h b/gcc/optabs.h index 09afccb..76ec8de 100644 --- a/gcc/optabs.h +++ b/gcc/optabs.h @@ -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); @@ -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 { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f647b33..25f2f13 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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. diff --git a/gcc/testsuite/gcc.c-torture/execute/20041124-1.c b/gcc/testsuite/gcc.c-torture/execute/20041124-1.c new file mode 100644 index 0000000..51ce253 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20041124-1.c @@ -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); +} |