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
This commit is contained in:
parent
e6f884cdac
commit
4d72536eec
5 changed files with 661 additions and 725 deletions
|
@ -1,3 +1,32 @@
|
|||
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.
|
||||
|
|
|
@ -102,96 +102,6 @@ Boston, MA 02111-1307, USA. */
|
|||
#undef FUNCTION_VALUE
|
||||
#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)
|
||||
|
||||
/* 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,
|
|||
enum machine_mode));
|
||||
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));
|
||||
extern void function_arg_advance PARAMS ((CUMULATIVE_ARGS *,
|
||||
enum machine_mode,
|
||||
tree, int));
|
||||
extern int function_arg_partial_nregs PARAMS ((CUMULATIVE_ARGS *,
|
||||
enum machine_mode,
|
||||
tree, int));
|
||||
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,
|
||||
tree, int));
|
||||
extern int function_arg_pass_by_reference
|
||||
PARAMS ((CUMULATIVE_ARGS *,
|
||||
PARAMS ((const CUMULATIVE_ARGS *,
|
||||
enum machine_mode, tree, int));
|
||||
extern int mips16_constant_after_function_p PARAMS ((tree));
|
||||
extern int mips_output_external PARAMS ((FILE *, tree,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1595,7 +1595,10 @@ do { \
|
|||
#define FP_INC (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT ? 1 : 2)
|
||||
|
||||
/* 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
|
||||
target machine. If you don't define this, the default is one
|
||||
|
@ -2737,6 +2740,10 @@ extern struct mips_frame_info current_frame_info;
|
|||
|
||||
#define 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
|
||||
|
@ -2748,32 +2755,75 @@ extern struct mips_frame_info current_frame_info;
|
|||
and about the args processed so far, enough to enable macros
|
||||
such as FUNCTION_ARG to determine where the next arg should go.
|
||||
|
||||
On the mips16, we need to keep track of which floating point
|
||||
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
|
||||
can move them to the FP regs if we wind up calling a 32 bit
|
||||
function. We record this information in fp_code, encoded in base
|
||||
four. A zero digit means no floating point argument, a one digit
|
||||
means an SFmode argument, and a two digit means a DFmode argument,
|
||||
and a three digit is not used. The low order digit is the first
|
||||
argument. Thus 6 == 1 * 4 + 2 means a DFmode argument followed by
|
||||
an SFmode argument. ??? A more sophisticated approach will be
|
||||
needed if MIPS_ABI != ABI_32. */
|
||||
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 {
|
||||
int gp_reg_found; /* whether a gp register was found yet */
|
||||
unsigned int arg_number; /* argument number */
|
||||
unsigned int arg_words; /* # total words the arguments take */
|
||||
unsigned int fp_arg_words; /* # words for FP args (MIPS_EABI only) */
|
||||
int last_arg_fp; /* nonzero if last arg was FP (EABI only) */
|
||||
int fp_code; /* Mode of FP arguments (mips16) */
|
||||
unsigned int num_adjusts; /* number of adjustments made */
|
||||
/* Adjustments made to args pass in regs. */
|
||||
/* ??? The size is doubled to work around a
|
||||
bug in the code that sets the adjustments
|
||||
in function_arg. */
|
||||
int prototype; /* True if the function has a prototype. */
|
||||
struct rtx_def *adjust[MAX_ARGS_IN_REGISTERS*2];
|
||||
/* 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
|
||||
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
|
||||
function. We record this information in fp_code, encoded in base
|
||||
four. A zero digit means no floating point argument, a one digit
|
||||
means an SFmode argument, and a two digit means a DFmode argument,
|
||||
and a three digit is not used. The low order digit is the first
|
||||
argument. Thus 6 == 1 * 4 + 2 means a DFmode argument followed by
|
||||
an SFmode argument. ??? A more sophisticated approach will be
|
||||
needed if MIPS_ABI != ABI_32. */
|
||||
int fp_code;
|
||||
|
||||
/* True if the function has a prototype. */
|
||||
int prototype;
|
||||
|
||||
/* When a structure does not take up a full register, the argument
|
||||
should sometimes be shifted left so that it occupies the high part
|
||||
of the register. These two fields describe an array of ashl
|
||||
patterns for doing this. See function_arg_advance, which creates
|
||||
the shift patterns, and function_arg, which returns them when given
|
||||
a VOIDmode argument. */
|
||||
unsigned int num_adjusts;
|
||||
struct rtx_def *adjust[MAX_ARGS_IN_REGISTERS];
|
||||
} CUMULATIVE_ARGS;
|
||||
|
||||
/* Initialize a variable CUM of type CUMULATIVE_ARGS
|
||||
|
@ -2828,6 +2878,12 @@ typedef struct mips_args {
|
|||
? PARM_BOUNDARY \
|
||||
: 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. */
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue