Commit a7bba6ca by Eric Botcazou Committed by Eric Botcazou

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
parent 2cb612d1
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> 2004-01-26 Richard Sandiford <rsandifo@redhat.com>
* config/mips/mips.c (mips16_optimize_gp): Delete. * config/mips/mips.c (mips16_optimize_gp): Delete.
......
...@@ -4827,7 +4827,7 @@ init_cumulative_args (struct sparc_args *cum, tree fntype, ...@@ -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. */ Sub-fields are not taken into account for the PACKED_P predicate. */
static void 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; tree field;
...@@ -5002,6 +5002,7 @@ static void function_arg_record_value_2 ...@@ -5002,6 +5002,7 @@ static void function_arg_record_value_2
static void function_arg_record_value_1 static void function_arg_record_value_1
(tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool); (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_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 /* A subroutine of function_arg_record_value. Traverse the structure
recursively and determine how many registers will be required. */ recursively and determine how many registers will be required. */
...@@ -5335,6 +5336,34 @@ function_arg_record_value (tree type, enum machine_mode mode, ...@@ -5335,6 +5336,34 @@ function_arg_record_value (tree type, enum machine_mode mode,
return parms.ret; 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. /* Handle the FUNCTION_ARG macro.
Determine where to put an argument to a function. Determine where to put an argument to a function.
Value is zero to push the argument on the stack, 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, ...@@ -5384,14 +5413,12 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
} }
else if (type && TREE_CODE (type) == UNION_TYPE) else if (type && TREE_CODE (type) == UNION_TYPE)
{ {
enum machine_mode mode; HOST_WIDE_INT size = int_size_in_bytes (type);
int bytes = int_size_in_bytes (type);
if (bytes > 16) if (size > 16)
abort (); abort (); /* shouldn't get here */
mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0); return function_arg_union_value (size, regno);
reg = gen_rtx_REG (mode, regno);
} }
/* v9 fp args in reg slots beyond the int reg slots get passed in regs /* v9 fp args in reg slots beyond the int reg slots get passed in regs
but also have the slot allocated for them. but also have the slot allocated for them.
...@@ -5646,12 +5673,13 @@ rtx ...@@ -5646,12 +5673,13 @@ rtx
function_value (tree type, enum machine_mode mode, int incoming_p) function_value (tree type, enum machine_mode mode, int incoming_p)
{ {
int regno; int regno;
int regbase = (incoming_p
? SPARC_OUTGOING_INT_ARG_FIRST
: SPARC_INCOMING_INT_ARG_FIRST);
if (TARGET_ARCH64 && type) if (TARGET_ARCH64 && type)
{ {
int regbase = (incoming_p
? SPARC_OUTGOING_INT_ARG_FIRST
: SPARC_INCOMING_INT_ARG_FIRST);
if (TREE_CODE (type) == RECORD_TYPE) if (TREE_CODE (type) == RECORD_TYPE)
{ {
/* Structures up to 32 bytes in size are passed in registers, /* 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) ...@@ -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); 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)) else if (AGGREGATE_TYPE_P (type))
{ {
/* All other aggregate types are passed in an integer register /* 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) ...@@ -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); 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) if (incoming_p)
regno = BASE_RETURN_VALUE_REG (mode); regno = BASE_RETURN_VALUE_REG (mode);
......
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