sparc.c (scan_record_type): Handle vector types.

* config/sparc/sparc.c (scan_record_type): Handle vector types.
	(function_arg_slotno): Handle vector types specially.
	(function_arg_record_value_1): Split fields with vector type and
	BLKmode into their subparts.
	(function_arg_record_value_2): Likewise.  Be prepared to handle
	more than 2 registers per field.
	(function_arg_union_value): Increment regno inside the loop.
	(function_arg_vector_value): New function.
	(function_arg): Use it to split fields with vector type and
	BLKmode into their subparts and build a PARALLEL.  Treat
	other vector types like floats.
	(function_value): Likewise.
	(sparc_pass_by_reference): Handle vector types.
	(sparc_return_in_memory): Likewise.

From-SVN: r90179
This commit is contained in:
Eric Botcazou 2004-11-06 18:06:05 +01:00 committed by Eric Botcazou
parent 8d43449bee
commit 45261626da
2 changed files with 232 additions and 72 deletions

View File

@ -1,3 +1,20 @@
2004-11-06 Eric Botcazou <ebotcazou@libertysurf.fr>
* config/sparc/sparc.c (scan_record_type): Handle vector types.
(function_arg_slotno): Handle vector types specially.
(function_arg_record_value_1): Split fields with vector type and
BLKmode into their subparts.
(function_arg_record_value_2): Likewise. Be prepared to handle
more than 2 registers per field.
(function_arg_union_value): Increment regno inside the loop.
(function_arg_vector_value): New function.
(function_arg): Use it to split fields with vector type and
BLKmode into their subparts and build a PARALLEL. Treat
other vector types like floats.
(function_value): Likewise.
(sparc_pass_by_reference): Handle vector types.
(sparc_return_in_memory): Likewise.
2004-11-06 Kazu Hirata <kazu@cs.umass.edu>
* tree-cfg.c (find_taken_edge_cond_expr): Remove an "if"

View File

@ -4928,8 +4928,7 @@ output_sibcall (rtx insn, rtx call_operand)
_Complex double 16 memory FP reg.
_Complex long double 32 memory FP reg.
vector float <=32 memory FP reg.
vector float >32 memory memory
vector float any memory memory
aggregate any memory memory
@ -4974,8 +4973,8 @@ implemented by the Sun compiler.
Note #2: integral vector types follow the scalar floating-point types
conventions to match what is implemented by the Sun VIS SDK.
Note #3: floating-point vector types follow the complex floating-point
types conventions. */
Note #3: floating-point vector types follow the aggregate types
conventions. */
/* Maximum number of int regs for args. */
@ -5037,7 +5036,9 @@ scan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p)
{
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
scan_record_type (TREE_TYPE (field), intregs_p, fpregs_p, 0);
else if (FLOAT_TYPE_P (TREE_TYPE (field)) && TARGET_FPU)
else if ((FLOAT_TYPE_P (TREE_TYPE (field))
|| TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
&& TARGET_FPU)
*fpregs_p = 1;
else
*intregs_p = 1;
@ -5072,6 +5073,7 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno = cum->words;
enum mode_class mclass;
int regno;
*ppadding = 0;
@ -5091,12 +5093,37 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
&& (slotno & 1) != 0)
slotno++, *ppadding = 1;
switch (GET_MODE_CLASS (mode))
mclass = GET_MODE_CLASS (mode);
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. */
if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
{
/* The SPARC port defines no floating-point vector modes. */
if (mode != BLKmode)
abort ();
}
else
{
/* Integral vector types should either have a vector
mode or an integral mode, because we are guaranteed
by pass_by_reference that their size is not greater
than 16 bytes and TImode is 16-byte wide. */
if (mode == BLKmode)
abort ();
/* Vector integers are handled like floats according to
the Sun VIS SDK. */
mclass = MODE_FLOAT;
}
}
switch (mclass)
{
case MODE_FLOAT:
case MODE_COMPLEX_FLOAT:
case MODE_VECTOR_INT:
case MODE_VECTOR_FLOAT:
if (TARGET_ARCH64 && TARGET_FPU && named)
{
if (slotno >= SPARC_FP_ARG_MAX)
@ -5132,18 +5159,21 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
&& (slotno & 1) != 0)
slotno++, *ppadding = 1;
if (TARGET_ARCH32 || (type && TREE_CODE (type) == UNION_TYPE))
if (TARGET_ARCH32 || !type || (TREE_CODE (type) == UNION_TYPE))
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
}
else /* TARGET_ARCH64 && type && TREE_CODE (type) == RECORD_TYPE */
else /* TARGET_ARCH64 && type */
{
int intregs_p = 0, fpregs_p = 0, packed_p = 0;
/* First see what kinds of registers we would need. */
scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
if (TREE_CODE (type) == VECTOR_TYPE)
fpregs_p = 1;
else
scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
/* The ABI obviously doesn't specify how packed structures
are passed. These are defined to be passed in int regs
@ -5274,8 +5304,12 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
/* There's no need to check this_slotno < SPARC_FP_ARG MAX.
If it wasn't true we wouldn't be here. */
parms->nregs += 1;
if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
&& DECL_MODE (field) == BLKmode)
parms->nregs += TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
parms->nregs += 2;
else
parms->nregs += 1;
}
else
@ -5389,34 +5423,41 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
&& ! packed_p)
{
int this_slotno = parms->slotno + bitpos / BITS_PER_WORD;
int regno;
int regno, nregs, pos;
enum machine_mode mode = DECL_MODE (field);
rtx reg;
function_arg_record_value_3 (bitpos, parms);
switch (mode)
{
case SCmode: mode = SFmode; break;
case DCmode: mode = DFmode; break;
case TCmode: mode = TFmode; break;
default: break;
if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
&& mode == BLKmode)
{
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
}
else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
{
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
nregs = 2;
}
else
nregs = 1;
regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
regno++;
reg = gen_rtx_REG (mode, regno);
pos = bitpos / BITS_PER_UNIT;
XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
= gen_rtx_EXPR_LIST (VOIDmode, reg,
GEN_INT (bitpos / BITS_PER_UNIT));
= gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
parms->nregs += 1;
if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
while (--nregs > 0)
{
regno += GET_MODE_SIZE (mode) / 4;
reg = gen_rtx_REG (mode, regno);
pos += GET_MODE_SIZE (mode);
XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
= gen_rtx_EXPR_LIST (VOIDmode, reg,
GEN_INT ((bitpos + GET_MODE_BITSIZE (mode))
/ BITS_PER_UNIT));
= gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
parms->nregs += 1;
}
}
@ -5547,14 +5588,47 @@ function_arg_union_value (int size, enum machine_mode mode, int regno)
int nwords = ROUND_ADVANCE (size), i;
rtx regs;
/* Unions are passed left-justified. */
regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
for (i = 0; i < nwords; i++)
XVECEXP (regs, 0, i)
= gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_REG (word_mode, regno + i),
GEN_INT (UNITS_PER_WORD * i));
{
/* Unions are passed left-justified. */
XVECEXP (regs, 0, i)
= gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_REG (word_mode, regno),
GEN_INT (UNITS_PER_WORD * i));
regno++;
}
return regs;
}
/* Used by function_arg and function_value to implement the conventions
for passing and returning large (BLKmode) vectors.
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 vector.
BASE_MODE is the argument's base machine mode.
REGNO is the FP hard register the vector will be passed in. */
static rtx
function_arg_vector_value (int size, enum machine_mode base_mode, int regno)
{
unsigned short base_mode_size = GET_MODE_SIZE (base_mode);
int nregs = size / base_mode_size, i;
rtx regs;
regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nregs));
for (i = 0; i < nregs; i++)
{
XVECEXP (regs, 0, i)
= gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_REG (base_mode, regno),
GEN_INT (base_mode_size * i));
regno += base_mode_size / 4;
}
return regs;
}
@ -5582,6 +5656,7 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
? SPARC_INCOMING_INT_ARG_FIRST
: 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,
@ -5615,14 +5690,29 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
return function_arg_union_value (size, mode, 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);
if (size > 16)
abort (); /* shouldn't get here */
if (mode == BLKmode)
return function_arg_vector_value (size,
TYPE_MODE (TREE_TYPE (type)),
SPARC_FP_ARG_FIRST + 2*slotno);
else
mclass = MODE_FLOAT;
}
/* 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. */
else if ((GET_MODE_CLASS (mode) == MODE_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (mode) == MODE_VECTOR_INT
|| GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
&& SPARC_FP_REG_P (regno))
{
reg = gen_rtx_REG (mode, regno);
@ -5760,11 +5850,8 @@ function_arg_partial_nregs (const struct sparc_args *cum,
return 0;
}
/* Return true if the argument should be passed by reference.
!v9: The SPARC ABI stipulates passing struct arguments (of any size) and
quad-precision floats by invisible reference.
v9: Aggregates greater than 16 bytes are passed by reference.
For Pascal, also pass arrays by reference. */
/* Handle the TARGET_PASS_BY_REFERENCE target hook.
Specify whether to pass the argument by reference. */
static bool
sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
@ -5773,23 +5860,48 @@ sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
{
if (TARGET_ARCH32)
{
return ((type && AGGREGATE_TYPE_P (type))
/* Extended ABI (as implemented by the Sun compiler) says
that all complex floats are passed in memory. */
/* 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
in registers.
Extended ABI (as implemented by the Sun compiler) says that all
complex floats are passed by reference. Pass complex integers
in registers up to 8 bytes. More generally, enforce the 2-word
cap for passing arguments in registers.
Vector ABI (as implemented by the Sun VIS SDK) says that vector
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
/* Enforce the 2-word cap for passing arguments in registers.
This affects CDImode, TFmode, DCmode, TCmode and large
vector modes. */
|| GET_MODE_SIZE (mode) > 8);
/* 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.
Extended ABI (as implemented by the Sun compiler) says that
complex floats are passed in registers up to 16 bytes. Pass
all complex integers in registers up to 16 bytes. More generally,
enforce the 2-word cap for passing arguments in registers.
Vector ABI (as implemented by the Sun VIS SDK) says that vector
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)
&& (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE)
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
/* Enforce the 2-word cap for passing arguments in registers.
This affects CTImode, TCmode and large vector modes. */
/* Catch CTImode and TCmode. */
|| GET_MODE_SIZE (mode) > 16);
}
}
@ -5861,30 +5973,40 @@ static bool
sparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
{
if (TARGET_ARCH32)
/* Original SPARC 32-bit ABI says that quad-precision floats
and all structures are returned in memory. Extended ABI
(as implemented by the Sun compiler) says that all complex
floats are returned in registers (8 FP registers at most
for '_Complex long double'). Return all complex integers
in registers (4 at most for '_Complex long long'). */
/* Original SPARC 32-bit ABI says that structures and unions,
and quad-precision floats are returned in memory. All other
base types are returned in registers.
Extended ABI (as implemented by the Sun compiler) says that
all complex floats are returned in registers (8 FP registers
at most for '_Complex long double'). Return all complex integers
in registers (4 at most for '_Complex long long').
Vector ABI (as implemented by the Sun VIS SDK) says that vector
integers are returned like floats of the same size, that is in
registers up to 8 bytes and in memory otherwise. Return all
vector floats in memory like structure and unions; note that
they always have BLKmode like the latter. */
return (TYPE_MODE (type) == BLKmode
|| TYPE_MODE (type) == TFmode
/* Integral vector types follow the scalar FP types conventions. */
|| (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_VECTOR_INT
&& GET_MODE_SIZE (TYPE_MODE (type)) > 8)
/* FP vector types follow the complex FP types conventions. */
|| (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_VECTOR_FLOAT
&& GET_MODE_SIZE (TYPE_MODE (type)) > 32));
|| (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 32 bytes are returned in registers. Extended
ABI (as implemented by the Sun compiler) says that all complex
floats are returned in registers (8 FP registers at most
for '_Complex long double'). Return all complex integers
in registers (4 at most for '_Complex TItype'). */
smaller than 32 bytes are returned in registers, as well as
all other base types.
Extended ABI (as implemented by the Sun compiler) says that all
complex floats are returned in registers (8 FP registers at most
for '_Complex long double'). Return all complex integers in
registers (4 at most for '_Complex TItype').
Vector ABI (as implemented by the Sun VIS SDK) says that vector
integers are returned like floats of the same size, that is in
registers. Return all vector floats like structure and unions;
note that they always have BLKmode like the latter. */
return ((TYPE_MODE (type) == BLKmode
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32)
|| GET_MODE_SIZE (TYPE_MODE (type)) > 32);
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32));
}
/* Handle the TARGET_STRUCT_VALUE target hook.
@ -5917,9 +6039,27 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
int regbase = (incoming_p
? SPARC_OUTGOING_INT_ARG_FIRST
: SPARC_INCOMING_INT_ARG_FIRST);
enum mode_class mclass = GET_MODE_CLASS (mode);
int regno;
if (TARGET_ARCH64 && type)
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);
if ((TARGET_ARCH32 && size > 8) || (TARGET_ARCH64 && size > 32))
abort (); /* shouldn't get here */
if (mode == BLKmode)
return function_arg_vector_value (size,
TYPE_MODE (TREE_TYPE (type)),
SPARC_FP_ARG_FIRST);
else
mclass = MODE_FLOAT;
}
else if (type && TARGET_ARCH64)
{
if (TREE_CODE (type) == RECORD_TYPE)
{
@ -5962,13 +6102,16 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
for unions in that case. */
if (mode == BLKmode)
return function_arg_union_value (bytes, mode, regbase);
else
mclass = MODE_INT;
}
else if (GET_MODE_CLASS (mode) == MODE_INT
else if (mclass == MODE_INT
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
mode = word_mode;
}
if (TARGET_FPU && (FLOAT_MODE_P (mode) || VECTOR_MODE_P (mode)))
if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
&& TARGET_FPU)
regno = SPARC_FP_ARG_FIRST;
else
regno = regbase;