Commit 4fb4e4b8 by Doug Evans

sp64-elf.h (TARGET_DEFAULT): Delete MASK_STACK_BIAS.

	* sparc/sp64-elf.h (TARGET_DEFAULT): Delete MASK_STACK_BIAS.
	* sparc/sparc.h (PROMOTE_MODE): Promote small ints if arch64.
	(PROMOTE_FUNCTION_ARGS,PROMOTE_FUNCTION_RETURN): Define.
	(SPARC_FIRST_FP_REG, SPARC_FP_REG_P): New macros.
	(SPARC_{OUTGOING,INCOMING}_INT_ARG_FIRST): New macros.
	(SPARC_FP_ARG_FIRST): New macro.
	(CONDITIONAL_REGISTER_USAGE): All v9 fp regs are volatile now.
	(REG_ALLOC_ORDER,REG_LEAF_ALLOC_ORDER): Reorganize fp regs.
	(NPARM_REGS): There are 32 fp argument registers now.
	(FUNCTION_ARG_REGNO_P): Likewise.
	(FIRST_PARM_OFFSET): Update to new v9 abi.
	(REG_PARM_STACK_SPACE): Define for arch64.
	(enum sparc_arg_class): Delete.
	(sparc_arg_count,sparc_n_named_args): Delete.
	(struct sparc_args): Redefine and use for arch32 as well as arch64.
	(GET_SPARC_ARG_CLASS,ROUND_REG,ROUND_ADVANCE): Delete.
	(FUNCTION_ARG_ADVANCE): Rewrite.
	(FUNCTION_ARG,FUNCTION_INCOMING_ARG): Rewrite.
	(FUNCTION_ARG_{PARTIAL_NREGS,PASS_BY_REFERENCE}): Rewrite.
	(FUNCTION_ARG_CALLEE_COPIES): Delete.
	(FUNCTION_ARG_{PADDING,BOUNDARY}): Define.
	(STRICT_ARGUMENT_NAMING): Define.
	(doublemove_string): Declare.
	* sparc/sparc.c (sparc_arg_count,sparc_n_named_args): Delete.
	(single_move_string): Use GEN_INT, and HOST_WIDE_INT.
	(doublemove_string): New function.
	(output_move_quad): Clean up some of the arch64 support.
	(compute_frame_size): Add REG_PARM_STACK_SPACE if arch64.
	Don't add 8 bytes of reserved space if arch64.
	(sparc_builtin_saveregs): Combine arch32/arch64 versions.
	(init_cumulative_args): New function.
	(function_arg_slotno): New static function.
	(function_arg,function_arg_partial_nregs): New functions.
	(function_arg_{pass_by_reference,advance}): New functions.
	(function_arg_padding): New function.
First pass at updating to current v9 abi.

From-SVN: r15968
parent 941b1165
/* Definitions of target machine for GNU compiler, for SPARC64, ELF.
Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Doug Evans, dje@cygnus.com.
This file is part of GNU CC.
......@@ -19,7 +19,7 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* This is a v9 only compiler. -mv8 is not expected to work. If you want
/* This is a v9 only compiler. -mcpu=v8 is not expected to work. If you want
a v8/v9 compiler, this isn't the place to do it. */
#define SPARC_V9 1 /* See sparc.h. */
......@@ -35,13 +35,15 @@ Boston, MA 02111-1307, USA. */
#undef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (sparc64-elf)")
/* A v9 compiler with stack-bias, 32 bit integers and 64 bit pointers,
in a Medium/Anywhere code model environment. */
/* A v9 compiler without stack-bias, lp64 sizes,
in a Medium/Anywhere code model environment.
There is no stack bias as this configuration is intended for
embedded systems. */
#undef TARGET_DEFAULT
#define TARGET_DEFAULT \
(MASK_V9 + MASK_ARCH64 + MASK_PTR64 + MASK_HARD_QUAD \
+ MASK_STACK_BIAS + MASK_MEDANY + MASK_APP_REGS + MASK_EPILOGUE + MASK_FPU)
(MASK_V9 + MASK_ARCH64 + MASK_PTR64 + MASK_LONG64 + MASK_HARD_QUAD \
MASK_MEDANY + MASK_APP_REGS + MASK_EPILOGUE + MASK_FPU)
/* __svr4__ is used by the C library */
/* ??? __arch64__ is subject to change. */
......@@ -120,6 +122,7 @@ crtbegin.o%s \
/* The medium/anywhere code model practically requires us to put jump tables
in the text section as gcc is unable to distinguish LABEL_REF's of jump
tables from other label refs (when we need to). */
/* ??? Revisit this. */
#undef JUMP_TABLES_IN_TEXT_SECTION
#define JUMP_TABLES_IN_TEXT_SECTION
......
......@@ -64,17 +64,6 @@ static int actual_fsize;
rtx sparc_compare_op0, sparc_compare_op1;
/* Count of named arguments (v9 only).
??? INIT_CUMULATIVE_ARGS initializes these, and FUNCTION_ARG_ADVANCE
increments SPARC_ARG_COUNT. They are then used by
FUNCTION_ARG_CALLEE_COPIES to determine if the argument is really a named
argument or not. This hack is necessary because the NAMED argument to the
FUNCTION_ARG_XXX macros is not what it says it is: it does not include the
last named argument. */
int sparc_arg_count;
int sparc_n_named_args;
/* We may need an epilogue if we spill too many registers.
If this is non-zero, then we branch here for the epilogue. */
static rtx leaf_label;
......@@ -1647,7 +1636,12 @@ emit_move_sequence (operands, mode)
}
/* Return the best assembler insn template
for moving operands[1] into operands[0] as a fullword. */
for moving operands[1] into operands[0] as a 4 byte quantity.
This isn't intended to be very smart. It is up to the caller to
choose the best way to do things.
Note that OPERANDS may be modified to suit the returned string. */
char *
singlemove_string (operands)
......@@ -1673,7 +1667,7 @@ singlemove_string (operands)
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (r, i);
operands[1] = gen_rtx (CONST_INT, VOIDmode, i);
operands[1] = GEN_INT (i);
if (CONST_OK_FOR_LETTER_P (i, 'I'))
return "mov %1,%0";
......@@ -1685,10 +1679,11 @@ singlemove_string (operands)
else if (GET_CODE (operands[1]) == CONST_INT
&& ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
{
int i = INTVAL (operands[1]);
HOST_WIDE_INT i = INTVAL (operands[1]);
/* If all low order 10 bits are clear, then we only need a single
sethi insn to load the constant. */
/* FIXME: Use SETHI_P. */
if ((i & 0x000003FF) != 0)
return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
else
......@@ -1698,6 +1693,58 @@ singlemove_string (operands)
return "mov %1,%0";
}
/* Return the best assembler insn template
for moving operands[1] into operands[0] as an 8 byte quantity.
This isn't intended to be very smart. It is up to the caller to
choose the best way to do things.
Note that OPERANDS may be modified to suit the returned string. */
char *
doublemove_string (operands)
rtx *operands;
{
rtx op0 = operands[0], op1 = operands[1];
if (GET_CODE (op0) == MEM)
{
if (GET_CODE (op1) == REG)
{
if (FP_REG_P (op1))
return "std %1,%0";
return TARGET_ARCH64 ? "stx %1,%0" : "std %1,%0";
}
if (TARGET_ARCH64
&& (op1 == const0_rtx
|| (GET_MODE (op1) != VOIDmode
&& op1 == CONST0_RTX (GET_MODE (op1)))))
return "stx %r1,%0";
abort ();
}
else if (GET_CODE (op1) == MEM)
{
if (GET_CODE (op0) != REG)
abort ();
if (FP_REG_P (op0))
return "ldd %1,%0";
return TARGET_ARCH64 ? "ldx %1,%0" : "ldd %1,%0";
}
else if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
/* ??? Unfinished, and maybe not needed. */
abort ();
}
else if (GET_CODE (operands[1]) == CONST_INT
&& ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
{
/* ??? Unfinished, and maybe not needed. */
abort ();
}
/* Operand 1 must be a register, or a 'I' type CONST_INT. */
return "mov %1,%0";
}
/* Return non-zero if it is OK to assume that the given memory operand is
aligned at least to a 8-byte boundary. This should only be called
for memory accesses whose size is 8 bytes or larger. */
......@@ -2038,19 +2085,27 @@ output_move_quad (operands)
if (optype0 == REGOP)
{
wordpart[0][0] = gen_rtx (REG, SImode, REGNO (op0) + 0);
wordpart[1][0] = gen_rtx (REG, SImode, REGNO (op0) + 1);
wordpart[2][0] = gen_rtx (REG, SImode, REGNO (op0) + 2);
wordpart[3][0] = gen_rtx (REG, SImode, REGNO (op0) + 3);
wordpart[0][0] = gen_rtx (REG, word_mode, REGNO (op0) + 0);
wordpart[1][0] = gen_rtx (REG, word_mode, REGNO (op0) + 1);
if (TARGET_ARCH32)
{
wordpart[2][0] = gen_rtx (REG, word_mode, REGNO (op0) + 2);
wordpart[3][0] = gen_rtx (REG, word_mode, REGNO (op0) + 3);
}
}
else if (optype0 == OFFSOP)
{
wordpart[0][0] = adj_offsettable_operand (op0, 0);
if (TARGET_ARCH32)
{
wordpart[1][0] = adj_offsettable_operand (op0, 4);
wordpart[2][0] = adj_offsettable_operand (op0, 8);
wordpart[3][0] = adj_offsettable_operand (op0, 12);
}
else
wordpart[1][0] = adj_offsettable_operand (op0, 8);
}
else
{
wordpart[0][0] = op0;
wordpart[1][0] = op0;
......@@ -2060,18 +2115,26 @@ output_move_quad (operands)
if (optype1 == REGOP)
{
wordpart[0][1] = gen_rtx (REG, SImode, REGNO (op1) + 0);
wordpart[1][1] = gen_rtx (REG, SImode, REGNO (op1) + 1);
wordpart[2][1] = gen_rtx (REG, SImode, REGNO (op1) + 2);
wordpart[3][1] = gen_rtx (REG, SImode, REGNO (op1) + 3);
wordpart[0][1] = gen_rtx (REG, word_mode, REGNO (op1) + 0);
wordpart[1][1] = gen_rtx (REG, word_mode, REGNO (op1) + 1);
if (TARGET_ARCH32)
{
wordpart[2][1] = gen_rtx (REG, word_mode, REGNO (op1) + 2);
wordpart[3][1] = gen_rtx (REG, word_mode, REGNO (op1) + 3);
}
}
else if (optype1 == OFFSOP)
{
wordpart[0][1] = adj_offsettable_operand (op1, 0);
if (TARGET_ARCH32)
{
wordpart[1][1] = adj_offsettable_operand (op1, 4);
wordpart[2][1] = adj_offsettable_operand (op1, 8);
wordpart[3][1] = adj_offsettable_operand (op1, 12);
}
else
wordpart[1][1] = adj_offsettable_operand (op1, 8);
}
else if (optype1 == CNSTOP)
{
REAL_VALUE_TYPE r;
......@@ -2117,12 +2180,13 @@ output_move_quad (operands)
/* If this is a floating point register higher than %f31,
then we *must* use an aligned load, since `ld' will not accept
the register number. */
|| (TARGET_V9 && REGNO (reg) >= 64))
|| (TARGET_V9 && REGNO (reg) >= SPARC_FIRST_V9_FP_REG))
{
if (TARGET_V9 && FP_REG_P (reg) && TARGET_HARD_QUAD)
{
if ((REGNO (reg) & 3) != 0)
abort ();
/* ??? Can `mem' have an inappropriate alignment here? */
return (mem == op1 ? "ldq %1,%0" : "stq %1,%0");
}
operands[2] = adj_offsettable_operand (mem, 8);
......@@ -2137,7 +2201,9 @@ output_move_quad (operands)
/* If the first move would clobber the source of the second one,
do them in the other order. */
/* Overlapping registers. */
/* Overlapping registers? */
if (TARGET_ARCH32)
{
if (optype0 == REGOP && optype1 == REGOP
&& (REGNO (op0) == REGNO (wordpart[1][3])
|| REGNO (op0) == REGNO (wordpart[1][2])
......@@ -2150,8 +2216,21 @@ output_move_quad (operands)
/* Do the second word. */
output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
/* Do lowest-numbered word. */
return singlemove_string (wordpart[0]);
output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]);
return "";
}
}
else /* TARGET_ARCH64 */
{
if (optype0 == REGOP && optype1 == REGOP
&& REGNO (op0) == REGNO (wordpart[1][1]))
{
output_asm_insn ("mov %1,%0", wordpart[1]);
output_asm_insn ("mov %1,%0", wordpart[0]);
return "";
}
}
/* Loading into a register which overlaps a register used in the address. */
if (optype0 == REGOP && optype1 != REGOP
&& reg_overlap_mentioned_p (op0, op1))
......@@ -2164,8 +2243,10 @@ output_move_quad (operands)
abort ();
}
/* Normal case: move the four words in lowest to highest address order. */
/* Normal case: move the words in lowest to highest address order. */
if (TARGET_ARCH32)
{
output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]);
/* Make any unoffsettable addresses point at the second word. */
......@@ -2200,6 +2281,26 @@ output_move_quad (operands)
output_asm_insn ("add %0,-0xc,%0", &addreg0);
if (addreg1)
output_asm_insn ("add %0,-0xc,%0", &addreg1);
}
else /* TARGET_ARCH64 */
{
output_asm_insn (doublemove_string (wordpart[0]), wordpart[0]);
/* Make any unoffsettable addresses point at the second word. */
if (addreg0)
output_asm_insn ("add %0,0x8,%0", &addreg0);
if (addreg1)
output_asm_insn ("add %0,0x8,%0", &addreg1);
/* Do the second word. */
output_asm_insn (doublemove_string (wordpart[1]), wordpart[1]);
/* Undo the adds we just did. */
if (addreg0)
output_asm_insn ("add %0,-0x8,%0", &addreg0);
if (addreg1)
output_asm_insn ("add %0,-0x8,%0", &addreg1);
}
return "";
}
......@@ -3056,10 +3157,7 @@ compute_frame_size (size, leaf_function)
{
int n_regs = 0, i;
int outgoing_args_size = (current_function_outgoing_args_size
#if ! SPARC_ARCH64
+ REG_PARM_STACK_SPACE (current_function_decl)
#endif
);
+ REG_PARM_STACK_SPACE (current_function_decl));
if (TARGET_EPILOGUE)
{
......@@ -3106,10 +3204,9 @@ compute_frame_size (size, leaf_function)
/* Make sure nothing can clobber our register windows.
If a SAVE must be done, or there is a stack-local variable,
the register window area must be allocated.
??? For v9 we need an additional 8 bytes of reserved space, apparently
it's needed by v8 as well. */
??? For v8 we apparently need an additional 8 bytes of reserved space. */
if (leaf_function == 0 || size > 0)
actual_fsize += (16 * UNITS_PER_WORD) + 8;
actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8);
return SPARC_STACK_ALIGN (actual_fsize);
}
......@@ -3406,104 +3503,670 @@ output_function_epilogue (file, size, leaf_function)
}
}
/* Do what is necessary for `va_start'. The argument is ignored.
!v9: We look at the current function to determine if stdarg or varargs
is used and return the address of the first unnamed parameter.
v9: We save the argument integer and floating point regs in a buffer, and
return the address of this buffer. The rest is handled in va-sparc.h. */
/* ??? This is currently conditioned on SPARC_ARCH64 because
current_function_args_info is different in each compiler. */
/* Functions for handling argument passing.
For v8 the first six args are normally in registers and the rest are
pushed. Any arg that starts within the first 6 words is at least
partially passed in a register unless its data type forbids.
For v9, 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
first 16 fp args (depending on size) are passed in regs.
Slot Stack Integral Float Float in structure Double Long Double
---- ----- -------- ----- ------------------ ------ -----------
15 [SP+248] %f31 %f30,%f31 %d30
14 [SP+240] %f29 %f28,%f29 %d28 %q28
13 [SP+232] %f27 %f26,%f27 %d26
12 [SP+224] %f25 %f24,%f25 %d24 %q24
11 [SP+216] %f23 %f22,%f23 %d22
10 [SP+208] %f21 %f20,%f21 %d20 %q20
9 [SP+200] %f19 %f18,%f19 %d18
8 [SP+192] %f17 %f16,%f17 %d16 %q16
7 [SP+184] %f15 %f14,%f15 %d14
6 [SP+176] %f13 %f12,%f13 %d12 %q12
5 [SP+168] %o5 %f11 %f10,%f11 %d10
4 [SP+160] %o4 %f9 %f8,%f9 %d8 %q8
3 [SP+152] %o3 %f7 %f6,%f7 %d6
2 [SP+144] %o2 %f5 %f4,%f5 %d4 %q4
1 [SP+136] %o1 %f3 %f2,%f3 %d2
0 [SP+128] %o0 %f1 %f0,%f1 %d0 %q0
Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise.
Integral arguments are always passed as 64 bit quantities appropriately
extended.
Passing of floating point values is handled as follows.
If a prototype is in scope:
If the value is in a named argument (i.e. not a stdarg function or a
value not part of the `...') then the value is passed in the appropriate
fp reg.
If the value is part of the `...' and is passed in one of the first 6
slots then the value is passed in the appropriate int reg.
If the value is part of the `...' and is not passed in one of the first 6
slots then the value is passed in memory.
If a prototype is not in scope:
If the value is one of the first 6 arguments the value is passed in the
appropriate integer reg and the appropriate fp reg.
If the value is not one of the first 6 arguments the value is passed in
the appropriate fp reg and in memory.
*/
/* Maximum number of int regs for args. */
#define SPARC_INT_ARG_MAX 6
/* Maximum number of fp regs for args. */
#define SPARC_FP_ARG_MAX 16
#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* Handle the INIT_CUMULATIVE_ARGS macro.
Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0. */
#if SPARC_ARCH64
void
init_cumulative_args (cum, fntype, libname, indirect)
CUMULATIVE_ARGS *cum;
tree fntype, libname;
int indirect;
{
cum->words = 0;
cum->prototype_p = fntype && TYPE_ARG_TYPES (fntype);
cum->libcall_p = fntype == 0;
}
/* Compute the slot number to pass an argument in.
Returns the slot number or -1 if passing on the stack.
CUM is a variable of type CUMULATIVE_ARGS which gives info about
the preceding args and about the function being called.
MODE is the argument's machine mode.
TYPE is the data type of the argument (as a tree).
This is null for libcalls where that information may
not be available.
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis).
INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.
*PREGNO records the register number to use if scalar type.
*PPADDING records the amount of padding needed in words. */
static int
function_arg_slotno (cum, mode, type, named, incoming_p, pregno, ppadding)
const CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
int incoming_p;
int *pregno;
int *ppadding;
{
int regbase = (incoming_p
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno = cum->words;
int regno;
*ppadding = 0;
if (type != 0 && TREE_ADDRESSABLE (type))
return -1;
if (TARGET_ARCH32
&& type != 0 && mode == BLKmode
&& TYPE_ALIGN (type) % PARM_BOUNDARY != 0)
return -1;
switch (mode)
{
case VOIDmode :
/* MODE is VOIDmode when generating the actual call.
See emit_call_1. */
return -1;
case QImode : case CQImode :
case HImode : case CHImode :
case SImode : case CSImode :
case DImode : case CDImode :
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
break;
case SFmode : case SCmode :
case DFmode : case DCmode :
case TFmode : case TCmode :
if (TARGET_ARCH32)
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
}
else
{
if ((mode == TFmode || mode == TCmode)
&& (slotno & 1) != 0)
slotno++, *ppadding = 1;
if (TARGET_FPU && named)
{
if (slotno >= SPARC_FP_ARG_MAX)
return 0;
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. */
if (TARGET_ARCH64)
{
if (type && TYPE_ALIGN (type) == 128 && (slotno & 1) != 0)
slotno++, *ppadding = 1;
}
if (TARGET_ARCH32
|| type && TREE_CODE (type) == UNION_TYPE)
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
}
else
{
tree field;
int intregs_p = 0, fpregs_p = 0;
/* The ABI obviously doesn't specify how packed
structures are passed. These are defined to be passed
in int regs if possible, otherwise memory. */
int packed_p = 0;
/* First see what kinds of registers we need. */
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
if (TREE_CODE (field) == FIELD_DECL)
{
if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
&& TARGET_FPU)
fpregs_p = 1;
else
intregs_p = 1;
if (DECL_PACKED (field))
packed_p = 1;
}
}
if (packed_p || !named)
fpregs_p = 0, intregs_p = 1;
/* If all arg slots are filled, then must pass on stack. */
if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
return -1;
/* If there are only int args and all int arg slots are filled,
then must pass on stack. */
if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
return -1;
/* Note that even if all int arg slots are filled, fp members may
still be passed in regs if such regs are available.
*PREGNO isn't set because there may be more than one, it's up
to the caller to compute them. */
return slotno;
}
break;
default :
abort ();
}
*pregno = regno;
return slotno;
}
/* Handle the FUNCTION_ARG macro.
Determine where to put an argument to a function.
Value is zero to push the argument on the stack,
or a hard register in which to store the argument.
CUM is a variable of type CUMULATIVE_ARGS which gives info about
the preceding args and about the function being called.
MODE is the argument's machine mode.
TYPE is the data type of the argument (as a tree).
This is null for libcalls where that information may
not be available.
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis).
INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG. */
rtx
sparc_builtin_saveregs (arglist)
tree arglist;
function_arg (cum, mode, type, named, incoming_p)
const CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
int incoming_p;
{
tree fntype = TREE_TYPE (current_function_decl);
/* First unnamed integer register. */
int first_intreg = current_function_args_info.arg_count[(int) SPARC_ARG_INT];
/* Number of integer registers we need to save. */
int n_intregs = MAX (0, NPARM_REGS (SImode) - first_intreg);
/* First unnamed SFmode float reg (no, you can't pass SFmode floats as
unnamed arguments, we just number them that way). We must round up to
the next double word float reg - that is the first one to save. */
int first_floatreg = current_function_args_info.arg_count[(int) SPARC_ARG_FLOAT] + 1 & ~1;
/* Number of SFmode float regs to save. */
int n_floatregs = MAX (0, NPARM_REGS (SFmode) - first_floatreg);
int ptrsize = GET_MODE_SIZE (Pmode);
rtx valist, regbuf, fpregs;
int bufsize, adjust, regno;
/* Allocate block of memory for the regs.
We only allocate as much as we need, but we must ensure quadword float
regs are stored with the appropriate alignment. */
/* ??? If n_intregs + n_floatregs == 0, should we allocate at least 1 byte?
Or can assign_stack_local accept a 0 SIZE argument? */
bufsize = (n_intregs * UNITS_PER_WORD) +
(TARGET_FPU ? (n_floatregs * (UNITS_PER_WORD / 2)) : 0);
/* Add space in front of the int regs to ensure proper alignment of quadword
fp regs. We must add the space in front because va_start assumes this. */
if (TARGET_FPU && n_floatregs >= 4)
adjust = ((n_intregs + first_floatreg / 2) % 2) * UNITS_PER_WORD;
else
adjust = 0;
regbuf = assign_stack_local (BLKmode, bufsize + adjust,
GET_MODE_BITSIZE (TFmode));
regbuf = gen_rtx (MEM, BLKmode, plus_constant (XEXP (regbuf, 0), adjust));
MEM_IN_STRUCT_P (regbuf) = 1;
/* Save int args.
This is optimized to only save the regs that are necessary. Explicitly
named args need not be saved. */
if (n_intregs > 0)
move_block_from_reg (BASE_INCOMING_ARG_REG (SImode) + first_intreg,
regbuf, n_intregs, n_intregs * UNITS_PER_WORD);
if (TARGET_FPU)
{
/* Save float args.
This is optimized to only save the regs that are necessary.
Explicitly named args need not be saved.
We explicitly build a pointer to the buffer because it halves the insn
count when not optimizing (otherwise the pointer is built for each reg
saved). */
fpregs = gen_reg_rtx (Pmode);
emit_move_insn (fpregs, plus_constant (XEXP (regbuf, 0),
n_intregs * UNITS_PER_WORD));
for (regno = first_floatreg; regno < NPARM_REGS (SFmode); regno += 2)
emit_move_insn (gen_rtx (MEM, DFmode,
plus_constant (fpregs,
GET_MODE_SIZE (SFmode)
* (regno - first_floatreg))),
gen_rtx (REG, DFmode,
BASE_INCOMING_ARG_REG (DFmode) + regno));
}
if (flag_check_memory_usage)
{
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, regbuf,
ptr_mode, GEN_INT (n_intregs * UNITS_PER_WORD),
TYPE_MODE (sizetype), GEN_INT (MEMORY_USE_RW), QImode);
int regbase = (incoming_p
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno, regno, padding;
rtx reg;
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
fpregs, ptr_mode,
GEN_INT (UNITS_PER_WORD
* GET_MODE_SIZE (SFmode)
* (NPARM_REGS (SFmode) - first_floatreg)),
TYPE_MODE (sizetype), GEN_INT (MEMORY_USE_RW), QImode);
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;
}
/* Return the address of the regbuf. */
/* 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 ((GET_MODE_CLASS (mode) == MODE_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
&& SPARC_FP_REG_P (regno))
{
reg = gen_rtx (REG, mode, regno);
if (cum->prototype_p || cum->libcall_p)
{
/* "* 2" because fp reg numbers are recorded in 4 byte
quantities. */
/* ??? This will cause the value to be passed in the fp reg and
in the stack. When a prototype exists we want to pass the
value in the reg but reserve space on the stack. That's an
optimization, and is defered [for a bit]. */
if ((regno - SPARC_FP_ARG_FIRST) >= SPARC_INT_ARG_MAX * 2)
return gen_rtx (PARALLEL, mode,
gen_rtvec (2,
gen_rtx (EXPR_LIST, VOIDmode,
NULL_RTX, const0_rtx),
gen_rtx (EXPR_LIST, VOIDmode,
reg, const0_rtx)));
else
return reg;
}
else
{
if ((regno - SPARC_FP_ARG_FIRST) < SPARC_INT_ARG_MAX * 2)
{
int regbase = (incoming_p
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int intreg = regbase + (regno - SPARC_FP_ARG_FIRST) / 2;
return gen_rtx (PARALLEL, mode,
gen_rtvec (2,
gen_rtx (EXPR_LIST, VOIDmode,
gen_rtx (REG, mode, intreg),
const0_rtx),
gen_rtx (EXPR_LIST, VOIDmode,
reg, const0_rtx)));
}
else
return gen_rtx (PARALLEL, mode,
gen_rtvec (2,
gen_rtx (EXPR_LIST, VOIDmode,
NULL_RTX, const0_rtx),
gen_rtx (EXPR_LIST, VOIDmode,
reg, const0_rtx)));
}
}
else 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. */
tree field;
rtx ret;
int i;
int nregs;
/* Starting bit position of a sequence of integer fields, counted from
msb of left most byte, -1 if last field wasn't an int. */
/* ??? This isn't entirely necessary, some simplification
may be possible. */
int start_int_bitpos;
/* Current bitpos in struct, counted from msb of left most byte. */
int bitpos, this_slotno;
/* The ABI obviously doesn't specify how packed
structures are passed. These are defined to be passed
in int regs if possible, otherwise memory. */
int packed_p = 0;
if (int_size_in_bytes (type) > 16)
abort (); /* shouldn't get here */
/* We need to compute how many registers are needed so we can allocate
the PARALLEL but before we can do that we need to know whether there
are any packed fields. If there are, int regs are used regardless of
whether there are fp values present. */
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
if (TREE_CODE (field) == FIELD_DECL
&& DECL_PACKED (field))
{
packed_p = 1;
break;
}
}
/* Compute how many registers we need. */
nregs = 0;
start_int_bitpos = -1;
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
this_slotno = slotno + bitpos / BITS_PER_WORD;
if (TREE_CODE (field) == FIELD_DECL)
{
if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
&& TARGET_FPU
&& ! packed_p
&& named)
{
/* There's no need to check this_slotno < SPARC_FP_ARG MAX.
If it wasn't true we wouldn't be here. */
nregs++;
start_int_bitpos = -1;
}
else if (this_slotno < SPARC_INT_ARG_MAX)
{
if (start_int_bitpos == -1)
{
nregs++;
start_int_bitpos = bitpos;
}
else
{
if (bitpos % BITS_PER_WORD == 0)
nregs++;
}
}
}
}
if (nregs == 0)
abort ();
ret = gen_rtx (PARALLEL, BLKmode, rtvec_alloc (nregs + 1));
/* ??? This causes the entire struct to be passed in memory.
This isn't necessary, but is left for later. */
XVECEXP (ret, 0, 0) = gen_rtx (EXPR_LIST, VOIDmode, NULL_RTX,
const0_rtx);
/* Fill in the entries. */
start_int_bitpos = -1;
for (i = 1, field = TYPE_FIELDS (type);
field;
field = TREE_CHAIN (field))
{
bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
this_slotno = slotno + bitpos / BITS_PER_WORD;
if (TREE_CODE (field) == FIELD_DECL)
{
if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
&& TARGET_FPU
&& ! packed_p
&& named)
{
reg = gen_rtx (REG, DECL_MODE (field),
(SPARC_FP_ARG_FIRST + this_slotno * 2
+ (DECL_MODE (field) == SFmode
&& (bitpos & 32) != 0)));
XVECEXP (ret, 0, i) = gen_rtx (EXPR_LIST, VOIDmode, reg,
GEN_INT (bitpos / BITS_PER_UNIT));
i++;
start_int_bitpos = -1;
}
else
{
if (this_slotno < SPARC_INT_ARG_MAX
&& (start_int_bitpos == -1
|| bitpos % BITS_PER_WORD == 0))
{
enum machine_mode mode;
/* If this is the trailing part of a word, only load
that much into the register. Otherwise load the
whole register. Note that in the latter case we may
pick up unwanted bits. It's not a problem at the
moment but may wish to revisit. */
if (bitpos % BITS_PER_WORD != 0)
mode = mode_for_size (BITS_PER_WORD - bitpos % BITS_PER_WORD,
MODE_INT, 0);
else
mode = word_mode;
regno = regbase + this_slotno;
reg = gen_rtx (REG, mode, regno);
XVECEXP (ret, 0, i) = gen_rtx (EXPR_LIST, VOIDmode, reg,
GEN_INT (bitpos / BITS_PER_UNIT));
i++;
if (start_int_bitpos == -1)
start_int_bitpos = bitpos;
}
}
}
}
if (i != nregs + 1)
abort ();
return ret;
}
else if (type && TREE_CODE (type) == UNION_TYPE)
{
enum machine_mode mode;
int bytes = int_size_in_bytes (type);
return XEXP (regbuf, 0);
if (bytes > 16)
abort ();
mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
reg = gen_rtx (REG, mode, regno);
}
else
{
/* Scalar or complex int. */
reg = gen_rtx (REG, mode, regno);
}
return reg;
}
#else /* ! SPARC_ARCH64 */
/* Handle the FUNCTION_ARG_PARTIAL_NREGS macro.
For an arg passed partly in registers and partly in memory,
this is the number of registers used.
For args passed entirely in registers or entirely in memory, zero.
Any arg that starts in the first 6 regs but won't entirely fit in them
needs partial registers on v8. On v9, structures with integer
values in arg slots 5,6 will be passed in %o5 and SP+176, and complex fp
values that begin in the last fp reg [where "last fp reg" varies with the
mode] will be split between that reg and memory. */
int
function_arg_partial_nregs (cum, mode, type, named)
const CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
int slotno, regno, padding;
/* We pass 0 for incoming_p here, it doesn't matter. */
slotno = function_arg_slotno (cum, mode, type, named, 0, &regno, &padding);
if (slotno == -1)
return 0;
if (TARGET_ARCH32)
{
if ((slotno + (mode == BLKmode
? ROUND_ADVANCE (int_size_in_bytes (type))
: ROUND_ADVANCE (GET_MODE_SIZE (mode))))
> NPARM_REGS (SImode))
return NPARM_REGS (SImode) - slotno;
return 0;
}
else
{
if (type && AGGREGATE_TYPE_P (type))
{
int size = int_size_in_bytes (type);
int align = TYPE_ALIGN (type);
if (align == 16)
slotno += slotno & 1;
if (size > 8 && size <= 16
&& slotno == SPARC_INT_ARG_MAX - 1)
return 1;
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
|| (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
&& ! TARGET_FPU))
{
if (GET_MODE_ALIGNMENT (mode) == 128)
{
slotno += slotno & 1;
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)
{
if (GET_MODE_ALIGNMENT (mode) == 128)
slotno += slotno & 1;
if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
> SPARC_FP_ARG_MAX)
return 1;
}
return 0;
}
}
/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
!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. */
int
function_arg_pass_by_reference (cum, mode, type, named)
const CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
if (TARGET_ARCH32)
{
return (type && AGGREGATE_TYPE_P (type)
|| mode == TFmode || mode == TCmode);
}
else
{
return ((type && TREE_CODE (type) == ARRAY_TYPE)
|| (type && AGGREGATE_TYPE_P (type)
&& int_size_in_bytes (type) > 16));
}
}
/* Handle the FUNCTION_ARG_ADVANCE macro.
Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
TYPE is null for libcalls where that information may not be available. */
void
function_arg_advance (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
int slotno, regno, padding;
/* We pass 0 for incoming_p here, it doesn't matter. */
slotno = function_arg_slotno (cum, mode, type, named, 0, &regno, &padding);
/* If register required leading padding, add it. */
if (slotno != -1)
cum->words += padding;
if (TARGET_ARCH32)
{
cum->words += (mode != BLKmode
? ROUND_ADVANCE (GET_MODE_SIZE (mode))
: ROUND_ADVANCE (int_size_in_bytes (type)));
}
else
{
if (type && AGGREGATE_TYPE_P (type))
{
int size = int_size_in_bytes (type);
if (size <= 8)
++cum->words;
else if (size <= 16)
cum->words += 2;
else /* passed by reference */
++cum->words;
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
{
cum->words += 2;
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
{
cum->words += GET_MODE_SIZE (mode) / UNITS_PER_WORD;
}
else
{
cum->words += (mode != BLKmode
? ROUND_ADVANCE (GET_MODE_SIZE (mode))
: ROUND_ADVANCE (int_size_in_bytes (type)));
}
}
}
/* Handle the FUNCTION_ARG_PADDING macro.
For the 64 bit ABI structs are always stored left shifted in their
argument slot. */
enum direction
function_arg_padding (mode, type)
enum machine_mode mode;
tree type;
{
if (TARGET_ARCH64 && type && TREE_CODE (type) == RECORD_TYPE)
{
return upward;
}
/* This is the default definition. */
return (! BYTES_BIG_ENDIAN
? upward
: ((mode == BLKmode
? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
&& int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT))
: GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
? downward : upward));
}
/* Do what is necessary for `va_start'. The argument is ignored.
We look at the current function to determine if stdarg or varargs
is used and return the address of the first unnamed parameter. */
rtx
sparc_builtin_saveregs (arglist)
......@@ -3513,42 +4176,35 @@ sparc_builtin_saveregs (arglist)
int stdarg = (TYPE_ARG_TYPES (fntype) != 0
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
!= void_type_node));
int first_reg = current_function_args_info;
int first_reg = current_function_args_info.words;
rtx address;
int regno;
#if 0 /* This code seemed to have no effect except to make
varargs not work right when va_list wasn't the first arg. */
if (! stdarg)
first_reg = 0;
#endif
for (regno = first_reg; regno < NPARM_REGS (SImode); regno++)
for (regno = first_reg; regno < NPARM_REGS (word_mode); regno++)
emit_move_insn (gen_rtx (MEM, word_mode,
gen_rtx (PLUS, Pmode,
frame_pointer_rtx,
GEN_INT (STACK_POINTER_OFFSET
+ UNITS_PER_WORD * regno))),
gen_rtx (REG, word_mode, BASE_INCOMING_ARG_REG (word_mode)
+ regno));
gen_rtx (REG, word_mode,
BASE_INCOMING_ARG_REG (word_mode) + regno));
address = gen_rtx (PLUS, Pmode,
frame_pointer_rtx,
GEN_INT (STACK_POINTER_OFFSET
+ UNITS_PER_WORD * first_reg));
if (flag_check_memory_usage)
if (flag_check_memory_usage
&& first_reg < NPARM_REGS (word_mode))
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
address, ptr_mode,
GEN_INT (UNITS_PER_WORD
* (NPARM_REGS (SImode) - first_reg)),
* (NPARM_REGS (word_mode) - first_reg)),
TYPE_MODE (sizetype), GEN_INT (MEMORY_USE_RW), QImode);
return address;
}
#endif /* ! SPARC_ARCH64 */
/* Return the string to output a conditional branch to LABEL, which is
the operand number of the label. OP is the conditional expression.
XEXP (OP, 0) is assumed to be a condition code register (integer or
......
......@@ -612,6 +612,34 @@ extern int sparc_align_funcs;
See also the macro `Pmode' defined below. */
#define POINTER_SIZE (TARGET_PTR64 ? 64 : 32)
/* A macro to update MODE and UNSIGNEDP when an object whose type
is TYPE and which has the specified mode and signedness is to be
stored in a register. This macro is only called when TYPE is a
scalar type. */
#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
if (TARGET_ARCH64 \
&& GET_MODE_CLASS (MODE) == MODE_INT \
&& GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \
{ \
(MODE) = DImode; \
}
/* Define this macro if the promotion described by PROMOTE_MODE
should also be done for outgoing function arguments. */
/* This is only needed for TARGET_ARCH64, but since PROMOTE_MODE is a no-op
for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime test
for this value. */
#define PROMOTE_FUNCTION_ARGS
/* Define this macro if the promotion described by PROMOTE_MODE
should also be done for the return value of functions.
If this macro is defined, FUNCTION_VALUE must perform the same
promotions done by PROMOTE_MODE. */
/* This is only needed for TARGET_ARCH64, but since PROMOTE_MODE is a no-op
for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime test
for this value. */
#define PROMOTE_FUNCTION_RETURN
/* Allocation boundary (in *bits*) for storing arguments in argument list. */
#define PARM_BOUNDARY (TARGET_ARCH64 ? 64 : 32)
......@@ -732,6 +760,7 @@ extern int sparc_align_funcs;
#define FIRST_PSEUDO_REGISTER 101
#define SPARC_FIRST_FP_REG 32
/* Additional V9 fp regs. */
#define SPARC_FIRST_V9_FP_REG 64
#define SPARC_LAST_V9_FP_REG 95
......@@ -743,16 +772,28 @@ extern int sparc_align_funcs;
/* Integer CC reg. We don't distinguish %icc from %xcc. */
#define SPARC_ICC_REG 100
/* Nonzero if REGNO is an fp reg. */
#define SPARC_FP_REG_P(REGNO) \
((REGNO) >= SPARC_FIRST_FP_REG && (REGNO) <= SPARC_LAST_V9_FP_REG)
/* Argument passing regs. */
#define SPARC_OUTGOING_INT_ARG_FIRST 8
#define SPARC_INCOMING_INT_ARG_FIRST 24
#define SPARC_FP_ARG_FIRST 32
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
On non-v9 systems:
g1 is free to use as temporary.
g2-g4 are reserved for applications. Gcc normally uses them as
temporaries, but this can be disabled via the -mno-app-regs option.
g5 through g7 are reserved for the operating system.
On v9 systems:
g1 and g5 are free to use as temporaries.
g2-g4 are reserved for applications. Gcc normally uses them as
g1,g4,g5 are free to use as temporaries.
g1,g5 are free to use between calls if call is to external function via PLT.
g2-g3 are reserved for applications. Gcc normally uses them as
temporaries, but this can be disabled via the -mno-app-regs option.
g6-g7 are reserved for the operating system.
??? Register 1 is used as a temporary by the 64 bit sethi pattern, so must
......@@ -819,11 +860,7 @@ do \
} \
if (SPARC_ARCH64) \
{ \
int regno; \
fixed_regs[1] = 1; \
/* ??? We need to scan argv for -fcall-used-. */ \
for (regno = 48; regno < 80; regno++) \
call_used_regs[regno] = 0; \
} \
if (! TARGET_V9) \
{ \
......@@ -916,11 +953,12 @@ extern int sparc_mode_class[];
/* Register to use for pushing function arguments. */
#define STACK_POINTER_REGNUM 14
/* Actual top-of-stack address is 92/136 greater than the contents of the
/* Actual top-of-stack address is 92/176 greater than the contents of the
stack pointer register for !v9/v9. That is:
- !v9: 64 bytes for the in and local registers, 4 bytes for structure return
address, and 24 bytes for the 6 register parameters.
- v9: 128 bytes for the in and local registers + 8 bytes reserved. */
address, and 6*4 bytes for the 6 register parameters.
- v9: 128 bytes for the in and local registers + 6*8 bytes for the integer
parameter regs. */
#define STACK_POINTER_OFFSET FIRST_PARM_OFFSET(0)
/* The stack bias (amount by which the hardware register is offset by). */
......@@ -978,11 +1016,16 @@ extern int sparc_mode_class[];
/* Sparc ABI says that quad-precision floats and all structures are returned
in memory.
For v9, all aggregates 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.
FIXME: wip */
#define RETURN_IN_MEMORY(TYPE) \
(TYPE_MODE (TYPE) == BLKmode \
|| (! TARGET_ARCH64 && (TYPE_MODE (TYPE) == TFmode \
|| TYPE_MODE (TYPE) == TCmode)))
(TARGET_ARCH32 \
? (TYPE_MODE (TYPE) == BLKmode \
|| TYPE_MODE (TYPE) == TFmode \
|| TYPE_MODE (TYPE) == TCmode) \
: TYPE_MODE (TYPE) == BLKmode)
/* Functions which return large structures get the address
to place the wanted value at offset 64 from the frame.
......@@ -1025,7 +1068,9 @@ extern int sparc_mode_class[];
For any two classes, it is very desirable that there be another
class that represents their union. */
/* The SPARC has two kinds of registers, general and floating point.
/* The SPARC has various kinds of registers: general, floating point,
and condition codes [well, it has others as well, but none that we
care directly about].
For v9 we must distinguish between the upper and lower floating point
registers because the upper ones can't hold SFmode values.
......@@ -1092,10 +1137,7 @@ extern enum reg_class sparc_regno_reg_class[];
We put %f0/%f1 last among the float registers, so as to make it more
likely that a pseudo-register which dies in the float return register
will get allocated to the float return register, thus saving a move
instruction at the end of the function.
The float registers are ordered a little "funny" because in the 64 bit
architecture, some of them (%f16-%f47) are call-preserved. */
instruction at the end of the function. */
#define REG_ALLOC_ORDER \
{ 8, 9, 10, 11, 12, 13, 2, 3, \
......@@ -1103,21 +1145,19 @@ extern enum reg_class sparc_regno_reg_class[];
23, 24, 25, 26, 27, 28, 29, 31, \
34, 35, 36, 37, 38, 39, /* %f2-%f7 */ \
40, 41, 42, 43, 44, 45, 46, 47, /* %f8-%f15 */ \
80, 81, 82, 83, 84, 85, 86, 87, /* %f48-%f55 */ \
88, 89, 90, 91, 92, 93, 94, 95, /* %f56-%f63 */ \
48, 49, 50, 51, 52, 53, 54, 55, /* %f16-%f23 */ \
56, 57, 58, 59, 60, 61, 62, 63, /* %f24-%f31 */ \
64, 65, 66, 67, 68, 69, 70, 71, /* %f32-%f39 */ \
72, 73, 74, 75, 76, 77, 78, 79, /* %f40-%f47 */ \
80, 81, 82, 83, 84, 85, 86, 87, /* %f48-%f55 */ \
88, 89, 90, 91, 92, 93, 94, 95, /* %f56-%f63 */ \
32, 33, /* %f0,%f1 */ \
96, 97, 98, 99, 100, /* %fcc0-3, %icc */ \
1, 4, 5, 6, 7, 0, 14, 30}
/* This is the order in which to allocate registers for
leaf functions. If all registers can fit in the "i" registers,
then we have the possibility of having a leaf function.
The floating point registers are ordered a little "funny" because in the
64 bit architecture some of them (%f16-%f47) are call-preserved. */
then we have the possibility of having a leaf function. */
#define REG_LEAF_ALLOC_ORDER \
{ 2, 3, 24, 25, 26, 27, 28, 29, \
......@@ -1125,12 +1165,12 @@ extern enum reg_class sparc_regno_reg_class[];
16, 17, 18, 19, 20, 21, 22, 23, \
34, 35, 36, 37, 38, 39, \
40, 41, 42, 43, 44, 45, 46, 47, \
80, 81, 82, 83, 84, 85, 86, 87, \
88, 89, 90, 91, 92, 93, 94, 95, \
48, 49, 50, 51, 52, 53, 54, 55, \
56, 57, 58, 59, 60, 61, 62, 63, \
64, 65, 66, 67, 68, 69, 70, 71, \
72, 73, 74, 75, 76, 77, 78, 79, \
80, 81, 82, 83, 84, 85, 86, 87, \
88, 89, 90, 91, 92, 93, 94, 95, \
32, 33, \
96, 97, 98, 99, 100, \
1, 4, 5, 6, 7, 0, 14, 30, 31}
......@@ -1293,13 +1333,15 @@ extern char leaf_reg_remap[];
/* Stack layout; function entry, exit and calling. */
/* Define the number of register that can hold parameters.
These two macros are used only in other macro definitions below.
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: Non-float args are passed in %o0-5 and float args are passed in
%f0-%f15. */
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 ? 16 : 6) : 6)
(TARGET_ARCH64 \
? (GET_MODE_CLASS (MODE) == MODE_FLOAT ? 32 : 6) \
: 6)
/* Define this if pushing a word on the stack
makes the stack pointer a smaller address. */
......@@ -1328,16 +1370,16 @@ extern char leaf_reg_remap[];
/* Offset of first parameter from the argument pointer register value.
!v9: This is 64 for the ins and locals, plus 4 for the struct-return reg
even if this function isn't going to use it.
v9: This is 128 for the ins and locals, plus a reserved space of 8. */
v9: This is 128 for the ins and locals. */
#define FIRST_PARM_OFFSET(FNDECL) \
(TARGET_ARCH64 ? (SPARC_STACK_BIAS + 136) \
(TARGET_ARCH64 ? (SPARC_STACK_BIAS + 16 * UNITS_PER_WORD) \
: (STRUCT_VALUE_OFFSET + UNITS_PER_WORD))
/* When a parameter is passed in a register, stack space is still
allocated for it. */
#if ! SPARC_ARCH64
#define REG_PARM_STACK_SPACE(DECL) (NPARM_REGS (SImode) * UNITS_PER_WORD)
#endif
/* This only takes into account the int regs.
fp regs are handled elsewhere. */
#define REG_PARM_STACK_SPACE(DECL) (6 * UNITS_PER_WORD)
/* Keep the stack pointer constant throughout the function.
This is both an optimization and a necessity: longjmp
......@@ -1427,11 +1469,12 @@ extern char leaf_reg_remap[];
#define APPLY_RESULT_SIZE 16
/* 1 if N is a possible register number for function argument passing.
On SPARC, these are the "output" registers. v9 also uses %f0-%f15. */
On SPARC, these are the "output" registers. v9 also uses %f0-%f31. */
#define FUNCTION_ARG_REGNO_P(N) \
(TARGET_ARCH64 ? (((N) < 14 && (N) > 7) || (N) > 31 && (N) < 48) \
: ((N) < 14 && (N) > 7))
(TARGET_ARCH64 \
? (((N) >= 8 && (N) <= 13) || ((N) >= 32 && (N) <= 63)) \
: ((N) >= 8 && (N) <= 13))
/* Define a data type for recording info about an argument list
during the scan of that argument list. This data type should
......@@ -1444,129 +1487,30 @@ extern char leaf_reg_remap[];
if any, which holds the structure-value-address).
Thus 7 or more means all following args should go on the stack.
For v9, we record how many of each type has been passed. Different
types get passed differently.
For v9, we also need to know whether a prototype is present. */
- Float args are passed in %f0-15, after which they go to the stack
where floats and doubles are passed 8 byte aligned and long doubles
are passed 16 byte aligned.
- All aggregates are passed by reference. The callee copies
the structure if necessary, except if stdarg/varargs and the struct
matches the ellipse in which case the caller makes a copy.
- Any non-float argument might be split between memory and reg %o5.
??? I don't think this can ever happen now that structs are no
longer passed in regs.
For v9 return values:
- For all aggregates, the caller allocates space for the return value,
and passes the pointer as an implicit first argument, which is
allocated like all other arguments.
- The unimp instruction stuff for structure returns is gone. */
#if SPARC_ARCH64
enum sparc_arg_class { SPARC_ARG_INT = 0, SPARC_ARG_FLOAT = 1 };
struct sparc_args {
int arg_count[2]; /* must be int! (for __builtin_args_info) */
int words; /* number of words passed so far */
int prototype_p; /* non-zero if a prototype is present */
int libcall_p; /* non-zero if a library call */
};
#define CUMULATIVE_ARGS struct sparc_args
/* Return index into CUMULATIVE_ARGS. */
#define GET_SPARC_ARG_CLASS(MODE) \
(GET_MODE_CLASS (MODE) == MODE_FLOAT ? SPARC_ARG_FLOAT : SPARC_ARG_INT)
/* Round a register number up to a proper boundary for an arg of mode MODE.
This macro is only used in this file.
The "& (0x10000 - ...)" is used to round up to the next appropriate reg. */
#define ROUND_REG(CUM, MODE) \
(GET_MODE_CLASS (MODE) != MODE_FLOAT \
? (CUM).arg_count[(int) GET_SPARC_ARG_CLASS (MODE)] \
: ((CUM).arg_count[(int) GET_SPARC_ARG_CLASS (MODE)] \
+ GET_MODE_UNIT_SIZE (MODE) / 4 - 1) \
& (0x10000 - GET_MODE_UNIT_SIZE (MODE) / 4))
#define ROUND_ADVANCE(SIZE) \
(((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
#else /* ! SPARC_ARCH64 */
#define CUMULATIVE_ARGS int
#define ROUND_REG(CUM, MODE) (CUM)
#define ROUND_ADVANCE(SIZE) \
((SIZE + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
#endif /* ! SPARC_ARCH64 */
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0.
For a library call, FNTYPE is 0. */
On SPARC, the offset always starts at 0: the first parm reg is always
the same reg. */
#if SPARC_ARCH64
extern int sparc_arg_count,sparc_n_named_args;
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
do { \
(CUM).arg_count[(int) SPARC_ARG_INT] = 0; \
(CUM).arg_count[(int) SPARC_ARG_FLOAT] = 0; \
sparc_arg_count = 0; \
sparc_n_named_args = \
((FNTYPE) && TYPE_ARG_TYPES (FNTYPE) \
? (list_length (TYPE_ARG_TYPES (FNTYPE)) \
+ (TREE_CODE (TREE_TYPE (FNTYPE)) == RECORD_TYPE \
|| TREE_CODE (TREE_TYPE (FNTYPE)) == QUAL_UNION_TYPE\
|| TREE_CODE (TREE_TYPE (FNTYPE)) == SET_TYPE \
|| TREE_CODE (TREE_TYPE (FNTYPE)) == UNION_TYPE)) \
/* Can't tell, treat 'em all as named. */ \
: 10000); \
} while (0)
#else
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) ((CUM) = 0)
#endif
extern void init_cumulative_args ();
#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \
init_cumulative_args (& (CUM), (FNTYPE), (LIBNAME), (INDIRECT));
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
(TYPE is null for libcalls where that information may not be available.) */
TYPE is null for libcalls where that information may not be available. */
#if SPARC_ARCH64
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
do { \
(CUM).arg_count[(int) GET_SPARC_ARG_CLASS (MODE)] = \
ROUND_REG ((CUM), (MODE)) \
+ (GET_MODE_CLASS (MODE) == MODE_FLOAT \
? GET_MODE_SIZE (MODE) / 4 \
: ROUND_ADVANCE ((MODE) == BLKmode \
? GET_MODE_SIZE (Pmode) \
: GET_MODE_SIZE (MODE))); \
sparc_arg_count++; \
} while (0)
#else
extern void function_arg_advance ();
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
((CUM) += ((MODE) != BLKmode \
? ROUND_ADVANCE (GET_MODE_SIZE (MODE)) \
: ROUND_ADVANCE (int_size_in_bytes (TYPE))))
#endif
/* Return boolean indicating arg of mode MODE will be passed in a reg.
This macro is only used in this file. */
#if SPARC_ARCH64
#define PASS_IN_REG_P(CUM, MODE, TYPE) \
(ROUND_REG ((CUM), (MODE)) < NPARM_REGS (MODE) \
&& ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \
&& ((TYPE)==0 || (MODE) != BLKmode))
#else
#define PASS_IN_REG_P(CUM, MODE, TYPE) \
((CUM) < NPARM_REGS (SImode) \
&& ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \
&& ((TYPE)==0 || (MODE) != BLKmode \
|| (TYPE_ALIGN (TYPE) % PARM_BOUNDARY == 0)))
#endif
function_arg_advance (& (CUM), (MODE), (TYPE), (NAMED))
/* Determine where to put an argument to a function.
Value is zero to push the argument on the stack,
......@@ -1581,64 +1525,52 @@ extern int sparc_arg_count,sparc_n_named_args;
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis). */
/* On SPARC the first six args are normally in registers
and the rest are pushed. Any arg that starts within the first 6 words
is at least partially passed in a register unless its data type forbids.
For v9, the first 6 int args are passed in regs and the first N
float args are passed in regs (where N is such that %f0-15 are filled).
The rest are pushed. Any arg that starts within the first 6 words
is at least partially passed in a register unless its data type forbids. */
extern struct rtx_def *function_arg ();
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
(PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \
? gen_rtx (REG, (MODE), \
(BASE_PASSING_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))))\
: 0)
function_arg (& (CUM), (MODE), (TYPE), (NAMED), 0)
/* Define where a function finds its arguments.
This is different from FUNCTION_ARG because of register windows. */
#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
(PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \
? gen_rtx (REG, (MODE), \
(BASE_INCOMING_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))))\
: 0)
function_arg (& (CUM), (MODE), (TYPE), (NAMED), 1)
/* For an arg passed partly in registers and partly in memory,
this is the number of registers used.
For args passed entirely in registers or entirely in memory, zero.
Any arg that starts in the first 6 regs but won't entirely fit in them
needs partial registers on the Sparc (!v9). On v9, there are no arguments
that are passed partially in registers (??? complex values?). */
For args passed entirely in registers or entirely in memory, zero. */
#if ! SPARC_ARCH64
extern int function_arg_partial_nregs ();
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
(PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \
&& ((CUM) + ((MODE) == BLKmode \
? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
: ROUND_ADVANCE (GET_MODE_SIZE (MODE))) - NPARM_REGS (SImode) > 0)\
? (NPARM_REGS (SImode) - (CUM)) \
: 0)
#endif
function_arg_partial_nregs (& (CUM), (MODE), (TYPE), (NAMED))
/* The SPARC ABI stipulates passing struct arguments (of any size) and
(!v9) quad-precision floats by invisible reference.
For Pascal, also pass arrays by reference. */
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
((TYPE && AGGREGATE_TYPE_P (TYPE)) \
|| (!TARGET_ARCH64 && MODE == TFmode))
/* A C expression that indicates when it is the called function's
responsibility to make copies of arguments passed by reference.
If the callee can determine that the argument won't be modified, it can
avoid the copy. */
/* ??? We'd love to be able to use NAMED here. Unfortunately, it doesn't
include the last named argument so we keep track of the args ourselves. */
/* A C expression that indicates when an argument must be passed by reference.
If nonzero for an argument, a copy of that argument is made in memory and a
pointer to the argument is passed instead of the argument itself.
The pointer is passed in whatever way is appropriate for passing a pointer
to that type. */
#if SPARC_ARCH64
#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
(sparc_arg_count < sparc_n_named_args)
#endif
extern int function_arg_pass_by_reference ();
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
function_arg_pass_by_reference (& (CUM), (MODE), (TYPE), (NAMED))
/* If defined, a C expression which determines whether, and in which direction,
to pad out an argument with extra space. The value should be of type
`enum direction': either `upward' to pad above the argument,
`downward' to pad below, or `none' to inhibit padding. */
extern enum direction function_arg_padding ();
#define FUNCTION_ARG_PADDING(MODE, TYPE) \
function_arg_padding ((MODE), (TYPE))
/* If defined, a C expression that gives the alignment boundary, in bits,
of an argument with the specified mode and type. If it is not defined,
PARM_BOUNDARY is used for all arguments.
For sparc64, objects requiring 16 byte alignment are passed that way. */
#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \
((TARGET_ARCH64 \
&& (GET_MODE_ALIGNMENT (MODE) == 128 \
|| ((TYPE) && TYPE_ALIGN (TYPE) == 128))) \
? 128 : PARM_BOUNDARY)
/* Initialize data used by insn expanders. This is called from
init_emit, once for each function, before code is generated.
......@@ -2133,6 +2065,7 @@ extern union tree_node *current_function_decl;
nop
.xword context
.xword function */
/* ??? Stack is execute-protected in v9. */
#define TRAMPOLINE_TEMPLATE(FILE) \
do { \
......@@ -2177,9 +2110,24 @@ void sparc64_initialize_trampoline ();
/* Generate necessary RTL for __builtin_saveregs().
ARGLIST is the argument list; see expr.c. */
extern struct rtx_def *sparc_builtin_saveregs ();
#define EXPAND_BUILTIN_SAVEREGS(ARGLIST) sparc_builtin_saveregs (ARGLIST)
/* Define this macro if the location where a function argument is passed
depends on whether or not it is a named argument.
This macro controls how the NAMED argument to FUNCTION_ARG
is set for varargs and stdarg functions. With this macro defined,
the NAMED argument is always true for named arguments, and false for
unnamed arguments. If this is not defined, but SETUP_INCOMING_VARARGS
is defined, then all arguments are treated as named. Otherwise, all named
arguments except the last are treated as named.
For the v9 we want NAMED to mean what it says it means. */
/* ??? This needn't be set for v8, but I don't want to make this runtime
selectable if I don't have to. */
#define STRICT_ARGUMENT_NAMING
/* Generate RTL to flush the register windows so as to make arbitrary frames
available. */
#define SETUP_FRAME_ADDRESSES() \
......@@ -2717,8 +2665,7 @@ extern struct rtx_def *legitimize_pic_address ();
return 8;
/* Compute the cost of an address. For the sparc, all valid addresses are
the same cost.
??? Is this true for v9? */
the same cost. */
#define ADDRESS_COST(RTX) 1
......@@ -3186,6 +3133,7 @@ do { \
/* Declare functions defined in sparc.c and used in templates. */
extern char *singlemove_string ();
extern char *doublemove_string ();
extern char *output_move_double ();
extern char *output_move_quad ();
extern char *output_fp_move_double ();
......
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