Commit 4d72536e by Richard Sandiford Committed by Richard Sandiford

abi64.h (SETUP_INCOMING_VARARGS): Undefine.

	* config/mips/abi64.h (SETUP_INCOMING_VARARGS): Undefine.
	* config/mips/mips-protos.h (mips_setup_incoming_varargs): Declare.
	(function_arg): Constify CUMULATIVE_ARGS.
	(function_arg_partial_nregs, function_arg_pass_by_reference): Likewise.
	* config/mips/mips.h (UNITS_PER_FPVALUE): Zero when TARGET_SOFT_FLOAT.
	(UNITS_PER_DOUBLE): New macro.
	(SETUP_INCOMING_VARARGS): Define.  Use mips_setup_incoming_varargs.
	(CUMULATIVE_ARGS): Reformat.  Remove num_adjusts workaround and
	last_arg_fp field.  Replace arg_words and fp_arg_words with gp_regs,
	fp_regs and stack_words.
	(EABI_FLOAT_VARARGS_P): New macro.
	* config/mips/mips.c (struct mips_arg_info): New.
	(mips_arg_info): New function.
	(function_arg_advance): Use it.  Add adjustment instructions here
	rather than in function_arg.
	(function_arg): Constify CUMULATIVE_ARGS.  Use mips_arg_info.  Check
	for VOIDmode at the beginning of the function.
	(function_partial_nregs): Constify CUMULATIVE_ARGS.  Use mips_arg_info.
	(function_arg_pass_by_reference): Likewise.
	(mips_setup_incoming_varags): New, largely based on old abi64.h code.
	(mips_build_va_list): Test EABI_FLOAT_VARARGS_P.
	(mips_va_start): Likewise.  Use the new stack_words field of
	CUMULATIVE_ARGS to set up overflow area.  Reformat.
	(mips_va_arg): Test EABI_FLOAT_VARARGS_P.  Unify EABI handling of
	doubles and other types, aligning the overflow pointer for non-doubles
	too.  Remove some code duplication.  Replace hard-coded constants.

From-SVN: r51167
parent e6f884cd
2002-03-22 Richard Sandiford <rsandifo@redhat.com> 2002-03-22 Richard Sandiford <rsandifo@redhat.com>
* config/mips/abi64.h (SETUP_INCOMING_VARARGS): Undefine.
* config/mips/mips-protos.h (mips_setup_incoming_varargs): Declare.
(function_arg): Constify CUMULATIVE_ARGS.
(function_arg_partial_nregs, function_arg_pass_by_reference): Likewise.
* config/mips/mips.h (UNITS_PER_FPVALUE): Zero when TARGET_SOFT_FLOAT.
(UNITS_PER_DOUBLE): New macro.
(SETUP_INCOMING_VARARGS): Define. Use mips_setup_incoming_varargs.
(CUMULATIVE_ARGS): Reformat. Remove num_adjusts workaround and
last_arg_fp field. Replace arg_words and fp_arg_words with gp_regs,
fp_regs and stack_words.
(EABI_FLOAT_VARARGS_P): New macro.
* config/mips/mips.c (struct mips_arg_info): New.
(mips_arg_info): New function.
(function_arg_advance): Use it. Add adjustment instructions here
rather than in function_arg.
(function_arg): Constify CUMULATIVE_ARGS. Use mips_arg_info. Check
for VOIDmode at the beginning of the function.
(function_partial_nregs): Constify CUMULATIVE_ARGS. Use mips_arg_info.
(function_arg_pass_by_reference): Likewise.
(mips_setup_incoming_varags): New, largely based on old abi64.h code.
(mips_build_va_list): Test EABI_FLOAT_VARARGS_P.
(mips_va_start): Likewise. Use the new stack_words field of
CUMULATIVE_ARGS to set up overflow area. Reformat.
(mips_va_arg): Test EABI_FLOAT_VARARGS_P. Unify EABI handling of
doubles and other types, aligning the overflow pointer for non-doubles
too. Remove some code duplication. Replace hard-coded constants.
2002-03-22 Richard Sandiford <rsandifo@redhat.com>
* config/mips/mips.h (FUNCTION_ARG_REGNO_P): Simplify. * config/mips/mips.h (FUNCTION_ARG_REGNO_P): Simplify.
(CLASS_UNITS): Undefine. (CLASS_UNITS): Undefine.
(CLASS_MAX_NREGS): Use FP_INC. (CLASS_MAX_NREGS): Use FP_INC.
......
...@@ -102,96 +102,6 @@ Boston, MA 02111-1307, USA. */ ...@@ -102,96 +102,6 @@ Boston, MA 02111-1307, USA. */
#undef FUNCTION_VALUE #undef FUNCTION_VALUE
#define FUNCTION_VALUE(VALTYPE, FUNC) mips_function_value (VALTYPE, FUNC) #define FUNCTION_VALUE(VALTYPE, FUNC) mips_function_value (VALTYPE, FUNC)
/* For varargs, we must save the current argument, because it is the fake
argument va_alist, and will need to be converted to the real argument.
For stdarg, we do not need to save the current argument, because it
is a real argument. */
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
{ unsigned int mips_off \
= (! current_function_varargs) && (! (CUM).last_arg_fp); \
unsigned int mips_fp_off \
= (! current_function_varargs) && ((CUM).last_arg_fp); \
if (((mips_abi != ABI_32 && mips_abi != ABI_O64) \
&& (CUM).arg_words < MAX_ARGS_IN_REGISTERS - mips_off) \
|| (mips_abi == ABI_EABI \
&& ! TARGET_SOFT_FLOAT \
&& (CUM).fp_arg_words < MAX_ARGS_IN_REGISTERS - mips_fp_off)) \
{ \
int mips_save_gp_regs \
= MAX_ARGS_IN_REGISTERS - (CUM).arg_words - mips_off; \
int mips_save_fp_regs \
= (mips_abi != ABI_EABI ? 0 \
: MAX_ARGS_IN_REGISTERS - (CUM).fp_arg_words - mips_fp_off); \
\
if (mips_save_gp_regs < 0) \
mips_save_gp_regs = 0; \
if (mips_save_fp_regs < 0) \
mips_save_fp_regs = 0; \
PRETEND_SIZE = ((mips_save_gp_regs * UNITS_PER_WORD) \
+ (mips_save_fp_regs * UNITS_PER_FPREG)); \
\
if (! (NO_RTL)) \
{ \
if ((CUM).arg_words < MAX_ARGS_IN_REGISTERS - mips_off) \
{ \
rtx ptr, mem; \
if (mips_abi != ABI_EABI) \
ptr = virtual_incoming_args_rtx; \
else \
ptr = plus_constant (virtual_incoming_args_rtx, \
- (mips_save_gp_regs \
* UNITS_PER_WORD)); \
mem = gen_rtx_MEM (BLKmode, ptr); \
/* va_arg is an array access in this case, which causes \
it to get MEM_IN_STRUCT_P set. We must set it here \
so that the insn scheduler won't assume that these \
stores can't possibly overlap with the va_arg loads. */ \
if (mips_abi != ABI_EABI && BYTES_BIG_ENDIAN) \
MEM_SET_IN_STRUCT_P (mem, 1); \
move_block_from_reg \
((CUM).arg_words + GP_ARG_FIRST + mips_off, \
mem, \
mips_save_gp_regs, \
mips_save_gp_regs * UNITS_PER_WORD); \
} \
if (mips_abi == ABI_EABI \
&& ! TARGET_SOFT_FLOAT \
&& (CUM).fp_arg_words < MAX_ARGS_IN_REGISTERS - mips_fp_off) \
{ \
enum machine_mode mode = TARGET_SINGLE_FLOAT ? SFmode : DFmode; \
int size = GET_MODE_SIZE (mode); \
int off; \
int i; \
/* We can't use move_block_from_reg, because it will use \
the wrong mode. */ \
off = - (mips_save_gp_regs * UNITS_PER_WORD); \
if (! TARGET_SINGLE_FLOAT) \
off &= ~ 7; \
if (! TARGET_FLOAT64 || TARGET_SINGLE_FLOAT) \
off -= (mips_save_fp_regs / 2) * size; \
else \
off -= mips_save_fp_regs * size; \
for (i = 0; i < mips_save_fp_regs; i++) \
{ \
rtx tem = \
gen_rtx_MEM (mode, \
plus_constant (virtual_incoming_args_rtx, \
off)); \
emit_move_insn (tem, \
gen_rtx_REG (mode, \
((CUM).fp_arg_words \
+ FP_ARG_FIRST \
+ i \
+ mips_fp_off))); \
off += size; \
if (! TARGET_FLOAT64 || TARGET_SINGLE_FLOAT) \
++i; \
} \
} \
} \
} \
}
#define STRICT_ARGUMENT_NAMING (mips_abi != ABI_32 && mips_abi != ABI_O64) #define STRICT_ARGUMENT_NAMING (mips_abi != ABI_32 && mips_abi != ABI_O64)
/* A C expression that indicates when an argument must be passed by /* A C expression that indicates when an argument must be passed by
......
...@@ -56,16 +56,21 @@ extern unsigned int mips_hard_regno_nregs PARAMS ((int, ...@@ -56,16 +56,21 @@ extern unsigned int mips_hard_regno_nregs PARAMS ((int,
enum machine_mode)); enum machine_mode));
extern int mips_return_in_memory PARAMS ((tree)); extern int mips_return_in_memory PARAMS ((tree));
extern struct rtx_def *function_arg PARAMS ((CUMULATIVE_ARGS *, extern struct rtx_def *function_arg PARAMS ((const CUMULATIVE_ARGS *,
enum machine_mode, tree, int)); enum machine_mode, tree, int));
extern void function_arg_advance PARAMS ((CUMULATIVE_ARGS *, extern void function_arg_advance PARAMS ((CUMULATIVE_ARGS *,
enum machine_mode, enum machine_mode,
tree, int)); tree, int));
extern int function_arg_partial_nregs PARAMS ((CUMULATIVE_ARGS *, extern int function_arg_partial_nregs
PARAMS ((const CUMULATIVE_ARGS *,
enum machine_mode,
tree, int));
extern int mips_setup_incoming_varargs
PARAMS ((const CUMULATIVE_ARGS *,
enum machine_mode, enum machine_mode,
tree, int)); tree, int));
extern int function_arg_pass_by_reference extern int function_arg_pass_by_reference
PARAMS ((CUMULATIVE_ARGS *, PARAMS ((const CUMULATIVE_ARGS *,
enum machine_mode, tree, int)); enum machine_mode, tree, int));
extern int mips16_constant_after_function_p PARAMS ((tree)); extern int mips16_constant_after_function_p PARAMS ((tree));
extern int mips_output_external PARAMS ((FILE *, tree, extern int mips_output_external PARAMS ((FILE *, tree,
......
...@@ -1595,7 +1595,10 @@ do { \ ...@@ -1595,7 +1595,10 @@ do { \
#define FP_INC (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT ? 1 : 2) #define FP_INC (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT ? 1 : 2)
/* The largest size of value that can be held in floating-point registers. */ /* The largest size of value that can be held in floating-point registers. */
#define UNITS_PER_FPVALUE (FP_INC * UNITS_PER_FPREG) #define UNITS_PER_FPVALUE (TARGET_SOFT_FLOAT ? 0 : FP_INC * UNITS_PER_FPREG)
/* The number of bytes in a double. */
#define UNITS_PER_DOUBLE (TYPE_PRECISION (double_type_node) / BITS_PER_UNIT)
/* A C expression for the size in bits of the type `int' on the /* A C expression for the size in bits of the type `int' on the
target machine. If you don't define this, the default is one target machine. If you don't define this, the default is one
...@@ -2738,6 +2741,10 @@ extern struct mips_frame_info current_frame_info; ...@@ -2738,6 +2741,10 @@ extern struct mips_frame_info current_frame_info;
#define RETURN_IN_MEMORY(TYPE) \ #define RETURN_IN_MEMORY(TYPE) \
mips_return_in_memory (TYPE) mips_return_in_memory (TYPE)
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
(PRETEND_SIZE) = mips_setup_incoming_varargs (&(CUM), (MODE), \
(TYPE), (NO_RTL))
#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT #define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
...@@ -2748,7 +2755,52 @@ extern struct mips_frame_info current_frame_info; ...@@ -2748,7 +2755,52 @@ extern struct mips_frame_info current_frame_info;
and about the args processed so far, enough to enable macros and about the args processed so far, enough to enable macros
such as FUNCTION_ARG to determine where the next arg should go. such as FUNCTION_ARG to determine where the next arg should go.
On the mips16, we need to keep track of which floating point This structure has to cope with two different argument allocation
schemes. Most MIPS ABIs view the arguments as a struct, of which the
first N words go in registers and the rest go on the stack. If I < N,
the Ith word might go in Ith integer argument register or the
Ith floating-point one. In some cases, it has to go in both (see
function_arg). For these ABIs, we only need to remember the number
of words passed so far.
The EABI instead allocates the integer and floating-point arguments
separately. The first N words of FP arguments go in FP registers,
the rest go on the stack. Likewise, the first N words of the other
arguments go in integer registers, and the rest go on the stack. We
need to maintain three counts: the number of integer registers used,
the number of floating-point registers used, and the number of words
passed on the stack.
We could keep separate information for the two ABIs (a word count for
the standard ABIs, and three separate counts for the EABI). But it
seems simpler to view the standard ABIs as forms of EABI that do not
allocate floating-point registers.
So for the standard ABIs, the first N words are allocated to integer
registers, and function_arg decides on an argument-by-argument basis
whether that argument should really go in an integer register, or in
a floating-point one. */
typedef struct mips_args {
/* Always true for varargs functions. Otherwise true if at least
one argument has been passed in an integer register. */
int gp_reg_found;
/* The number of arguments seen so far. */
unsigned int arg_number;
/* For EABI, the number of integer registers used so far. For other
ABIs, the number of words passed in registers (whether integer
or floating-point). */
unsigned int gp_regs;
/* For EABI, the number of floating-point registers used so far. */
unsigned int fp_regs;
/* The number of words passed on the stack. */
unsigned int stack_words;
/* On the mips16, we need to keep track of which floating point
arguments were passed in general registers, but would have been arguments were passed in general registers, but would have been
passed in the FP regs if this were a 32 bit function, so that we passed in the FP regs if this were a 32 bit function, so that we
can move them to the FP regs if we wind up calling a 32 bit can move them to the FP regs if we wind up calling a 32 bit
...@@ -2759,21 +2811,19 @@ extern struct mips_frame_info current_frame_info; ...@@ -2759,21 +2811,19 @@ extern struct mips_frame_info current_frame_info;
argument. Thus 6 == 1 * 4 + 2 means a DFmode argument followed by argument. Thus 6 == 1 * 4 + 2 means a DFmode argument followed by
an SFmode argument. ??? A more sophisticated approach will be an SFmode argument. ??? A more sophisticated approach will be
needed if MIPS_ABI != ABI_32. */ needed if MIPS_ABI != ABI_32. */
int fp_code;
typedef struct mips_args {
int gp_reg_found; /* whether a gp register was found yet */ /* True if the function has a prototype. */
unsigned int arg_number; /* argument number */ int prototype;
unsigned int arg_words; /* # total words the arguments take */
unsigned int fp_arg_words; /* # words for FP args (MIPS_EABI only) */ /* When a structure does not take up a full register, the argument
int last_arg_fp; /* nonzero if last arg was FP (EABI only) */ should sometimes be shifted left so that it occupies the high part
int fp_code; /* Mode of FP arguments (mips16) */ of the register. These two fields describe an array of ashl
unsigned int num_adjusts; /* number of adjustments made */ patterns for doing this. See function_arg_advance, which creates
/* Adjustments made to args pass in regs. */ the shift patterns, and function_arg, which returns them when given
/* ??? The size is doubled to work around a a VOIDmode argument. */
bug in the code that sets the adjustments unsigned int num_adjusts;
in function_arg. */ struct rtx_def *adjust[MAX_ARGS_IN_REGISTERS];
int prototype; /* True if the function has a prototype. */
struct rtx_def *adjust[MAX_ARGS_IN_REGISTERS*2];
} CUMULATIVE_ARGS; } CUMULATIVE_ARGS;
/* Initialize a variable CUM of type CUMULATIVE_ARGS /* Initialize a variable CUM of type CUMULATIVE_ARGS
...@@ -2828,6 +2878,12 @@ typedef struct mips_args { ...@@ -2828,6 +2878,12 @@ typedef struct mips_args {
? PARM_BOUNDARY \ ? PARM_BOUNDARY \
: GET_MODE_ALIGNMENT(MODE))) : GET_MODE_ALIGNMENT(MODE)))
/* True if using EABI and varargs can be passed in floating-point
registers. Under these conditions, we need a more complex form
of va_list, which tracks GPR, FPR and stack arguments separately. */
#define EABI_FLOAT_VARARGS_P \
(mips_abi == ABI_EABI && UNITS_PER_FPVALUE >= UNITS_PER_DOUBLE)
/* Tell prologue and epilogue if register REGNO should be saved / restored. */ /* Tell prologue and epilogue if register REGNO should be saved / restored. */
......
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