{ "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)
? ((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
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; \
+ } \
+ } \
} \
} \
}
/* ??? 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
/* 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;
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);
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:
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));
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:
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
|| 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);
/* 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;
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]" : "");
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
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
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++)
{
}
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
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
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)
}
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");
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;
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;
/* 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
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)
{
/* ??? 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. */
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
enum mips_abi_type {
ABI_32,
ABI_N32,
- ABI_64
+ ABI_64,
+ ABI_EABI
};
#ifndef MIPS_ABI_DEFAULT
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 ();
%{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) "
&& ((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 \
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
/* ??? 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 \
|| 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
#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
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); \
#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
#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. */
#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
+ __va_rounded_size(__type))))[-1]
#endif
#endif
+#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */