From 293a36ebf10d89b7bc994e18a4d01b84b6eb91b7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 16 Oct 1996 02:33:42 +0000 Subject: [PATCH] Add support for MIPS EABI From-SVN: r12967 --- gcc/config/mips/abi64.h | 131 ++++++++++++++++++++++++++++++++-------- gcc/config/mips/mips.c | 107 ++++++++++++++++++++++++-------- gcc/config/mips/mips.h | 19 ++++-- gcc/ginclude/va-mips.h | 109 +++++++++++++++++++++++++++++++-- 4 files changed, 307 insertions(+), 59 deletions(-) diff --git a/gcc/config/mips/abi64.h b/gcc/config/mips/abi64.h index 9e1a4b98537..df6eec664c5 100644 --- a/gcc/config/mips/abi64.h +++ b/gcc/config/mips/abi64.h @@ -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 diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index f32117b94da..29a53ac760c 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -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= */ 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, "%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 diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 19abb47f781..8d2a6147857 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -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); \ diff --git a/gcc/ginclude/va-mips.h b/gcc/ginclude/va-mips.h index 7841f255aa1..c8c84ee9b91 100644 --- a/gcc/ginclude/va-mips.h +++ b/gcc/ginclude/va-mips.h @@ -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) */ -- 2.30.2