aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDoug Evans <devans@gcc.gnu.org>1997-10-17 20:39:37 +0000
committerDoug Evans <devans@gcc.gnu.org>1997-10-17 20:39:37 +0000
commit4fb4e4b8be6e8c27eb777469727555fc1db3ca01 (patch)
treea66dd17c6cdd2d0fdbd52a6cbac07913b75ddbba /gcc
parent941b1165c2536a4709341cb3c33e7b7c375f0d95 (diff)
downloadgcc-4fb4e4b8be6e8c27eb777469727555fc1db3ca01.zip
gcc-4fb4e4b8be6e8c27eb777469727555fc1db3ca01.tar.gz
gcc-4fb4e4b8be6e8c27eb777469727555fc1db3ca01.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/sparc/sp64-elf.h15
-rw-r--r--gcc/config/sparc/sparc.c998
-rw-r--r--gcc/config/sparc/sparc.h354
3 files changed, 987 insertions, 380 deletions
diff --git a/gcc/config/sparc/sp64-elf.h b/gcc/config/sparc/sp64-elf.h
index f0a36e6..8ff9650 100644
--- a/gcc/config/sparc/sp64-elf.h
+++ b/gcc/config/sparc/sp64-elf.h
@@ -1,5 +1,5 @@
/* 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
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 91d731f8..de4ee75 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -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
@@ -1697,7 +1692,59 @@ singlemove_string (operands)
/* Operand 1 must be a register, or a 'I' type CONST_INT. */
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,17 +2085,25 @@ 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);
- wordpart[1][0] = adj_offsettable_operand (op0, 4);
- wordpart[2][0] = adj_offsettable_operand (op0, 8);
- wordpart[3][0] = adj_offsettable_operand (op0, 12);
+ 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
{
@@ -2060,17 +2115,25 @@ 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);
- wordpart[1][1] = adj_offsettable_operand (op1, 4);
- wordpart[2][1] = adj_offsettable_operand (op1, 8);
- wordpart[3][1] = adj_offsettable_operand (op1, 12);
+ 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)
{
@@ -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,21 +2201,36 @@ output_move_quad (operands)
/* If the first move would clobber the source of the second one,
do them in the other order. */
- /* Overlapping registers. */
- if (optype0 == REGOP && optype1 == REGOP
- && (REGNO (op0) == REGNO (wordpart[1][3])
- || REGNO (op0) == REGNO (wordpart[1][2])
- || REGNO (op0) == REGNO (wordpart[1][1])))
+ /* Overlapping registers? */
+ if (TARGET_ARCH32)
{
- /* Do fourth word. */
- output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
- /* Do the third word. */
- output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
- /* Do the second word. */
- output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
- /* Do lowest-numbered word. */
- return singlemove_string (wordpart[0]);
+ if (optype0 == REGOP && optype1 == REGOP
+ && (REGNO (op0) == REGNO (wordpart[1][3])
+ || REGNO (op0) == REGNO (wordpart[1][2])
+ || REGNO (op0) == REGNO (wordpart[1][1])))
+ {
+ /* Do fourth word. */
+ output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
+ /* Do the third word. */
+ output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
+ /* Do the second word. */
+ output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
+ /* Do lowest-numbered word. */
+ 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,42 +2243,64 @@ 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. */
- output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]);
+ if (TARGET_ARCH32)
+ {
+ output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]);
- /* Make any unoffsettable addresses point at the second word. */
- if (addreg0)
- output_asm_insn ("add %0,0x4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("add %0,0x4,%0", &addreg1);
+ /* Make any unoffsettable addresses point at the second word. */
+ if (addreg0)
+ output_asm_insn ("add %0,0x4,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn ("add %0,0x4,%0", &addreg1);
+
+ /* Do the second word. */
+ output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
- /* Do the second word. */
- output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
+ /* Make any unoffsettable addresses point at the third word. */
+ if (addreg0)
+ output_asm_insn ("add %0,0x4,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn ("add %0,0x4,%0", &addreg1);
- /* Make any unoffsettable addresses point at the third word. */
- if (addreg0)
- output_asm_insn ("add %0,0x4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("add %0,0x4,%0", &addreg1);
+ /* Do the third word. */
+ output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
- /* Do the third word. */
- output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
+ /* Make any unoffsettable addresses point at the fourth word. */
+ if (addreg0)
+ output_asm_insn ("add %0,0x4,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn ("add %0,0x4,%0", &addreg1);
- /* Make any unoffsettable addresses point at the fourth word. */
- if (addreg0)
- output_asm_insn ("add %0,0x4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("add %0,0x4,%0", &addreg1);
+ /* Do the fourth word. */
+ output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
- /* Do the fourth word. */
- output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
+ /* Undo the adds we just did. */
+ if (addreg0)
+ 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]);
- /* Undo the adds we just did. */
- if (addreg0)
- output_asm_insn ("add %0,-0xc,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("add %0,-0xc,%0", &addreg1);
+ /* 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 "";
}
@@ -2324,7 +2425,7 @@ output_sized_memop (opname, mode, signedp)
fprintf (asm_out_file, "\t%s%s", opname, modename);
}
-
+
void
output_move_with_extension (operands)
rtx *operands;
@@ -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);
}
@@ -3405,105 +3502,671 @@ output_function_epilogue (file, size, leaf_function)
target_flags |= old_target_epilogue;
}
}
+
+/* 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. */
-/* 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. */
+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;
+}
-#if SPARC_ARCH64
+/* 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;
+ int regbase = (incoming_p
+ ? SPARC_INCOMING_INT_ARG_FIRST
+ : SPARC_OUTGOING_INT_ARG_FIRST);
+ int slotno, regno, padding;
+ rtx reg;
+
+ slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
+ &regno, &padding);
+
+ if (slotno == -1)
+ return 0;
+
+ if (TARGET_ARCH32)
+ {
+ reg = gen_rtx (REG, mode, regno);
+ return reg;
+ }
+
+ /* 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);
+
+ if (bytes > 16)
+ abort ();
+
+ mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
+ reg = gen_rtx (REG, mode, regno);
+ }
else
- adjust = 0;
+ {
+ /* Scalar or complex int. */
+ reg = gen_rtx (REG, mode, regno);
+ }
+
+ return reg;
+}
- 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;
+/* 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;
- /* Save int args.
- This is optimized to only save the regs that are necessary. Explicitly
- named args need not be saved. */
+ /* We pass 0 for incoming_p here, it doesn't matter. */
+ slotno = function_arg_slotno (cum, mode, type, named, 0, &regno, &padding);
- if (n_intregs > 0)
- move_block_from_reg (BASE_INCOMING_ARG_REG (SImode) + first_intreg,
- regbuf, n_intregs, n_intregs * UNITS_PER_WORD);
+ if (slotno == -1)
+ return 0;
- if (TARGET_FPU)
+ if (TARGET_ARCH32)
{
- /* 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). */
+ 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);
- 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 (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. */
- if (flag_check_memory_usage)
+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
{
- 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);
+ 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;
- 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);
+ /* 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)));
+ }
+ }
+}
- /* Return the address of the regbuf. */
+/* Handle the FUNCTION_ARG_PADDING macro.
+ For the 64 bit ABI structs are always stored left shifted in their
+ argument slot. */
- return XEXP (regbuf, 0);
+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.
-#else /* ! SPARC_ARCH64 */
+ 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,41 +4176,34 @@ 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.
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h
index 46e83b1..205f59b 100644
--- a/gcc/config/sparc/sparc.h
+++ b/gcc/config/sparc/sparc.h
@@ -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,9 +760,10 @@ 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
+#define SPARC_FIRST_V9_FP_REG 64
+#define SPARC_LAST_V9_FP_REG 95
/* V9 %fcc[0123]. V8 uses (figuratively) %fcc0. */
#define SPARC_FIRST_V9_FCC_REG 96
#define SPARC_LAST_V9_FCC_REG 99
@@ -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.
-
- - 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. */
+ For v9, we also need to know whether a prototype is present. */
-#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.
-
- On SPARC, the offset always starts at 0: the first parm reg is always
- the same reg. */
+ For a library call, FNTYPE is 0. */
-#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.) */
-
-#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
-#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
+ TYPE is null for libcalls where that information may not be available. */
-/* 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
+extern void function_arg_advance ();
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+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. */
-
-#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)
+extern struct rtx_def *function_arg ();
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+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)
+#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
+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?). */
-
-#if ! SPARC_ARCH64
-#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
-
-/* 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. */
-
-#if SPARC_ARCH64
-#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
- (sparc_arg_count < sparc_n_named_args)
-#endif
+ For args passed entirely in registers or entirely in memory, zero. */
+
+extern int function_arg_partial_nregs ();
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
+function_arg_partial_nregs (& (CUM), (MODE), (TYPE), (NAMED))
+
+/* 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. */
+
+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 ();