Commit 293a36eb by Ian Lance Taylor

Add support for MIPS EABI

From-SVN: r12967
parent 03f00806
......@@ -26,11 +26,14 @@ Boston, MA 02111-1307, USA. */
{ "abi=", &mips_abi_string },
#undef STACK_BOUNDARY
#define STACK_BOUNDARY (mips_abi == ABI_32 ? 64 : 128)
#define STACK_BOUNDARY \
((mips_abi == ABI_32 || mips_abi == ABI_EABI) ? 64 : 128)
#undef MIPS_STACK_ALIGN
#define MIPS_STACK_ALIGN(LOC) \
(mips_abi == ABI_32 ? ((LOC)+7) & ~7 : ((LOC)+15) & ~15)
#define MIPS_STACK_ALIGN(LOC) \
((mips_abi == ABI_32 || mips_abi == ABI_EABI) \
? ((LOC) + 7) & ~7 \
: ((LOC) + 15) & ~15)
#undef GP_ARG_LAST
#define GP_ARG_LAST (mips_abi == ABI_32 ? GP_REG_FIRST + 7 : GP_REG_FIRST + 11)
......@@ -78,13 +81,16 @@ Boston, MA 02111-1307, USA. */
? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \
&& int_size_in_bytes (TYPE) < (PARM_BOUNDARY / BITS_PER_UNIT))\
: (GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY \
&& (mips_abi == ABI_32 || GET_MODE_CLASS (MODE) == MODE_INT)))\
&& (mips_abi == ABI_32 || mips_abi == ABI_EABI \
|| GET_MODE_CLASS (MODE) == MODE_INT))) \
? downward : upward))
#undef RETURN_IN_MEMORY
#define RETURN_IN_MEMORY(TYPE) \
#define RETURN_IN_MEMORY(TYPE) \
(mips_abi == ABI_32 \
? TYPE_MODE (TYPE) == BLKmode : int_size_in_bytes (TYPE) > 16)
? TYPE_MODE (TYPE) == BLKmode \
: (int_size_in_bytes (TYPE) \
> (mips_abi == ABI_EABI ? 2 * UNITS_PER_WORD : 16)))
extern struct rtx_def *mips_function_value ();
#undef FUNCTION_VALUE
......@@ -95,29 +101,78 @@ extern struct rtx_def *mips_function_value ();
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) \
{ if (mips_abi != ABI_32 \
&& ((CUM).arg_words \
< (MAX_ARGS_IN_REGISTERS - ! current_function_varargs))) \
{ int mips_off = (! current_function_varargs) && (! (CUM).last_arg_fp); \
int mips_fp_off = (! current_function_varargs) && ((CUM).last_arg_fp); \
if ((mips_abi != ABI_32 \
&& (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)) \
{ \
PRETEND_SIZE \
= (MAX_ARGS_IN_REGISTERS - (CUM).arg_words \
- ! current_function_varargs) * UNITS_PER_WORD; \
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)) \
{ \
rtx mem = gen_rtx (MEM, BLKmode, virtual_incoming_args_rtx); \
/* 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 (BYTES_BIG_ENDIAN) \
MEM_IN_STRUCT_P (mem) = 1; \
move_block_from_reg \
((CUM).arg_words + GP_ARG_FIRST + ! current_function_varargs, \
mem, \
(MAX_ARGS_IN_REGISTERS - (CUM).arg_words \
- ! current_function_varargs), \
PRETEND_SIZE); \
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_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) \
{ \
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) \
- (mips_save_fp_regs * UNITS_PER_FPREG)); \
for (i = 0; i < mips_save_fp_regs; i++) \
{ \
rtx tem = \
gen_rtx (MEM, DFmode, \
plus_constant (virtual_incoming_args_rtx, \
(off \
+ i * GET_MODE_SIZE (DFmode)))); \
emit_move_insn (tem, \
gen_rtx (REG, DFmode, \
((CUM).fp_arg_words \
+ FP_ARG_FIRST \
+ i \
+ mips_fp_off))); \
if (! TARGET_FLOAT64) \
++i; \
} \
} \
} \
} \
}
......@@ -125,6 +180,32 @@ extern struct rtx_def *mips_function_value ();
/* ??? Should disable for mips_abi == ABI32. */
#define STRICT_ARGUMENT_NAMING
/* 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. */
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
(mips_abi == ABI_EABI \
&& function_arg_pass_by_reference (&CUM, MODE, TYPE, NAMED))
/* A C expression that indicates when it is the called function's
responsibility to make a copy of arguments passed by invisible
reference. Normally, the caller makes a copy and passes the
address of the copy to the routine being called. When
FUNCTION_ARG_CALLEE_COPIES is defined and is nonzero, the caller
does not make a copy. Instead, it passes a pointer to the "live"
value. The called function must not modify this value. If it can
be determined that the value won't be modified, it need not make a
copy; otherwise a copy must be made.
??? The MIPS EABI says that the caller should copy in ``K&R mode.''
I don't know how to detect that here, since flag_traditional is not
a back end flag. */
#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
(mips_abi == ABI_EABI && (NAMED) \
&& FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED))
/* ??? Unimplemented stuff follows. */
/* ??? Add support for 16 byte/128 bit long doubles here when
......
......@@ -201,7 +201,7 @@ enum mips_abi_type mips_abi;
/* Strings to hold which cpu and instruction set architecture to use. */
char *mips_cpu_string; /* for -mcpu=<xxx> */
char *mips_isa_string; /* for -mips{1,2,3,4} */
char *mips_abi_string; /* for -mabi={o32,32,n32,n64,64} */
char *mips_abi_string; /* for -mabi={o32,32,n32,n64,64,eabi} */
/* If TRUE, we split addresses into their high and low parts in the RTL. */
int mips_split_addresses;
......@@ -500,7 +500,7 @@ mips_const_double_ok (op, mode)
return TRUE;
/* ??? li.s does not work right with SGI's Irix 6 assembler. */
if (mips_abi != ABI_32)
if (mips_abi != ABI_32 && mips_abi != ABI_EABI)
return FALSE;
REAL_VALUE_FROM_CONST_DOUBLE (d, op);
......@@ -3031,11 +3031,17 @@ function_arg_advance (cum, mode, type, named)
break;
case SFmode:
cum->arg_words++;
if (mips_abi == ABI_EABI && ! TARGET_SOFT_FLOAT)
cum->fp_arg_words++;
else
cum->arg_words++;
break;
case DFmode:
cum->arg_words += (TARGET_64BIT ? 1 : 2);
if (mips_abi == ABI_EABI && ! TARGET_SOFT_FLOAT && ! TARGET_SINGLE_FLOAT)
cum->fp_arg_words += (TARGET_64BIT ? 1 : 2);
else
cum->arg_words += (TARGET_64BIT ? 1 : 2);
break;
case DImode:
......@@ -3065,6 +3071,7 @@ function_arg (cum, mode, type, named)
rtx ret;
int regbase = -1;
int bias = 0;
int *arg_words = &cum->arg_words;
int struct_p = ((type != (tree)0)
&& (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE));
......@@ -3075,6 +3082,7 @@ function_arg (cum, mode, type, named)
cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
type, named);
cum->last_arg_fp = 0;
switch (mode)
{
case SFmode:
......@@ -3091,13 +3099,28 @@ function_arg (cum, mode, type, named)
bias = 1;
}
}
else if (mips_abi == ABI_EABI && ! TARGET_SOFT_FLOAT)
{
if (! TARGET_64BIT)
cum->fp_arg_words += cum->fp_arg_words & 1;
cum->last_arg_fp = 1;
arg_words = &cum->fp_arg_words;
regbase = FP_ARG_FIRST;
}
else
regbase = (TARGET_SOFT_FLOAT || ! named ? GP_ARG_FIRST : FP_ARG_FIRST);
break;
case DFmode:
if (! TARGET_64BIT)
cum->arg_words += (cum->arg_words & 1);
{
if (mips_abi == ABI_EABI
&& ! TARGET_SOFT_FLOAT
&& ! TARGET_SINGLE_FLOAT)
cum->fp_arg_words += cum->fp_arg_words & 1;
else
cum->arg_words += cum->arg_words & 1;
}
if (mips_abi == ABI_32)
regbase = ((cum->gp_reg_found
|| TARGET_SOFT_FLOAT
......@@ -3105,6 +3128,14 @@ function_arg (cum, mode, type, named)
|| cum->arg_number >= 2)
? GP_ARG_FIRST
: FP_ARG_FIRST);
else if (mips_abi == ABI_EABI
&& ! TARGET_SOFT_FLOAT
&& ! TARGET_SINGLE_FLOAT)
{
cum->last_arg_fp = 1;
arg_words = &cum->fp_arg_words;
regbase = FP_ARG_FIRST;
}
else
regbase = (TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT || ! named
? GP_ARG_FIRST : FP_ARG_FIRST);
......@@ -3118,9 +3149,8 @@ function_arg (cum, mode, type, named)
/* Drops through. */
case BLKmode:
if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD
&& ! TARGET_64BIT)
&& ! TARGET_64BIT && mips_abi != ABI_EABI)
cum->arg_words += (cum->arg_words & 1);
regbase = GP_ARG_FIRST;
break;
......@@ -3137,7 +3167,7 @@ function_arg (cum, mode, type, named)
regbase = GP_ARG_FIRST;
}
if (cum->arg_words >= MAX_ARGS_IN_REGISTERS)
if (*arg_words >= MAX_ARGS_IN_REGISTERS)
{
if (TARGET_DEBUG_E_MODE)
fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : "");
......@@ -3150,8 +3180,8 @@ function_arg (cum, mode, type, named)
abort ();
if (! type || TREE_CODE (type) != RECORD_TYPE || mips_abi == ABI_32
|| ! named)
ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias);
|| mips_abi == ABI_EABI || ! named)
ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
else
{
/* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the
......@@ -3169,7 +3199,7 @@ function_arg (cum, mode, type, named)
break;
if (! field)
ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias);
ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
else
{
/* Now handle the special case by returning a PARALLEL
......@@ -3188,15 +3218,15 @@ function_arg (cum, mode, type, named)
backend to allow DImode values in fp registers. */
chunks = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_WORD;
if (chunks + cum->arg_words + bias > MAX_ARGS_IN_REGISTERS)
chunks = MAX_ARGS_IN_REGISTERS - cum->arg_words - bias;
if (chunks + *arg_words + bias > MAX_ARGS_IN_REGISTERS)
chunks = MAX_ARGS_IN_REGISTERS - *arg_words - bias;
/* assign_parms checks the mode of ENTRY_PARM, so we must
use the actual mode here. */
ret = gen_rtx (PARALLEL, mode, rtvec_alloc (chunks));
bitpos = 0;
regno = regbase + cum->arg_words + bias;
regno = regbase + *arg_words + bias;
field = TYPE_FIELDS (type);
for (i = 0; i < chunks; i++)
{
......@@ -3227,7 +3257,7 @@ function_arg (cum, mode, type, named)
}
if (TARGET_DEBUG_E_MODE)
fprintf (stderr, "%s%s\n", reg_names[regbase + cum->arg_words + bias],
fprintf (stderr, "%s%s\n", reg_names[regbase + *arg_words + bias],
struct_p ? ", [struct]" : "");
/* The following is a hack in order to pass 1 byte structures
......@@ -3250,11 +3280,11 @@ function_arg (cum, mode, type, named)
calling convention for now. */
if (struct_p && int_size_in_bytes (type) < UNITS_PER_WORD
&& ! TARGET_64BIT)
&& ! TARGET_64BIT && mips_abi != ABI_EABI)
{
rtx amount = GEN_INT (BITS_PER_WORD
- int_size_in_bytes (type) * BITS_PER_UNIT);
rtx reg = gen_rtx (REG, word_mode, regbase + cum->arg_words + bias);
rtx reg = gen_rtx (REG, word_mode, regbase + *arg_words + bias);
if (TARGET_64BIT)
cum->adjust[ cum->num_adjusts++ ] = gen_ashldi3 (reg, reg, amount);
else
......@@ -3279,7 +3309,8 @@ function_arg_partial_nregs (cum, mode, type, named)
if ((mode == BLKmode
|| GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
|| GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
&& cum->arg_words < MAX_ARGS_IN_REGISTERS)
&& cum->arg_words < MAX_ARGS_IN_REGISTERS
&& mips_abi != ABI_EABI)
{
int words;
if (mode == BLKmode)
......@@ -3299,7 +3330,8 @@ function_arg_partial_nregs (cum, mode, type, named)
}
else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1
&& ! TARGET_64BIT)
&& ! TARGET_64BIT
&& mips_abi != ABI_EABI)
{
if (TARGET_DEBUG_E_MODE)
fprintf (stderr, "function_arg_partial_nregs = 1\n");
......@@ -3402,11 +3434,13 @@ override_options ()
else if (! strcmp (mips_abi_string, "64")
|| ! strcmp (mips_abi_string, "n64"))
mips_abi = ABI_64;
else if (! strcmp (mips_abi_string, "eabi"))
mips_abi = ABI_EABI;
else
error ("bad value (%s) for -mabi= switch", mips_abi_string);
/* A specified ISA defaults the ABI if it was not specified. */
if (mips_abi_string == 0 && mips_isa_string)
if (mips_abi_string == 0 && mips_isa_string && mips_abi != ABI_EABI)
{
if (mips_isa <= 2)
mips_abi = ABI_32;
......@@ -3414,7 +3448,7 @@ override_options ()
mips_abi = ABI_64;
}
/* A specified ABI defaults the ISA if it was not specified. */
else if (mips_isa_string == 0 && mips_abi_string)
else if (mips_isa_string == 0 && mips_abi_string && mips_abi != ABI_EABI)
{
if (mips_abi == ABI_32)
mips_isa = 1;
......@@ -4506,7 +4540,7 @@ mips_asm_file_start (stream)
/* Start a section, so that the first .popsection directive is guaranteed
to have a previously defined section to pop back to. */
if (mips_abi != ABI_32)
if (mips_abi != ABI_32 && mips_abi != ABI_EABI)
fprintf (stream, "\t.section\t.text\n");
/* This code exists so that we can put all externs before all symbol
......@@ -4853,7 +4887,7 @@ compute_frame_size (size)
for leaf routines (total_size == extra_size) to save the gp reg.
The gp reg is callee saved in the 64 bit ABI, so all routines must
save the gp reg. */
if (total_size == extra_size && mips_abi == ABI_32)
if (total_size == extra_size && (mips_abi == ABI_32 || mips_abi == ABI_EABI))
total_size = extra_size = 0;
else if (TARGET_ABICALLS)
{
......@@ -5857,7 +5891,8 @@ mips_function_value (valtype, func)
/* ??? How should we return complex float? */
if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
reg = FP_RETURN;
else if (TREE_CODE (valtype) == RECORD_TYPE && mips_abi != ABI_32)
else if (TREE_CODE (valtype) == RECORD_TYPE
&& mips_abi != ABI_32 && mips_abi != ABI_EABI)
{
/* A struct with only one or two floating point fields is returned in
the floating point registers. */
......@@ -5916,6 +5951,30 @@ mips_function_value (valtype, func)
return gen_rtx (REG, mode, reg);
}
/* The implementation of FUNCTION_ARG_PASS_BY_REFERENCE. Return
nonzero when an argument must be passed by reference. */
int
function_arg_pass_by_reference (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
int size;
if (mips_abi != ABI_EABI)
return 0;
/* ??? How should SCmode be handled? */
if (type == NULL_TREE || mode == DImode || mode == DFmode)
return 0;
size = int_size_in_bytes (type);
return size == -1 || size > UNITS_PER_WORD;
}
#endif
/* This function returns the register class required for a secondary
......
......@@ -82,7 +82,8 @@ enum processor_type {
enum mips_abi_type {
ABI_32,
ABI_N32,
ABI_64
ABI_64,
ABI_EABI
};
#ifndef MIPS_ABI_DEFAULT
......@@ -166,6 +167,7 @@ extern void final_prescan_insn ();
extern struct rtx_def * function_arg ();
extern void function_arg_advance ();
extern int function_arg_partial_nregs ();
extern int function_arg_pass_by_reference ();
extern void function_epilogue ();
extern void function_prologue ();
extern void gen_conditional_branch ();
......@@ -803,6 +805,8 @@ while (0)
%{mgp32:-U__mips64} %{mgp64:-D__mips64} \
%{msingle-float:%{!msoft-float:-D__mips_single_float}} \
%{m4650:%{!msoft-float:-D__mips_single_float}} \
%{msoft-float:-D__mips_soft_float} \
%{mabi=eabi:-D__mips_eabi} \
%{EB:-UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__ -D_MIPSEB -D__MIPSEB -D__MIPSEB__ %{!ansi:-DMIPSEB}} \
%{EL:-UMIPSEB -U_MIPSEB -U__MIPSEB -U__MIPSEB__ -D_MIPSEL -D__MIPSEL -D__MIPSEL__ %{!ansi:-DMIPSEL}} \
%(subtarget_cpp_spec) "
......@@ -1914,7 +1918,7 @@ extern struct mips_frame_info current_frame_info;
&& ((TO) == FRAME_POINTER_REGNUM \
|| (TO) == STACK_POINTER_REGNUM)) \
(OFFSET) = (current_frame_info.total_size \
- (mips_abi != ABI_32 \
- ((mips_abi != ABI_32 && mips_abi != ABI_EABI) \
? current_function_pretend_args_size \
: 0)); \
else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM \
......@@ -2112,6 +2116,8 @@ typedef struct mips_args {
int gp_reg_found; /* whether a gp register was found yet */
int arg_number; /* argument number */
int arg_words; /* # total words the arguments take */
int fp_arg_words; /* # words for FP args (MIPS_EABI only) */
int last_arg_fp; /* nonzero if last arg was FP (EABI only) */
int num_adjusts; /* number of adjustments made */
/* Adjustments made to args pass in regs. */
/* ??? The size is doubled to work around a
......@@ -2507,7 +2513,7 @@ typedef struct mips_args {
/* ??? Reject combining an address with a register for the MIPS \
64 bit ABI, because the SGI assembler can not handle this. */ \
if (!TARGET_DEBUG_A_MODE \
&& mips_abi == ABI_32 \
&& (mips_abi == ABI_32 || mips_abi == ABI_EABI) \
&& CONSTANT_ADDRESS_P (xplus1) \
&& ! mips_split_addresses \
&& (!TARGET_EMBEDDED_PIC \
......@@ -2537,7 +2543,7 @@ typedef struct mips_args {
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH \
|| (GET_CODE (X) == CONST \
&& ! (flag_pic && pic_address_needs_scratch (X)) \
&& mips_abi == ABI_32)) \
&& (mips_abi == ABI_32 || mips_abi == ABI_EABI))) \
&& (!HALF_PIC_P () || !HALF_PIC_ADDRESS_P (X)))
/* Define this, so that when PIC, reload won't try to reload invalid
......@@ -2556,7 +2562,8 @@ typedef struct mips_args {
#define LEGITIMATE_CONSTANT_P(X) \
((GET_CODE (X) != CONST_DOUBLE \
|| mips_const_double_ok (X, GET_MODE (X))) \
&& ! (GET_CODE (X) == CONST && mips_abi != ABI_32))
&& ! (GET_CODE (X) == CONST \
&& mips_abi != ABI_32 && mips_abi != ABI_EABI))
/* A C compound statement that attempts to replace X with a valid
memory address for an operand of mode MODE. WIN will be a C
......@@ -2618,7 +2625,7 @@ typedef struct mips_args {
if (GET_CODE (xinsn) == CONST \
&& ((flag_pic && pic_address_needs_scratch (xinsn)) \
/* ??? SGI's Irix 6 assembler can't handle CONST. */ \
|| mips_abi != ABI_32)) \
|| (mips_abi != ABI_32 && mips_abi != ABI_EABI))) \
{ \
rtx ptr_reg = gen_reg_rtx (Pmode); \
rtx constant = XEXP (XEXP (xinsn, 0), 1); \
......
......@@ -13,7 +13,51 @@
#ifndef __GNUC_VA_LIST
#define __GNUC_VA_LIST
#if defined (__mips_eabi) && ! defined (__mips_soft_float)
typedef struct {
/* Pointer to FP regs. */
char *__fp_regs;
/* Number of FP regs remaining. */
int __fp_left;
/* Pointer to GP regs followed by stack parameters. */
char *__gp_regs;
} __gnuc_va_list;
#ifdef __mips64
#define __va_reg_size 8
#else
#define __va_reg_size 4
#endif
enum {
__no_type_class = -1,
__void_type_class,
__integer_type_class,
__char_type_class,
__enumeral_type_class,
__boolean_type_class,
__pointer_type_class,
__reference_type_class,
__offset_type_class,
__real_type_class,
__complex_type_class,
__function_type_class,
__method_type_class,
__record_type_class,
__union_type_class,
__array_type_class,
__string_type_class,
__set_type_class,
__file_type_class,
__lang_type_class
};
#else /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
typedef char * __gnuc_va_list;
#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#endif /* not __GNUC_VA_LIST */
/* If this is for internal libc use, don't define anything but
......@@ -43,10 +87,19 @@ typedef char * __gnuc_va_list;
#endif
#ifdef _STDARG_H
#if defined (__mips_eabi) && ! defined (__mips_soft_float)
#define va_start(__AP, __LASTARG) \
(__AP.__gp_regs = ((char *) __builtin_next_arg (__LASTARG) \
- (__builtin_args_info (2) < 8 \
? (8 - __builtin_args_info (2)) * __va_reg_size \
: 0)), \
__AP.__fp_left = 8 - __builtin_args_info (3), \
__AP.__fp_regs = __AP.__gp_regs - __AP.__fp_left * __va_reg_size)
#else /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#define va_start(__AP, __LASTARG) \
(__AP = (__gnuc_va_list) __builtin_next_arg (__LASTARG))
#else
#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#else /* ! _STDARG_H */
#define va_alist __builtin_va_alist
#ifdef __mips64
/* This assumes that `long long int' is always a 64 bit type. */
......@@ -54,21 +107,68 @@ typedef char * __gnuc_va_list;
#else
#define va_dcl int __builtin_va_alist; __va_ellipsis
#endif
#if defined (__mips_eabi) && ! defined (__mips_soft_float)
#define va_start(__AP) \
(__AP.__gp_regs = ((char *) __builtin_next_arg () \
- (__builtin_args_info (2) < 8 \
? (8 - __builtin_args_info (2)) * __va_reg_size \
: 8)), \
__AP.__fp_left = 8 - __builtin_args_info (3), \
__AP.__fp_regs = __AP.__gp_regs - __AP.__fp_left * __va_reg_size)
/* Need alternate code for _MIPS_SIM_ABI64. */
#if defined(_MIPS_SIM) && (_MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32)
#elif defined(_MIPS_SIM) && (_MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32)
#define va_start(__AP) \
(__AP = (__gnuc_va_list) __builtin_next_arg () \
+ (__builtin_args_info (2) >= 8 ? -8 : 0))
#else
#define va_start(__AP) __AP = (char *) &__builtin_va_alist
#endif
#endif
#endif /* ! _STDARG_H */
#ifndef va_end
void va_end (__gnuc_va_list); /* Defined in libgcc.a */
#endif
#define va_end(__AP) ((void)0)
#if defined (__mips_eabi) && ! defined (__mips_soft_float)
#ifdef __mips64
#define __va_next_addr(__AP, __type) \
((__builtin_classify_type (*(__type *) 0) == __real_type_class \
&& __AP.__fp_left > 0) \
? (--__AP.__fp_left, (__AP.__fp_regs += 8) - 8) \
: (__AP.__gp_regs += __va_reg_size) - __va_reg_size)
#else
#define __va_next_addr(__AP, __type) \
((__builtin_classify_type (*(__type *) 0) == __real_type_class \
&& __AP.__fp_left > 0) \
? (--__AP.__fp_left, (__AP.__fp_regs += 8) - 8) \
: (((__builtin_classify_type (* (__type *) 0) < record_type_class \
&& __alignof__ (__type) > 4) \
? __AP.__gp_regs = (__AP.__gp_regs + 8 - 1) & -8), \
(__AP.__gp_regs += __va_reg_size) - __va_reg_size))
#endif
#ifdef __MIPSEB__
#define va_arg(__AP, __type) \
((__va_rounded_size (__type) <= __va_reg_size) \
? *(__type *) (void *) (__va_next_addr (__AP, __type) \
+ __va_reg_size \
- sizeof (__type)) \
: (__builtin_classify_type (*(__type *) 0) >= __record_type_class \
? **(__type **) (void *) (__va_next_addr (__AP, __type) \
+ __va_reg_size \
- sizeof (char *)) \
: *(__type *) (void *) __va_next_addr (__AP, __type)))
#else
#define va_arg(__AP, __type) \
(__builtin_classify_type (* (__type *) 0) >= __record_type_class \
? **(__type **) (void *) __va_next_addr (__AP, __type) \
: *(__type *) (void *) __va_next_addr (__AP, __type))
#endif
#else /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
/* We cast to void * and then to TYPE * because this avoids
a warning about increasing the alignment requirement. */
/* The __mips64 cases are reversed from the 32 bit cases, because the standard
......@@ -106,5 +206,6 @@ void va_end (__gnuc_va_list); /* Defined in libgcc.a */
+ __va_rounded_size(__type))))[-1]
#endif
#endif
#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
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