sparc.c (function_arg_slotno): Handle aggregate types other than record and union types.

* config/sparc/sparc.c (function_arg_slotno) <BLKmode>: Handle
	aggregate types other than record and union types.
	(function_arg): Likewise.
	(function_arg_pass_by_reference): In 64-bit mode, return 0 for
	small arrays.
	(function_value): In 64-bit mode, return objects that require it
	in FP registers.

From-SVN: r112859
This commit is contained in:
Eric Botcazou 2006-04-11 18:25:46 +02:00 committed by Eric Botcazou
parent 20cbfac4e9
commit ef6843ed0b
2 changed files with 90 additions and 76 deletions

View file

@ -1,3 +1,13 @@
2006-04-11 Eric Botcazou <ebotcazou@libertysurf.fr>
* config/sparc/sparc.c (function_arg_slotno) <BLKmode>: Handle
aggregate types other than record and union types.
(function_arg): Likewise.
(function_arg_pass_by_reference): In 64-bit mode, return 0 for
small arrays.
(function_value): In 64-bit mode, return objects that require it
in FP registers.
2006-04-11 Roger Sayle <roger@eyesopen.com>
* dwarf2out.c (premark_used_types): Remove problematic prototype.

View file

@ -4559,7 +4559,10 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
gcc_assert (mode == BLKmode);
if (TARGET_ARCH32 || !type || (TREE_CODE (type) == UNION_TYPE))
if (TARGET_ARCH32
|| !type
|| (TREE_CODE (type) != VECTOR_TYPE
&& TREE_CODE (type) != RECORD_TYPE))
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
@ -5073,45 +5076,19 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno, regno, padding;
enum mode_class mclass = GET_MODE_CLASS (mode);
rtx reg;
slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
&regno, &padding);
if (slotno == -1)
return 0;
if (TARGET_ARCH32)
{
reg = gen_rtx_REG (mode, regno);
return reg;
}
if (type && TREE_CODE (type) == RECORD_TYPE)
{
/* Structures up to 16 bytes in size are passed in arg slots on the
stack and are promoted to registers where possible. */
gcc_assert (int_size_in_bytes (type) <= 16);
return function_arg_record_value (type, mode, slotno, named, regbase);
}
else if (type && TREE_CODE (type) == UNION_TYPE)
/* Vector types deserve special treatment because they are polymorphic wrt
their mode, depending upon whether VIS instructions are enabled. */
if (type && TREE_CODE (type) == VECTOR_TYPE)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
gcc_assert (size <= 16);
return function_arg_union_value (size, mode, slotno, regno);
}
else if (type && TREE_CODE (type) == VECTOR_TYPE)
{
/* Vector types deserve special treatment because they are
polymorphic wrt their mode, depending upon whether VIS
instructions are enabled. */
HOST_WIDE_INT size = int_size_in_bytes (type);
gcc_assert (size <= 16);
gcc_assert ((TARGET_ARCH32 && size <= 8)
|| (TARGET_ARCH64 && size <= 16));
if (mode == BLKmode)
return function_arg_vector_value (size,
@ -5121,14 +5098,36 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
mclass = MODE_FLOAT;
}
if (TARGET_ARCH32)
return gen_rtx_REG (mode, regno);
/* Structures up to 16 bytes in size are passed in arg slots on the stack
and are promoted to registers if possible. */
if (type && TREE_CODE (type) == RECORD_TYPE)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
gcc_assert (size <= 16);
return function_arg_record_value (type, mode, slotno, named, regbase);
}
/* Unions up to 16 bytes in size are passed in integer registers. */
else if (type && TREE_CODE (type) == UNION_TYPE)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
gcc_assert (size <= 16);
return function_arg_union_value (size, mode, slotno, regno);
}
/* v9 fp args in reg slots beyond the int reg slots get passed in regs
but also have the slot allocated for them.
If no prototype is in scope fp values in register slots get passed
in two places, either fp regs and int regs or fp regs and memory. */
if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
&& SPARC_FP_REG_P (regno))
else if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
&& SPARC_FP_REG_P (regno))
{
reg = gen_rtx_REG (mode, regno);
rtx reg = gen_rtx_REG (mode, regno);
if (cum->prototype_p || cum->libcall_p)
{
/* "* 2" because fp reg numbers are recorded in 4 byte
@ -5189,13 +5188,18 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
}
}
}
else
/* All other aggregate types are passed in an integer register in a mode
corresponding to the size of the type. */
else if (type && AGGREGATE_TYPE_P (type))
{
/* Scalar or complex int. */
reg = gen_rtx_REG (mode, regno);
HOST_WIDE_INT size = int_size_in_bytes (type);
gcc_assert (size <= 16);
mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
}
return reg;
return gen_rtx_REG (mode, regno);
}
/* For an arg passed partly in registers and partly in memory,
@ -5271,7 +5275,6 @@ sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
bool named ATTRIBUTE_UNUSED)
{
if (TARGET_ARCH32)
{
/* Original SPARC 32-bit ABI says that structures and unions,
and quad-precision floats are passed by reference. For Pascal,
also pass arrays by reference. All other base types are passed
@ -5286,19 +5289,17 @@ sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
integers are passed like floats of the same size, that is in
registers up to 8 bytes. Pass all vector floats by reference
like structure and unions. */
return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
|| mode == SCmode
/* Catch CDImode, TFmode, DCmode and TCmode. */
|| GET_MODE_SIZE (mode) > 8
|| (type
&& TREE_CODE (type) == VECTOR_TYPE
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
}
return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
|| mode == SCmode
/* Catch CDImode, TFmode, DCmode and TCmode. */
|| GET_MODE_SIZE (mode) > 8
|| (type
&& TREE_CODE (type) == VECTOR_TYPE
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
else
{
/* Original SPARC 64-bit ABI says that structures and unions
smaller than 16 bytes are passed in registers, as well as
all other base types. For Pascal, pass arrays by reference.
all other base types.
Extended ABI (as implemented by the Sun compiler) says that
complex floats are passed in registers up to 16 bytes. Pass
@ -5309,13 +5310,11 @@ sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
integers are passed like floats of the same size, that is in
registers (up to 16 bytes). Pass all vector floats like structure
and unions. */
return ((type && TREE_CODE (type) == ARRAY_TYPE)
|| (type
&& (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE)
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
/* Catch CTImode and TCmode. */
|| GET_MODE_SIZE (mode) > 16);
}
return ((type
&& (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE)
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
/* Catch CTImode and TCmode. */
|| GET_MODE_SIZE (mode) > 16);
}
/* Handle the FUNCTION_ARG_ADVANCE macro.
@ -5499,13 +5498,11 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
enum mode_class mclass = GET_MODE_CLASS (mode);
int regno;
/* Vector types deserve special treatment because they are polymorphic wrt
their mode, depending upon whether VIS instructions are enabled. */
if (type && TREE_CODE (type) == VECTOR_TYPE)
{
/* Vector types deserve special treatment because they are
polymorphic wrt their mode, depending upon whether VIS
instructions are enabled. */
HOST_WIDE_INT size = int_size_in_bytes (type);
gcc_assert ((TARGET_ARCH32 && size <= 8)
|| (TARGET_ARCH64 && size <= 32));
@ -5516,34 +5513,41 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
else
mclass = MODE_FLOAT;
}
else if (type && TARGET_ARCH64)
if (TARGET_ARCH64 && type)
{
/* Structures up to 32 bytes in size are returned in registers. */
if (TREE_CODE (type) == RECORD_TYPE)
{
/* Structures up to 32 bytes in size are passed in registers,
promoted to fp registers where possible. */
gcc_assert (int_size_in_bytes (type) <= 32);
HOST_WIDE_INT size = int_size_in_bytes (type);
gcc_assert (size <= 32);
return function_arg_record_value (type, mode, 0, 1, regbase);
}
/* Unions up to 32 bytes in size are returned in integer registers. */
else if (TREE_CODE (type) == UNION_TYPE)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
gcc_assert (size <= 32);
return function_arg_union_value (size, mode, 0, regbase);
}
/* Objects that require it are returned in FP registers. */
else if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
;
/* All other aggregate types are returned in an integer register in a
mode corresponding to the size of the type. */
else if (AGGREGATE_TYPE_P (type))
{
/* All other aggregate types are passed in an integer register
in a mode corresponding to the size of the type. */
HOST_WIDE_INT bytes = int_size_in_bytes (type);
HOST_WIDE_INT size = int_size_in_bytes (type);
gcc_assert (size <= 32);
gcc_assert (bytes <= 32);
mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
/* ??? We probably should have made the same ABI change in
3.4.0 as the one we made for unions. The latter was
@ -5555,17 +5559,17 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
try to be unduly clever, and simply follow the ABI
for unions in that case. */
if (mode == BLKmode)
return function_arg_union_value (bytes, mode, 0, regbase);
return function_arg_union_value (size, mode, 0, regbase);
else
mclass = MODE_INT;
}
else if (mclass == MODE_INT
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
/* This must match PROMOTE_FUNCTION_MODE. */
else if (mclass == MODE_INT && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
mode = word_mode;
}
if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
&& TARGET_FPU)
if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) && TARGET_FPU)
regno = SPARC_FP_ARG_FIRST;
else
regno = regbase;