aboutsummaryrefslogtreecommitdiff
path: root/gcc/stmt.c
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@redhat.com>2003-11-16 19:10:09 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2003-11-16 19:10:09 +0000
commitc988af2b8cb75ca28789f30a6bb650b38684cc0b (patch)
tree9ef329c0c8bbcf96f5ead9aa89d71751793d4122 /gcc/stmt.c
parente0c99e151e45babaac50125628ca9caf0f8c9008 (diff)
downloadgcc-c988af2b8cb75ca28789f30a6bb650b38684cc0b.zip
gcc-c988af2b8cb75ca28789f30a6bb650b38684cc0b.tar.gz
gcc-c988af2b8cb75ca28789f30a6bb650b38684cc0b.tar.bz2
Makefile.in (expr.o): Depend on $(TARGET_H).
* Makefile.in (expr.o): Depend on $(TARGET_H). * target.h (return_in_msb): New target hook. * target-def.h (TARGET_RETURN_IN_MSB): New macro. (TARGET_CALLS): Include it. * calls.c (shift_returned_value): New function. (expand_call): Use it. * expr.c: Include target.h. (copy_blkmode_from_reg): Check targetm.calls.return_in_msb when deciding what padding is needed. Change the name of the local padding variable from big_endian_correction to padding_correction. * stmt.c (shift_return_value): New function. (expand_return): Use it. Adjust memory->register copy in the same way as copy_blkmode_from_reg. Only change the return register's mode if it was originally BLKmode. * doc/tm.texi (TARGET_RETURN_IN_MSB): Document. * config/mips/mips.c (TARGET_RETURN_IN_MSB): Define. (mips_fpr_return_fields): New, split out from mips_function_value. (mips_return_in_msb, mips_return_fpr_pair): New functions. (mips_function_value): Rework to use the functions above. * config/mips/irix6-libc-compat.c: Delete. * config/mips/t-iris6 (LIB2FUNCS_STATIC_EXTRA): Undefine. From-SVN: r73652
Diffstat (limited to 'gcc/stmt.c')
-rw-r--r--gcc/stmt.c93
1 files changed, 67 insertions, 26 deletions
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 718f255..3c8e286 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -403,6 +403,7 @@ static bool check_unique_operand_names (tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree);
static void expand_null_return_1 (rtx);
static enum br_predictor return_prediction (rtx);
+static rtx shift_return_value (rtx);
static void expand_value_return (rtx);
static int tail_recursion_args (tree, tree);
static void expand_cleanups (tree, int, int);
@@ -2902,6 +2903,34 @@ return_prediction (rtx val)
return PRED_NO_PREDICTION;
}
+
+/* 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_binop (GET_MODE (target), ashl_optab,
+ gen_lowpart (GET_MODE (target), val),
+ GEN_INT (shift), target, 1, OPTAB_WIDEN);
+ }
+ return val;
+}
+
+
/* Generate RTL to return from the current function, with value VAL. */
static void
@@ -3066,7 +3095,7 @@ expand_return (tree retval)
{
int i;
unsigned HOST_WIDE_INT bitpos, xbitpos;
- unsigned HOST_WIDE_INT big_endian_correction = 0;
+ unsigned HOST_WIDE_INT padding_correction = 0;
unsigned HOST_WIDE_INT bytes
= int_size_in_bytes (TREE_TYPE (retval_rhs));
int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
@@ -3083,25 +3112,33 @@ expand_return (tree retval)
return;
}
- /* Structures whose size is not a multiple of a word are aligned
- to the least significant byte (to the right). On a BYTES_BIG_ENDIAN
- machine, this means we must skip the empty high order bytes when
- calculating the bit offset. */
- if (BYTES_BIG_ENDIAN
- && bytes % UNITS_PER_WORD)
- big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
- * BITS_PER_UNIT));
+ /* If the structure doesn't take up a whole number of words, see
+ whether the register value should be padded on the left or on
+ the right. Set PADDING_CORRECTION to the number of padding
+ bits needed on the left side.
+
+ In most ABIs, the structure will be returned at the least end of
+ the register, which translates to right padding on little-endian
+ targets and left padding on big-endian targets. The opposite
+ holds if the structure is returned at the most significant
+ end of the register. */
+ if (bytes % UNITS_PER_WORD != 0
+ && (targetm.calls.return_in_msb (TREE_TYPE (retval_rhs))
+ ? !BYTES_BIG_ENDIAN
+ : BYTES_BIG_ENDIAN))
+ padding_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
+ * BITS_PER_UNIT));
/* Copy the structure BITSIZE bits at a time. */
- for (bitpos = 0, xbitpos = big_endian_correction;
+ for (bitpos = 0, xbitpos = padding_correction;
bitpos < bytes * BITS_PER_UNIT;
bitpos += bitsize, xbitpos += bitsize)
{
/* We need a new destination pseudo each time xbitpos is
- on a word boundary and when xbitpos == big_endian_correction
+ on a word boundary and when xbitpos == padding_correction
(the first time through). */
if (xbitpos % BITS_PER_WORD == 0
- || xbitpos == big_endian_correction)
+ || xbitpos == padding_correction)
{
/* Generate an appropriate register. */
dst = gen_reg_rtx (word_mode);
@@ -3128,21 +3165,25 @@ expand_return (tree retval)
BITS_PER_WORD);
}
- /* Find the smallest integer mode large enough to hold the
- entire structure and use that mode instead of BLKmode
- on the USE insn for the return register. */
- for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
- tmpmode != VOIDmode;
- tmpmode = GET_MODE_WIDER_MODE (tmpmode))
- /* Have we found a large enough mode? */
- if (GET_MODE_SIZE (tmpmode) >= bytes)
- break;
+ tmpmode = GET_MODE (result_rtl);
+ if (tmpmode == BLKmode)
+ {
+ /* Find the smallest integer mode large enough to hold the
+ entire structure and use that mode instead of BLKmode
+ on the USE insn for the return register. */
+ for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ tmpmode != VOIDmode;
+ tmpmode = GET_MODE_WIDER_MODE (tmpmode))
+ /* Have we found a large enough mode? */
+ if (GET_MODE_SIZE (tmpmode) >= bytes)
+ break;
- /* No suitable mode found. */
- if (tmpmode == VOIDmode)
- abort ();
+ /* No suitable mode found. */
+ if (tmpmode == VOIDmode)
+ abort ();
- PUT_MODE (result_rtl, tmpmode);
+ PUT_MODE (result_rtl, tmpmode);
+ }
if (GET_MODE_SIZE (tmpmode) < GET_MODE_SIZE (word_mode))
result_reg_mode = word_mode;
@@ -3175,7 +3216,7 @@ expand_return (tree retval)
val = force_not_mem (val);
emit_queue ();
/* Return the calculated value, doing cleanups first. */
- expand_value_return (val);
+ expand_value_return (shift_return_value (val));
}
else
{