Commit 1b5963f7 by Eric Botcazou Committed by Eric Botcazou

re PR target/12916 (No vector ABI)

	PR target/12916
	* config/sparc/sparc.h (NPARM_REGS): Delete.
	(BASE_RETURN_VALUE_REG): Likewise.
	(BASE_OUTGOING_VALUE_REG): Likewise.
	(BASE_PASSING_ARG_REG): Likewise.
	(BASE_INCOMING_ARG_REG): Likewise.
	* config/sparc/sparc.c (sparc_strict_argument_naming): Test
	TARGET_ARCH64, not TARGET_V9.
	(function_arg_slotno): Dispatch based on the mode class.
	Handle vector modes like floating-point modes.
	(function_arg_record_value_1): Handle vector types like
	floating-point types.
	(function_arg_record_value_2): Likewise.
	Calculate regno after mode transformation.
	(function_arg): Handle vector modes like floating-point modes.
	(function_arg_partial_nregs): Replace NPARM_REGS by SPARC_INT_ARG_MAX.
	If ARCH64, do not recheck alignment.
	(function_arg_pass_by_reference): Reorder the conditions.
	(sparc_return_in_memory): Move after function_arg_padding.
	Implement calling conventions for vector modes.
	(sparc_struct_value_rtx): Move after sparc_return_in_memory.
	(function_value): Move scope of 'regbase'.
	Implement calling conventions for vector modes.
	(sparc_builtin_saveregs): Replace NPARM_REGS by SPARC_INT_ARG_MAX
	and BASE_INCOMING_ARG_REG by SPARC_INCOMING_INT_ARG_FIRST.
	(sparc_va_arg): Use function_arg_pass_by_reference to test whether
	the argument is passed by reference.
	(sparc_type_code): Handle vector types.

From-SVN: r78087
parent 19037b5c
2004-02-19 Eric Botcazou <ebotcazou@libertysurf.fr>
PR target/12916
* config/sparc/sparc.h (NPARM_REGS): Delete.
(BASE_RETURN_VALUE_REG): Likewise.
(BASE_OUTGOING_VALUE_REG): Likewise.
(BASE_PASSING_ARG_REG): Likewise.
(BASE_INCOMING_ARG_REG): Likewise.
* config/sparc/sparc.c (sparc_strict_argument_naming): Test
TARGET_ARCH64, not TARGET_V9.
(function_arg_slotno): Dispatch based on the mode class.
Handle vector modes like floating-point modes.
(function_arg_record_value_1): Handle vector types like
floating-point types.
(function_arg_record_value_2): Likewise.
Calculate regno after mode transformation.
(function_arg): Handle vector modes like floating-point modes.
(function_arg_partial_nregs): Replace NPARM_REGS by SPARC_INT_ARG_MAX.
If ARCH64, do not recheck alignment.
(function_arg_pass_by_reference): Reorder the conditions.
(sparc_return_in_memory): Move after function_arg_padding.
Implement calling conventions for vector modes.
(sparc_struct_value_rtx): Move after sparc_return_in_memory.
(function_value): Move scope of 'regbase'.
Implement calling conventions for vector modes.
(sparc_builtin_saveregs): Replace NPARM_REGS by SPARC_INT_ARG_MAX
and BASE_INCOMING_ARG_REG by SPARC_INCOMING_INT_ARG_FIRST.
(sparc_va_arg): Use function_arg_pass_by_reference to test whether
the argument is passed by reference.
(sparc_type_code): Handle vector types.
2004-02-19 Alan Modra <amodra@bigpond.net.au> 2004-02-19 Alan Modra <amodra@bigpond.net.au>
* function.c (assign_parms): When building decl_rtl for * function.c (assign_parms): When building decl_rtl for
......
...@@ -4769,11 +4769,11 @@ output_sibcall (rtx insn, rtx call_operand) ...@@ -4769,11 +4769,11 @@ output_sibcall (rtx insn, rtx call_operand)
/* Functions for handling argument passing. /* Functions for handling argument passing.
For v8 the first six args are normally in registers and the rest are For 32-bit, the first 6 args are normally in registers and the rest are
pushed. Any arg that starts within the first 6 words is at least pushed. Any arg that starts within the first 6 words is at least
partially passed in a register unless its data type forbids. partially passed in a register unless its data type forbids.
For v9, the argument registers are laid out as an array of 16 elements For 64-bit, the argument registers are laid out as an array of 16 elements
and arguments are added sequentially. The first 6 int args and up to the and arguments are added sequentially. The first 6 int args and up to the
first 16 fp args (depending on size) are passed in regs. first 16 fp args (depending on size) are passed in regs.
...@@ -4798,7 +4798,7 @@ output_sibcall (rtx insn, rtx call_operand) ...@@ -4798,7 +4798,7 @@ output_sibcall (rtx insn, rtx call_operand)
Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise. Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise.
Integral arguments are always passed as 64 bit quantities appropriately Integral arguments are always passed as 64-bit quantities appropriately
extended. extended.
Passing of floating point values is handled as follows. Passing of floating point values is handled as follows.
...@@ -4815,7 +4815,81 @@ output_sibcall (rtx insn, rtx call_operand) ...@@ -4815,7 +4815,81 @@ output_sibcall (rtx insn, rtx call_operand)
appropriate integer reg and the appropriate fp reg. appropriate integer reg and the appropriate fp reg.
If the value is not one of the first 6 arguments the value is passed in If the value is not one of the first 6 arguments the value is passed in
the appropriate fp reg and in memory. the appropriate fp reg and in memory.
*/
Summary of the calling conventions implemented by GCC on SPARC:
32-bit ABI:
size argument return value
small integer <4 int. reg. int. reg.
word 4 int. reg. int. reg.
double word 8 int. reg. int. reg.
_Complex small integer <8 int. reg. int. reg.
_Complex word 8 int. reg. int. reg.
_Complex double word 16 memory int. reg.
vector integer <=8 int. reg. FP reg.
vector integer >8 memory memory
float 4 int. reg. FP reg.
double 8 int. reg. FP reg.
long double 16 memory memory
_Complex float 8 memory FP reg.
_Complex double 16 memory FP reg.
_Complex long double 32 memory FP reg.
vector float <=32 memory FP reg.
vector float >32 memory memory
aggregate any memory memory
64-bit ABI:
size argument return value
small integer <8 int. reg. int. reg.
word 8 int. reg. int. reg.
double word 16 int. reg. int. reg.
_Complex small integer <16 int. reg. int. reg.
_Complex word 16 int. reg. int. reg.
_Complex double word 32 memory int. reg.
vector integer <=16 FP reg. FP reg.
vector integer 16<s<=32 memory FP reg.
vector integer >32 memory memory
float 4 FP reg. FP reg.
double 8 FP reg. FP reg.
long double 16 FP reg. FP reg.
_Complex float 8 FP reg. FP reg.
_Complex double 16 FP reg. FP reg.
_Complex long double 32 memory FP reg.
vector float <=16 FP reg. FP reg.
vector float 16<s<=32 memory FP reg.
vector float >32 memory memory
aggregate <=16 reg. reg.
aggregate 16<s<=32 memory reg.
aggregate >32 memory memory
Note #1: complex floating-point types follow the extended SPARC ABIs as
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. */
/* Maximum number of int regs for args. */ /* Maximum number of int regs for args. */
#define SPARC_INT_ARG_MAX 6 #define SPARC_INT_ARG_MAX 6
...@@ -4853,44 +4927,7 @@ sparc_promote_prototypes (tree fntype ATTRIBUTE_UNUSED) ...@@ -4853,44 +4927,7 @@ sparc_promote_prototypes (tree fntype ATTRIBUTE_UNUSED)
static bool static bool
sparc_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED) sparc_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
{ {
/* For the V9 we want NAMED to mean what it says it means. */ return TARGET_ARCH64 ? true : false;
return TARGET_V9 ? true : false;
}
/* Handle the TARGET_RETURN_IN_MEMORY target hook.
Specify whether to return the return value in memory. */
static bool
sparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
{
/* SPARC ABI says that quad-precision floats and all structures are
returned in memory.
For V9: unions <= 32 bytes in size are returned in int regs,
structures up to 32 bytes are returned in int and fp regs. */
return (TARGET_ARCH32
? (TYPE_MODE (type) == BLKmode
|| TYPE_MODE (type) == TFmode)
: (TYPE_MODE (type) == BLKmode
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32));
}
/* Handle the TARGET_STRUCT_VALUE target hook.
Return where to find the structure return value address. */
static rtx
sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
{
if (TARGET_ARCH64)
return 0;
else
{
if (incoming)
return gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx,
STRUCT_VALUE_OFFSET));
else
return gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
STRUCT_VALUE_OFFSET));
}
} }
/* Scan the record type TYPE and return the following predicates: /* Scan the record type TYPE and return the following predicates:
...@@ -4952,82 +4989,69 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode, ...@@ -4952,82 +4989,69 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
*ppadding = 0; *ppadding = 0;
if (type != 0 && TREE_ADDRESSABLE (type)) if (type && TREE_ADDRESSABLE (type))
return -1; return -1;
if (TARGET_ARCH32 if (TARGET_ARCH32
&& type != 0 && mode == BLKmode && mode == BLKmode
&& type
&& TYPE_ALIGN (type) % PARM_BOUNDARY != 0) && TYPE_ALIGN (type) % PARM_BOUNDARY != 0)
return -1; return -1;
switch (mode) /* For SPARC64, objects requiring 16-byte alignment get it. */
{ if (TARGET_ARCH64
case VOIDmode : && GET_MODE_ALIGNMENT (mode) >= 2 * BITS_PER_WORD
/* MODE is VOIDmode when generating the actual call. && (slotno & 1) != 0)
See emit_call_1. */ slotno++, *ppadding = 1;
return -1;
case TImode : case CTImode : switch (GET_MODE_CLASS (mode))
if (TARGET_ARCH64 && (slotno & 1) != 0) {
slotno++, *ppadding = 1; 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)
return -1;
regno = SPARC_FP_ARG_FIRST + slotno * 2;
/* Arguments filling only one single FP register are
right-justified in the outer double FP register. */
if (GET_MODE_SIZE (mode) <= 4)
regno++;
break;
}
/* fallthrough */ /* fallthrough */
case QImode : case CQImode : case MODE_INT:
case HImode : case CHImode : case MODE_COMPLEX_INT:
case SImode : case CSImode :
case DImode : case CDImode :
if (slotno >= SPARC_INT_ARG_MAX) if (slotno >= SPARC_INT_ARG_MAX)
return -1; return -1;
regno = regbase + slotno; regno = regbase + slotno;
break; break;
case TFmode : case TCmode : case MODE_RANDOM:
if (TARGET_ARCH64 && (slotno & 1) != 0) if (mode == VOIDmode)
slotno++, *ppadding = 1; /* MODE is VOIDmode when generating the actual call. */
/* fallthrough */ return -1;
case SFmode : case SCmode : if (mode != BLKmode)
case DFmode : case DCmode : abort ();
if (TARGET_ARCH32)
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
}
else
{
if (TARGET_FPU && named)
{
if (slotno >= SPARC_FP_ARG_MAX)
return -1;
regno = SPARC_FP_ARG_FIRST + slotno * 2;
if (mode == SFmode)
regno++;
}
else
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
}
}
break;
case BLKmode : /* For SPARC64, objects requiring 16-byte alignment get it. */
/* For sparc64, objects requiring 16 byte alignment get it. */ if (TARGET_ARCH64
if (TARGET_ARCH64) && type
{ && TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
if (type && TYPE_ALIGN (type) == 128 && (slotno & 1) != 0) && (slotno & 1) != 0)
slotno++, *ppadding = 1; slotno++, *ppadding = 1;
}
if (TARGET_ARCH32 if (TARGET_ARCH32 || (type && TREE_CODE (type) == UNION_TYPE))
|| (type && TREE_CODE (type) == UNION_TYPE))
{ {
if (slotno >= SPARC_INT_ARG_MAX) if (slotno >= SPARC_INT_ARG_MAX)
return -1; return -1;
regno = regbase + slotno; regno = regbase + slotno;
} }
else else /* TARGET_ARCH64 && type && TREE_CODE (type) == RECORD_TYPE */
{ {
int intregs_p = 0, fpregs_p = 0, packed_p = 0; int intregs_p = 0, fpregs_p = 0, packed_p = 0;
...@@ -5043,10 +5067,12 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode, ...@@ -5043,10 +5067,12 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
/* If all arg slots are filled, then must pass on stack. */ /* If all arg slots are filled, then must pass on stack. */
if (fpregs_p && slotno >= SPARC_FP_ARG_MAX) if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
return -1; return -1;
/* If there are only int args and all int arg slots are filled, /* If there are only int args and all int arg slots are filled,
then must pass on stack. */ then must pass on stack. */
if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX) if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
return -1; return -1;
/* Note that even if all int arg slots are filled, fp members may /* Note that even if all int arg slots are filled, fp members may
still be passed in regs if such regs are available. still be passed in regs if such regs are available.
*PREGNO isn't set because there may be more than one, it's up *PREGNO isn't set because there may be more than one, it's up
...@@ -5130,7 +5156,8 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos, ...@@ -5130,7 +5156,8 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
bitpos, bitpos,
parms, parms,
packed_p); packed_p);
else if (FLOAT_TYPE_P (TREE_TYPE (field)) else if ((FLOAT_TYPE_P (TREE_TYPE (field))
|| TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
&& TARGET_FPU && TARGET_FPU
&& parms->named && parms->named
&& ! packed_p) && ! packed_p)
...@@ -5268,7 +5295,8 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos, ...@@ -5268,7 +5295,8 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
bitpos, bitpos,
parms, parms,
packed_p); packed_p);
else if (FLOAT_TYPE_P (TREE_TYPE (field)) else if ((FLOAT_TYPE_P (TREE_TYPE (field))
|| TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
&& TARGET_FPU && TARGET_FPU
&& parms->named && parms->named
&& ! packed_p) && ! packed_p)
...@@ -5279,9 +5307,6 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos, ...@@ -5279,9 +5307,6 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
rtx reg; rtx reg;
function_arg_record_value_3 (bitpos, parms); function_arg_record_value_3 (bitpos, parms);
regno = SPARC_FP_ARG_FIRST + this_slotno * 2
+ ((mode == SFmode || mode == SCmode)
&& (bitpos & 32) != 0);
switch (mode) switch (mode)
{ {
case SCmode: mode = SFmode; break; case SCmode: mode = SFmode; break;
...@@ -5289,6 +5314,9 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos, ...@@ -5289,6 +5314,9 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
case TCmode: mode = TFmode; break; case TCmode: mode = TFmode; break;
default: break; default: break;
} }
regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
regno++;
reg = gen_rtx_REG (mode, regno); reg = gen_rtx_REG (mode, regno);
XVECEXP (parms->ret, 0, parms->stack + parms->nregs) XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
= gen_rtx_EXPR_LIST (VOIDmode, reg, = gen_rtx_EXPR_LIST (VOIDmode, reg,
...@@ -5506,7 +5534,9 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode, ...@@ -5506,7 +5534,9 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
If no prototype is in scope fp values in register slots get passed 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. */ in two places, either fp regs and int regs or fp regs and memory. */
else if ((GET_MODE_CLASS (mode) == MODE_FLOAT else if ((GET_MODE_CLASS (mode) == MODE_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (mode) == MODE_VECTOR_INT
|| GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
&& SPARC_FP_REG_P (regno)) && SPARC_FP_REG_P (regno))
{ {
reg = gen_rtx_REG (mode, regno); reg = gen_rtx_REG (mode, regno);
...@@ -5607,20 +5637,20 @@ function_arg_partial_nregs (const struct sparc_args *cum, ...@@ -5607,20 +5637,20 @@ function_arg_partial_nregs (const struct sparc_args *cum,
if ((slotno + (mode == BLKmode if ((slotno + (mode == BLKmode
? ROUND_ADVANCE (int_size_in_bytes (type)) ? ROUND_ADVANCE (int_size_in_bytes (type))
: ROUND_ADVANCE (GET_MODE_SIZE (mode)))) : ROUND_ADVANCE (GET_MODE_SIZE (mode))))
> NPARM_REGS (SImode)) > SPARC_INT_ARG_MAX)
return NPARM_REGS (SImode) - slotno; return SPARC_INT_ARG_MAX - slotno;
return 0;
} }
else else
{ {
/* We are guaranteed by function_arg_pass_by_reference that the size
of the argument is not greater than 16 bytes, so we only need to
return 1 if the argument is partially passed in registers. */
if (type && AGGREGATE_TYPE_P (type)) if (type && AGGREGATE_TYPE_P (type))
{ {
int size = int_size_in_bytes (type); int size = int_size_in_bytes (type);
int align = TYPE_ALIGN (type);
if (align == 16) if (size > UNITS_PER_WORD
slotno += slotno & 1;
if (size > 8 && size <= 16
&& slotno == SPARC_INT_ARG_MAX - 1) && slotno == SPARC_INT_ARG_MAX - 1)
return 1; return 1;
} }
...@@ -5629,33 +5659,19 @@ function_arg_partial_nregs (const struct sparc_args *cum, ...@@ -5629,33 +5659,19 @@ function_arg_partial_nregs (const struct sparc_args *cum,
&& ! (TARGET_FPU && named))) && ! (TARGET_FPU && named)))
{ {
/* The complex types are passed as packed types. */ /* The complex types are passed as packed types. */
if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
return 0; && slotno == SPARC_INT_ARG_MAX - 1)
return 1;
if (GET_MODE_ALIGNMENT (mode) == 128)
{
slotno += slotno & 1;
/* ??? The mode needs 3 slots? */
if (slotno == SPARC_INT_ARG_MAX - 2)
return 1;
}
else
{
if (slotno == SPARC_INT_ARG_MAX - 1)
return 1;
}
} }
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
{ {
if (GET_MODE_ALIGNMENT (mode) == 128)
slotno += slotno & 1;
if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD) if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
> SPARC_FP_ARG_MAX) > SPARC_FP_ARG_MAX)
return 1; return 1;
} }
return 0;
} }
return 0;
} }
/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro. /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
...@@ -5672,18 +5688,23 @@ function_arg_pass_by_reference (const struct sparc_args *cum ATTRIBUTE_UNUSED, ...@@ -5672,18 +5688,23 @@ function_arg_pass_by_reference (const struct sparc_args *cum ATTRIBUTE_UNUSED,
if (TARGET_ARCH32) if (TARGET_ARCH32)
{ {
return ((type && AGGREGATE_TYPE_P (type)) return ((type && AGGREGATE_TYPE_P (type))
/* Extended ABI (as implemented by the Sun compiler) says
that all complex floats are passed in memory. */
|| mode == SCmode || 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); || GET_MODE_SIZE (mode) > 8);
} }
else else
{ {
return ((type && TREE_CODE (type) == ARRAY_TYPE) return ((type && TREE_CODE (type) == ARRAY_TYPE)
/* Consider complex values as aggregates, so care
for CTImode and TCmode. */
|| GET_MODE_SIZE (mode) > 16
|| (type || (type
&& AGGREGATE_TYPE_P (type) && AGGREGATE_TYPE_P (type)
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)); && (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. */
|| GET_MODE_SIZE (mode) > 16);
} }
} }
...@@ -5747,21 +5768,73 @@ function_arg_padding (enum machine_mode mode, tree type) ...@@ -5747,21 +5768,73 @@ function_arg_padding (enum machine_mode mode, tree type)
return DEFAULT_FUNCTION_ARG_PADDING (mode, type); return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
} }
/* Handle the TARGET_RETURN_IN_MEMORY target hook.
Specify whether to return the return value in memory. */
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'). */
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));
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'). */
return ((TYPE_MODE (type) == BLKmode
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32)
|| GET_MODE_SIZE (TYPE_MODE (type)) > 32);
}
/* Handle the TARGET_STRUCT_VALUE target hook.
Return where to find the structure return value address. */
static rtx
sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
{
if (TARGET_ARCH64)
return 0;
else
{
if (incoming)
return gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx,
STRUCT_VALUE_OFFSET));
else
return gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
STRUCT_VALUE_OFFSET));
}
}
/* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE macros. /* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE macros.
For v9, function return values are subject to the same rules as arguments, For v9, function return values are subject to the same rules as arguments,
except that up to 32-bytes may be returned in registers. */ except that up to 32 bytes may be returned in registers. */
rtx rtx
function_value (tree type, enum machine_mode mode, int incoming_p) function_value (tree type, enum machine_mode mode, int incoming_p)
{ {
/* Beware that the two values are swapped here wrt function_arg. */
int regbase = (incoming_p
? SPARC_OUTGOING_INT_ARG_FIRST
: SPARC_INCOMING_INT_ARG_FIRST);
int regno; int regno;
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,
...@@ -5788,7 +5861,7 @@ function_value (tree type, enum machine_mode mode, int incoming_p) ...@@ -5788,7 +5861,7 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
HOST_WIDE_INT bytes = int_size_in_bytes (type); HOST_WIDE_INT bytes = int_size_in_bytes (type);
if (bytes > 32) if (bytes > 32)
abort (); abort (); /* shouldn't get here */
mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0); mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
} }
...@@ -5797,10 +5870,10 @@ function_value (tree type, enum machine_mode mode, int incoming_p) ...@@ -5797,10 +5870,10 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
mode = word_mode; mode = word_mode;
} }
if (incoming_p) if (TARGET_FPU && (FLOAT_MODE_P (mode) || VECTOR_MODE_P (mode)))
regno = BASE_RETURN_VALUE_REG (mode); regno = SPARC_FP_ARG_FIRST;
else else
regno = BASE_OUTGOING_VALUE_REG (mode); regno = regbase;
return gen_rtx_REG (mode, regno); return gen_rtx_REG (mode, regno);
} }
...@@ -5816,7 +5889,7 @@ sparc_builtin_saveregs (void) ...@@ -5816,7 +5889,7 @@ sparc_builtin_saveregs (void)
rtx address; rtx address;
int regno; int regno;
for (regno = first_reg; regno < NPARM_REGS (word_mode); regno++) for (regno = first_reg; regno < SPARC_INT_ARG_MAX; regno++)
emit_move_insn (gen_rtx_MEM (word_mode, emit_move_insn (gen_rtx_MEM (word_mode,
gen_rtx_PLUS (Pmode, gen_rtx_PLUS (Pmode,
frame_pointer_rtx, frame_pointer_rtx,
...@@ -5824,7 +5897,7 @@ sparc_builtin_saveregs (void) ...@@ -5824,7 +5897,7 @@ sparc_builtin_saveregs (void)
+ (UNITS_PER_WORD + (UNITS_PER_WORD
* regno)))), * regno)))),
gen_rtx_REG (word_mode, gen_rtx_REG (word_mode,
BASE_INCOMING_ARG_REG (word_mode) + regno)); SPARC_INCOMING_INT_ARG_FIRST + regno));
address = gen_rtx_PLUS (Pmode, address = gen_rtx_PLUS (Pmode,
frame_pointer_rtx, frame_pointer_rtx,
...@@ -5834,7 +5907,7 @@ sparc_builtin_saveregs (void) ...@@ -5834,7 +5907,7 @@ sparc_builtin_saveregs (void)
return address; return address;
} }
/* Implement `va_start' for varargs and stdarg. */ /* Implement `va_start' for stdarg. */
void void
sparc_va_start (tree valist, rtx nextarg) sparc_va_start (tree valist, rtx nextarg)
...@@ -5843,7 +5916,7 @@ sparc_va_start (tree valist, rtx nextarg) ...@@ -5843,7 +5916,7 @@ sparc_va_start (tree valist, rtx nextarg)
std_expand_builtin_va_start (valist, nextarg); std_expand_builtin_va_start (valist, nextarg);
} }
/* Implement `va_arg'. */ /* Implement `va_arg' for stdarg. */
rtx rtx
sparc_va_arg (tree valist, tree type) sparc_va_arg (tree valist, tree type)
...@@ -5851,44 +5924,36 @@ sparc_va_arg (tree valist, tree type) ...@@ -5851,44 +5924,36 @@ sparc_va_arg (tree valist, tree type)
HOST_WIDE_INT size, rsize, align; HOST_WIDE_INT size, rsize, align;
tree addr, incr; tree addr, incr;
rtx addr_rtx; rtx addr_rtx;
int indirect = 0; bool indirect;
/* Round up sizeof(type) to a word. */ if (function_arg_pass_by_reference (0, TYPE_MODE (type), type, 0))
size = int_size_in_bytes (type);
rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
align = 0;
if (TARGET_ARCH64)
{ {
if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD) indirect = true;
align = 2 * UNITS_PER_WORD; size = rsize = UNITS_PER_WORD;
align = 0;
/* Consider complex values as aggregates, so care
for CTImode and TCmode. */
if ((unsigned HOST_WIDE_INT) size > 16)
{
indirect = 1;
size = rsize = UNITS_PER_WORD;
align = 0;
}
else if (AGGREGATE_TYPE_P (type))
{
/* SPARC-V9 ABI states that structures up to 16 bytes in size
are given whole slots as needed. */
if (size == 0)
size = rsize = UNITS_PER_WORD;
else
size = rsize;
}
} }
else else
{ {
if (AGGREGATE_TYPE_P (type) indirect = false;
|| TYPE_MODE (type) == SCmode size = int_size_in_bytes (type);
|| GET_MODE_SIZE (TYPE_MODE (type)) > 8) rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
align = 0;
if (TARGET_ARCH64)
{ {
indirect = 1; /* For SPARC64, objects requiring 16-byte alignment get it. */
size = rsize = UNITS_PER_WORD; if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
align = 2 * UNITS_PER_WORD;
/* SPARC-V9 ABI states that structures up to 16 bytes in size
are given whole slots as needed. */
if (AGGREGATE_TYPE_P (type))
{
if (size == 0)
size = rsize = UNITS_PER_WORD;
else
size = rsize;
}
} }
} }
...@@ -7259,6 +7324,7 @@ sparc_type_code (register tree type) ...@@ -7259,6 +7324,7 @@ sparc_type_code (register tree type)
existing front-ends. */ existing front-ends. */
return (qualifiers | 7); /* Who knows? */ return (qualifiers | 7); /* Who knows? */
case VECTOR_TYPE:
case CHAR_TYPE: /* GNU Pascal CHAR type. Not used in C. */ case CHAR_TYPE: /* GNU Pascal CHAR type. Not used in C. */
case BOOLEAN_TYPE: /* GNU Fortran BOOLEAN type. */ case BOOLEAN_TYPE: /* GNU Fortran BOOLEAN type. */
case FILE_TYPE: /* GNU Pascal FILE type. */ case FILE_TYPE: /* GNU Pascal FILE type. */
......
...@@ -1467,17 +1467,6 @@ extern char leaf_reg_remap[]; ...@@ -1467,17 +1467,6 @@ extern char leaf_reg_remap[];
/* Stack layout; function entry, exit and calling. */ /* Stack layout; function entry, exit and calling. */
/* Define the number of register that can hold parameters.
This macro is only used in other macro definitions below and in sparc.c.
MODE is the mode of the argument.
!v9: All args are passed in %o0-%o5.
v9: %o0-%o5 and %f0-%f31 are cumulatively used to pass values.
See the description in sparc.c. */
#define NPARM_REGS(MODE) \
(TARGET_ARCH64 \
? (GET_MODE_CLASS (MODE) == MODE_FLOAT ? 32 : 6) \
: 6)
/* Define this if pushing a word on the stack /* Define this if pushing a word on the stack
makes the stack pointer a smaller address. */ makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD #define STACK_GROWS_DOWNWARD
...@@ -1565,22 +1554,6 @@ extern char leaf_reg_remap[]; ...@@ -1565,22 +1554,6 @@ extern char leaf_reg_remap[];
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0
/* Some subroutine macros specific to this machine.
When !TARGET_FPU, put float return values in the general registers,
since we don't have any fp registers. */
#define BASE_RETURN_VALUE_REG(MODE) \
(TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 : 8)
#define BASE_OUTGOING_VALUE_REG(MODE) \
(TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 : 24)
#define BASE_PASSING_ARG_REG(MODE) \
(TARGET_ARCH64 && TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 : 8)
/* ??? FIXME -- seems wrong for v9 structure passing... */
#define BASE_INCOMING_ARG_REG(MODE) \
(TARGET_ARCH64 && TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 : 24)
/* Define this macro if the target machine has "register windows". This /* Define this macro if the target machine has "register windows". This
C expression returns the register number as seen by the called function C expression returns the register number as seen by the called function
corresponding to register number OUT as seen by the calling function. corresponding to register number OUT as seen by the calling function.
......
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