aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@libertysurf.fr>2004-01-26 12:11:11 +0100
committerEric Botcazou <ebotcazou@gcc.gnu.org>2004-01-26 11:11:11 +0000
commita7bba6ca0e41334dfc3768af39b48a142c5ed34e (patch)
tree394359c2d0d2c999ab3115d7051f0ff25fbdba04
parent2cb612d1b0459fdb72a0af8928741869f2fdaaed (diff)
downloadgcc-a7bba6ca0e41334dfc3768af39b48a142c5ed34e.zip
gcc-a7bba6ca0e41334dfc3768af39b48a142c5ed34e.tar.gz
gcc-a7bba6ca0e41334dfc3768af39b48a142c5ed34e.tar.bz2
re PR target/13666 (deviation from the psABI for small unions)
PR target/13666 * config/sparc/sparc.c (function_arg_union_value): New function. (function_arg): Use it to deal with unions. (function_value): Likewise. Define 'regbase' only for ARCH64. Replace a conditional statement by a simpler one. From-SVN: r76628
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/sparc/sparc.c66
2 files changed, 58 insertions, 16 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index bbeb017..af75fc1 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2004-01-26 Eric Botcazou <ebotcazou@libertysurf.fr>
+
+ PR target/13666
+ * config/sparc/sparc.c (function_arg_union_value): New function.
+ (function_arg): Use it to deal with unions.
+ (function_value): Likewise. Define 'regbase' only for ARCH64.
+ Replace a conditional statement by a simpler one.
+
2004-01-26 Richard Sandiford <rsandifo@redhat.com>
* config/mips/mips.c (mips16_optimize_gp): Delete.
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index b5247b8..b732e7a 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -4827,7 +4827,7 @@ init_cumulative_args (struct sparc_args *cum, tree fntype,
Sub-fields are not taken into account for the PACKED_P predicate. */
static void
-scan_record_type(tree type, int *intregs_p, int *fpregs_p, int *packed_p)
+scan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p)
{
tree field;
@@ -5002,6 +5002,7 @@ static void function_arg_record_value_2
static void function_arg_record_value_1
(tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
static rtx function_arg_record_value (tree, enum machine_mode, int, int, int);
+static rtx function_arg_union_value (int, int);
/* A subroutine of function_arg_record_value. Traverse the structure
recursively and determine how many registers will be required. */
@@ -5335,6 +5336,34 @@ function_arg_record_value (tree type, enum machine_mode mode,
return parms.ret;
}
+/* Used by function_arg and function_value to implement the conventions
+ of the 64-bit ABI for passing and returning unions.
+ Return an expression valid as a return value for the two macros
+ FUNCTION_ARG and FUNCTION_VALUE.
+
+ SIZE is the size in bytes of the union.
+ REGNO is the hard register the union will be passed in. */
+
+static rtx
+function_arg_union_value (int size, int regno)
+{
+ enum machine_mode mode;
+ rtx reg;
+
+ if (size <= UNITS_PER_WORD)
+ mode = word_mode;
+ else
+ mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+
+ reg = gen_rtx_REG (mode, regno);
+
+ /* Unions are passed left-justified. */
+ return gen_rtx_PARALLEL (mode,
+ gen_rtvec (1, gen_rtx_EXPR_LIST (VOIDmode,
+ reg,
+ const0_rtx)));
+}
+
/* Handle the FUNCTION_ARG macro.
Determine where to put an argument to a function.
Value is zero to push the argument on the stack,
@@ -5384,14 +5413,12 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
}
else if (type && TREE_CODE (type) == UNION_TYPE)
{
- enum machine_mode mode;
- int bytes = int_size_in_bytes (type);
+ HOST_WIDE_INT size = int_size_in_bytes (type);
- if (bytes > 16)
- abort ();
+ if (size > 16)
+ abort (); /* shouldn't get here */
- mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
- reg = gen_rtx_REG (mode, regno);
+ return function_arg_union_value (size, regno);
}
/* v9 fp args in reg slots beyond the int reg slots get passed in regs
but also have the slot allocated for them.
@@ -5646,12 +5673,13 @@ rtx
function_value (tree type, enum machine_mode mode, int incoming_p)
{
int regno;
- int regbase = (incoming_p
- ? SPARC_OUTGOING_INT_ARG_FIRST
- : SPARC_INCOMING_INT_ARG_FIRST);
if (TARGET_ARCH64 && type)
{
+ int regbase = (incoming_p
+ ? SPARC_OUTGOING_INT_ARG_FIRST
+ : SPARC_INCOMING_INT_ARG_FIRST);
+
if (TREE_CODE (type) == RECORD_TYPE)
{
/* Structures up to 32 bytes in size are passed in registers,
@@ -5662,6 +5690,15 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
return function_arg_record_value (type, mode, 0, 1, regbase);
}
+ else if (TREE_CODE (type) == UNION_TYPE)
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+
+ if (size > 32)
+ abort (); /* shouldn't get here */
+
+ return function_arg_union_value (size, regbase);
+ }
else if (AGGREGATE_TYPE_P (type))
{
/* All other aggregate types are passed in an integer register
@@ -5673,13 +5710,10 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
}
+ else if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+ mode = word_mode;
}
-
- if (TARGET_ARCH64
- && GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) < UNITS_PER_WORD
- && type && ! AGGREGATE_TYPE_P (type))
- mode = DImode;
if (incoming_p)
regno = BASE_RETURN_VALUE_REG (mode);