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. */ ...@@ -26,11 +26,14 @@ Boston, MA 02111-1307, USA. */
{ "abi=", &mips_abi_string }, { "abi=", &mips_abi_string },
#undef STACK_BOUNDARY #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 #undef MIPS_STACK_ALIGN
#define MIPS_STACK_ALIGN(LOC) \ #define MIPS_STACK_ALIGN(LOC) \
(mips_abi == ABI_32 ? ((LOC)+7) & ~7 : ((LOC)+15) & ~15) ((mips_abi == ABI_32 || mips_abi == ABI_EABI) \
? ((LOC) + 7) & ~7 \
: ((LOC) + 15) & ~15)
#undef GP_ARG_LAST #undef GP_ARG_LAST
#define GP_ARG_LAST (mips_abi == ABI_32 ? GP_REG_FIRST + 7 : GP_REG_FIRST + 11) #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. */ ...@@ -78,13 +81,16 @@ Boston, MA 02111-1307, USA. */
? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \ ? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \
&& int_size_in_bytes (TYPE) < (PARM_BOUNDARY / BITS_PER_UNIT))\ && int_size_in_bytes (TYPE) < (PARM_BOUNDARY / BITS_PER_UNIT))\
: (GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY \ : (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)) ? downward : upward))
#undef RETURN_IN_MEMORY #undef RETURN_IN_MEMORY
#define RETURN_IN_MEMORY(TYPE) \ #define RETURN_IN_MEMORY(TYPE) \
(mips_abi == ABI_32 \ (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 (); extern struct rtx_def *mips_function_value ();
#undef FUNCTION_VALUE #undef FUNCTION_VALUE
...@@ -95,29 +101,78 @@ extern struct rtx_def *mips_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 For stdarg, we do not need to save the current argument, because it
is a real argument. */ is a real argument. */
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ #define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
{ if (mips_abi != ABI_32 \ { int mips_off = (! current_function_varargs) && (! (CUM).last_arg_fp); \
&& ((CUM).arg_words \ int mips_fp_off = (! current_function_varargs) && ((CUM).last_arg_fp); \
< (MAX_ARGS_IN_REGISTERS - ! current_function_varargs))) \ 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 \ int mips_save_gp_regs = \
= (MAX_ARGS_IN_REGISTERS - (CUM).arg_words \ MAX_ARGS_IN_REGISTERS - (CUM).arg_words - mips_off; \
- ! current_function_varargs) * UNITS_PER_WORD; \ 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 (! (NO_RTL)) \
{ \ { \
rtx mem = gen_rtx (MEM, BLKmode, virtual_incoming_args_rtx); \ if ((CUM).arg_words < MAX_ARGS_IN_REGISTERS - mips_off) \
/* 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 \ rtx ptr, mem; \
insn scheduler won't assume that these stores can't \ if (mips_abi != ABI_EABI) \
possibly overlap with the va_arg loads. */ \ ptr = virtual_incoming_args_rtx; \
if (BYTES_BIG_ENDIAN) \ else \
MEM_IN_STRUCT_P (mem) = 1; \ ptr = plus_constant (virtual_incoming_args_rtx, \
move_block_from_reg \ - (mips_save_gp_regs \
((CUM).arg_words + GP_ARG_FIRST + ! current_function_varargs, \ * UNITS_PER_WORD)); \
mem, \ mem = gen_rtx (MEM, BLKmode, ptr); \
(MAX_ARGS_IN_REGISTERS - (CUM).arg_words \ /* va_arg is an array access in this case, which causes \
- ! current_function_varargs), \ it to get MEM_IN_STRUCT_P set. We must set it here \
PRETEND_SIZE); \ 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 (); ...@@ -125,6 +180,32 @@ extern struct rtx_def *mips_function_value ();
/* ??? Should disable for mips_abi == ABI32. */ /* ??? Should disable for mips_abi == ABI32. */
#define STRICT_ARGUMENT_NAMING #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. */ /* ??? Unimplemented stuff follows. */
/* ??? Add support for 16 byte/128 bit long doubles here when /* ??? Add support for 16 byte/128 bit long doubles here when
......
...@@ -201,7 +201,7 @@ enum mips_abi_type mips_abi; ...@@ -201,7 +201,7 @@ enum mips_abi_type mips_abi;
/* Strings to hold which cpu and instruction set architecture to use. */ /* Strings to hold which cpu and instruction set architecture to use. */
char *mips_cpu_string; /* for -mcpu=<xxx> */ char *mips_cpu_string; /* for -mcpu=<xxx> */
char *mips_isa_string; /* for -mips{1,2,3,4} */ 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. */ /* If TRUE, we split addresses into their high and low parts in the RTL. */
int mips_split_addresses; int mips_split_addresses;
...@@ -500,7 +500,7 @@ mips_const_double_ok (op, mode) ...@@ -500,7 +500,7 @@ mips_const_double_ok (op, mode)
return TRUE; return TRUE;
/* ??? li.s does not work right with SGI's Irix 6 assembler. */ /* ??? 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; return FALSE;
REAL_VALUE_FROM_CONST_DOUBLE (d, op); REAL_VALUE_FROM_CONST_DOUBLE (d, op);
...@@ -3031,11 +3031,17 @@ function_arg_advance (cum, mode, type, named) ...@@ -3031,11 +3031,17 @@ function_arg_advance (cum, mode, type, named)
break; break;
case SFmode: case SFmode:
cum->arg_words++; if (mips_abi == ABI_EABI && ! TARGET_SOFT_FLOAT)
cum->fp_arg_words++;
else
cum->arg_words++;
break; break;
case DFmode: 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; break;
case DImode: case DImode:
...@@ -3065,6 +3071,7 @@ function_arg (cum, mode, type, named) ...@@ -3065,6 +3071,7 @@ function_arg (cum, mode, type, named)
rtx ret; rtx ret;
int regbase = -1; int regbase = -1;
int bias = 0; int bias = 0;
int *arg_words = &cum->arg_words;
int struct_p = ((type != (tree)0) int struct_p = ((type != (tree)0)
&& (TREE_CODE (type) == RECORD_TYPE && (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)); || TREE_CODE (type) == UNION_TYPE));
...@@ -3075,6 +3082,7 @@ function_arg (cum, mode, type, named) ...@@ -3075,6 +3082,7 @@ function_arg (cum, mode, type, named)
cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
type, named); type, named);
cum->last_arg_fp = 0;
switch (mode) switch (mode)
{ {
case SFmode: case SFmode:
...@@ -3091,13 +3099,28 @@ function_arg (cum, mode, type, named) ...@@ -3091,13 +3099,28 @@ function_arg (cum, mode, type, named)
bias = 1; 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 else
regbase = (TARGET_SOFT_FLOAT || ! named ? GP_ARG_FIRST : FP_ARG_FIRST); regbase = (TARGET_SOFT_FLOAT || ! named ? GP_ARG_FIRST : FP_ARG_FIRST);
break; break;
case DFmode: case DFmode:
if (! TARGET_64BIT) 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) if (mips_abi == ABI_32)
regbase = ((cum->gp_reg_found regbase = ((cum->gp_reg_found
|| TARGET_SOFT_FLOAT || TARGET_SOFT_FLOAT
...@@ -3105,6 +3128,14 @@ function_arg (cum, mode, type, named) ...@@ -3105,6 +3128,14 @@ function_arg (cum, mode, type, named)
|| cum->arg_number >= 2) || cum->arg_number >= 2)
? GP_ARG_FIRST ? GP_ARG_FIRST
: FP_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 else
regbase = (TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT || ! named regbase = (TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT || ! named
? GP_ARG_FIRST : FP_ARG_FIRST); ? GP_ARG_FIRST : FP_ARG_FIRST);
...@@ -3118,9 +3149,8 @@ function_arg (cum, mode, type, named) ...@@ -3118,9 +3149,8 @@ function_arg (cum, mode, type, named)
/* Drops through. */ /* Drops through. */
case BLKmode: case BLKmode:
if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD 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); cum->arg_words += (cum->arg_words & 1);
regbase = GP_ARG_FIRST; regbase = GP_ARG_FIRST;
break; break;
...@@ -3137,7 +3167,7 @@ function_arg (cum, mode, type, named) ...@@ -3137,7 +3167,7 @@ function_arg (cum, mode, type, named)
regbase = GP_ARG_FIRST; regbase = GP_ARG_FIRST;
} }
if (cum->arg_words >= MAX_ARGS_IN_REGISTERS) if (*arg_words >= MAX_ARGS_IN_REGISTERS)
{ {
if (TARGET_DEBUG_E_MODE) if (TARGET_DEBUG_E_MODE)
fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : ""); fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : "");
...@@ -3150,8 +3180,8 @@ function_arg (cum, mode, type, named) ...@@ -3150,8 +3180,8 @@ function_arg (cum, mode, type, named)
abort (); abort ();
if (! type || TREE_CODE (type) != RECORD_TYPE || mips_abi == ABI_32 if (! type || TREE_CODE (type) != RECORD_TYPE || mips_abi == ABI_32
|| ! named) || mips_abi == ABI_EABI || ! named)
ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias); ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
else else
{ {
/* The Irix 6 n32/n64 ABIs say that if any 64 bit chunk of the /* 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) ...@@ -3169,7 +3199,7 @@ function_arg (cum, mode, type, named)
break; break;
if (! field) if (! field)
ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias); ret = gen_rtx (REG, mode, regbase + *arg_words + bias);
else else
{ {
/* Now handle the special case by returning a PARALLEL /* Now handle the special case by returning a PARALLEL
...@@ -3188,15 +3218,15 @@ function_arg (cum, mode, type, named) ...@@ -3188,15 +3218,15 @@ function_arg (cum, mode, type, named)
backend to allow DImode values in fp registers. */ backend to allow DImode values in fp registers. */
chunks = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_WORD; chunks = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_WORD;
if (chunks + cum->arg_words + bias > MAX_ARGS_IN_REGISTERS) if (chunks + *arg_words + bias > MAX_ARGS_IN_REGISTERS)
chunks = MAX_ARGS_IN_REGISTERS - cum->arg_words - bias; chunks = MAX_ARGS_IN_REGISTERS - *arg_words - bias;
/* assign_parms checks the mode of ENTRY_PARM, so we must /* assign_parms checks the mode of ENTRY_PARM, so we must
use the actual mode here. */ use the actual mode here. */
ret = gen_rtx (PARALLEL, mode, rtvec_alloc (chunks)); ret = gen_rtx (PARALLEL, mode, rtvec_alloc (chunks));
bitpos = 0; bitpos = 0;
regno = regbase + cum->arg_words + bias; regno = regbase + *arg_words + bias;
field = TYPE_FIELDS (type); field = TYPE_FIELDS (type);
for (i = 0; i < chunks; i++) for (i = 0; i < chunks; i++)
{ {
...@@ -3227,7 +3257,7 @@ function_arg (cum, mode, type, named) ...@@ -3227,7 +3257,7 @@ function_arg (cum, mode, type, named)
} }
if (TARGET_DEBUG_E_MODE) 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]" : ""); struct_p ? ", [struct]" : "");
/* The following is a hack in order to pass 1 byte structures /* The following is a hack in order to pass 1 byte structures
...@@ -3250,11 +3280,11 @@ function_arg (cum, mode, type, named) ...@@ -3250,11 +3280,11 @@ function_arg (cum, mode, type, named)
calling convention for now. */ calling convention for now. */
if (struct_p && int_size_in_bytes (type) < UNITS_PER_WORD 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 rtx amount = GEN_INT (BITS_PER_WORD
- int_size_in_bytes (type) * BITS_PER_UNIT); - 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) if (TARGET_64BIT)
cum->adjust[ cum->num_adjusts++ ] = gen_ashldi3 (reg, reg, amount); cum->adjust[ cum->num_adjusts++ ] = gen_ashldi3 (reg, reg, amount);
else else
...@@ -3279,7 +3309,8 @@ function_arg_partial_nregs (cum, mode, type, named) ...@@ -3279,7 +3309,8 @@ function_arg_partial_nregs (cum, mode, type, named)
if ((mode == BLKmode if ((mode == BLKmode
|| GET_MODE_CLASS (mode) != MODE_COMPLEX_INT || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
|| GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) || 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; int words;
if (mode == BLKmode) if (mode == BLKmode)
...@@ -3299,7 +3330,8 @@ function_arg_partial_nregs (cum, mode, type, named) ...@@ -3299,7 +3330,8 @@ function_arg_partial_nregs (cum, mode, type, named)
} }
else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1 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) if (TARGET_DEBUG_E_MODE)
fprintf (stderr, "function_arg_partial_nregs = 1\n"); fprintf (stderr, "function_arg_partial_nregs = 1\n");
...@@ -3402,11 +3434,13 @@ override_options () ...@@ -3402,11 +3434,13 @@ override_options ()
else if (! strcmp (mips_abi_string, "64") else if (! strcmp (mips_abi_string, "64")
|| ! strcmp (mips_abi_string, "n64")) || ! strcmp (mips_abi_string, "n64"))
mips_abi = ABI_64; mips_abi = ABI_64;
else if (! strcmp (mips_abi_string, "eabi"))
mips_abi = ABI_EABI;
else else
error ("bad value (%s) for -mabi= switch", mips_abi_string); error ("bad value (%s) for -mabi= switch", mips_abi_string);
/* A specified ISA defaults the ABI if it was not specified. */ /* 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) if (mips_isa <= 2)
mips_abi = ABI_32; mips_abi = ABI_32;
...@@ -3414,7 +3448,7 @@ override_options () ...@@ -3414,7 +3448,7 @@ override_options ()
mips_abi = ABI_64; mips_abi = ABI_64;
} }
/* A specified ABI defaults the ISA if it was not specified. */ /* 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) if (mips_abi == ABI_32)
mips_isa = 1; mips_isa = 1;
...@@ -4506,7 +4540,7 @@ mips_asm_file_start (stream) ...@@ -4506,7 +4540,7 @@ mips_asm_file_start (stream)
/* Start a section, so that the first .popsection directive is guaranteed /* Start a section, so that the first .popsection directive is guaranteed
to have a previously defined section to pop back to. */ 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"); fprintf (stream, "\t.section\t.text\n");
/* This code exists so that we can put all externs before all symbol /* This code exists so that we can put all externs before all symbol
...@@ -4853,7 +4887,7 @@ compute_frame_size (size) ...@@ -4853,7 +4887,7 @@ compute_frame_size (size)
for leaf routines (total_size == extra_size) to save the gp reg. 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 The gp reg is callee saved in the 64 bit ABI, so all routines must
save the gp reg. */ 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; total_size = extra_size = 0;
else if (TARGET_ABICALLS) else if (TARGET_ABICALLS)
{ {
...@@ -5857,7 +5891,8 @@ mips_function_value (valtype, func) ...@@ -5857,7 +5891,8 @@ mips_function_value (valtype, func)
/* ??? How should we return complex float? */ /* ??? How should we return complex float? */
if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
reg = FP_RETURN; 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 /* A struct with only one or two floating point fields is returned in
the floating point registers. */ the floating point registers. */
...@@ -5916,6 +5951,30 @@ mips_function_value (valtype, func) ...@@ -5916,6 +5951,30 @@ mips_function_value (valtype, func)
return gen_rtx (REG, mode, reg); 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 #endif
/* This function returns the register class required for a secondary /* This function returns the register class required for a secondary
......
...@@ -82,7 +82,8 @@ enum processor_type { ...@@ -82,7 +82,8 @@ enum processor_type {
enum mips_abi_type { enum mips_abi_type {
ABI_32, ABI_32,
ABI_N32, ABI_N32,
ABI_64 ABI_64,
ABI_EABI
}; };
#ifndef MIPS_ABI_DEFAULT #ifndef MIPS_ABI_DEFAULT
...@@ -166,6 +167,7 @@ extern void final_prescan_insn (); ...@@ -166,6 +167,7 @@ extern void final_prescan_insn ();
extern struct rtx_def * function_arg (); extern struct rtx_def * function_arg ();
extern void function_arg_advance (); extern void function_arg_advance ();
extern int function_arg_partial_nregs (); extern int function_arg_partial_nregs ();
extern int function_arg_pass_by_reference ();
extern void function_epilogue (); extern void function_epilogue ();
extern void function_prologue (); extern void function_prologue ();
extern void gen_conditional_branch (); extern void gen_conditional_branch ();
...@@ -803,6 +805,8 @@ while (0) ...@@ -803,6 +805,8 @@ while (0)
%{mgp32:-U__mips64} %{mgp64:-D__mips64} \ %{mgp32:-U__mips64} %{mgp64:-D__mips64} \
%{msingle-float:%{!msoft-float:-D__mips_single_float}} \ %{msingle-float:%{!msoft-float:-D__mips_single_float}} \
%{m4650:%{!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}} \ %{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}} \ %{EL:-UMIPSEB -U_MIPSEB -U__MIPSEB -U__MIPSEB__ -D_MIPSEL -D__MIPSEL -D__MIPSEL__ %{!ansi:-DMIPSEL}} \
%(subtarget_cpp_spec) " %(subtarget_cpp_spec) "
...@@ -1914,7 +1918,7 @@ extern struct mips_frame_info current_frame_info; ...@@ -1914,7 +1918,7 @@ extern struct mips_frame_info current_frame_info;
&& ((TO) == FRAME_POINTER_REGNUM \ && ((TO) == FRAME_POINTER_REGNUM \
|| (TO) == STACK_POINTER_REGNUM)) \ || (TO) == STACK_POINTER_REGNUM)) \
(OFFSET) = (current_frame_info.total_size \ (OFFSET) = (current_frame_info.total_size \
- (mips_abi != ABI_32 \ - ((mips_abi != ABI_32 && mips_abi != ABI_EABI) \
? current_function_pretend_args_size \ ? current_function_pretend_args_size \
: 0)); \ : 0)); \
else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM \ else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM \
...@@ -2112,6 +2116,8 @@ typedef struct mips_args { ...@@ -2112,6 +2116,8 @@ typedef struct mips_args {
int gp_reg_found; /* whether a gp register was found yet */ int gp_reg_found; /* whether a gp register was found yet */
int arg_number; /* argument number */ int arg_number; /* argument number */
int arg_words; /* # total words the arguments take */ 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 */ int num_adjusts; /* number of adjustments made */
/* Adjustments made to args pass in regs. */ /* Adjustments made to args pass in regs. */
/* ??? The size is doubled to work around a /* ??? The size is doubled to work around a
...@@ -2507,7 +2513,7 @@ typedef struct mips_args { ...@@ -2507,7 +2513,7 @@ typedef struct mips_args {
/* ??? Reject combining an address with a register for the MIPS \ /* ??? Reject combining an address with a register for the MIPS \
64 bit ABI, because the SGI assembler can not handle this. */ \ 64 bit ABI, because the SGI assembler can not handle this. */ \
if (!TARGET_DEBUG_A_MODE \ if (!TARGET_DEBUG_A_MODE \
&& mips_abi == ABI_32 \ && (mips_abi == ABI_32 || mips_abi == ABI_EABI) \
&& CONSTANT_ADDRESS_P (xplus1) \ && CONSTANT_ADDRESS_P (xplus1) \
&& ! mips_split_addresses \ && ! mips_split_addresses \
&& (!TARGET_EMBEDDED_PIC \ && (!TARGET_EMBEDDED_PIC \
...@@ -2537,7 +2543,7 @@ typedef struct mips_args { ...@@ -2537,7 +2543,7 @@ typedef struct mips_args {
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH \ || GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH \
|| (GET_CODE (X) == CONST \ || (GET_CODE (X) == CONST \
&& ! (flag_pic && pic_address_needs_scratch (X)) \ && ! (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))) && (!HALF_PIC_P () || !HALF_PIC_ADDRESS_P (X)))
/* Define this, so that when PIC, reload won't try to reload invalid /* Define this, so that when PIC, reload won't try to reload invalid
...@@ -2556,7 +2562,8 @@ typedef struct mips_args { ...@@ -2556,7 +2562,8 @@ typedef struct mips_args {
#define LEGITIMATE_CONSTANT_P(X) \ #define LEGITIMATE_CONSTANT_P(X) \
((GET_CODE (X) != CONST_DOUBLE \ ((GET_CODE (X) != CONST_DOUBLE \
|| mips_const_double_ok (X, GET_MODE (X))) \ || 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 /* 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 memory address for an operand of mode MODE. WIN will be a C
...@@ -2618,7 +2625,7 @@ typedef struct mips_args { ...@@ -2618,7 +2625,7 @@ typedef struct mips_args {
if (GET_CODE (xinsn) == CONST \ if (GET_CODE (xinsn) == CONST \
&& ((flag_pic && pic_address_needs_scratch (xinsn)) \ && ((flag_pic && pic_address_needs_scratch (xinsn)) \
/* ??? SGI's Irix 6 assembler can't handle CONST. */ \ /* ??? 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 ptr_reg = gen_reg_rtx (Pmode); \
rtx constant = XEXP (XEXP (xinsn, 0), 1); \ rtx constant = XEXP (XEXP (xinsn, 0), 1); \
......
...@@ -13,7 +13,51 @@ ...@@ -13,7 +13,51 @@
#ifndef __GNUC_VA_LIST #ifndef __GNUC_VA_LIST
#define __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; typedef char * __gnuc_va_list;
#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#endif /* not __GNUC_VA_LIST */ #endif /* not __GNUC_VA_LIST */
/* If this is for internal libc use, don't define anything but /* If this is for internal libc use, don't define anything but
...@@ -43,10 +87,19 @@ typedef char * __gnuc_va_list; ...@@ -43,10 +87,19 @@ typedef char * __gnuc_va_list;
#endif #endif
#ifdef _STDARG_H #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) \ #define va_start(__AP, __LASTARG) \
(__AP = (__gnuc_va_list) __builtin_next_arg (__LASTARG)) (__AP = (__gnuc_va_list) __builtin_next_arg (__LASTARG))
#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#else #else /* ! _STDARG_H */
#define va_alist __builtin_va_alist #define va_alist __builtin_va_alist
#ifdef __mips64 #ifdef __mips64
/* This assumes that `long long int' is always a 64 bit type. */ /* This assumes that `long long int' is always a 64 bit type. */
...@@ -54,21 +107,68 @@ typedef char * __gnuc_va_list; ...@@ -54,21 +107,68 @@ typedef char * __gnuc_va_list;
#else #else
#define va_dcl int __builtin_va_alist; __va_ellipsis #define va_dcl int __builtin_va_alist; __va_ellipsis
#endif #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. */ /* 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) \ #define va_start(__AP) \
(__AP = (__gnuc_va_list) __builtin_next_arg () \ (__AP = (__gnuc_va_list) __builtin_next_arg () \
+ (__builtin_args_info (2) >= 8 ? -8 : 0)) + (__builtin_args_info (2) >= 8 ? -8 : 0))
#else #else
#define va_start(__AP) __AP = (char *) &__builtin_va_alist #define va_start(__AP) __AP = (char *) &__builtin_va_alist
#endif #endif
#endif #endif /* ! _STDARG_H */
#ifndef va_end #ifndef va_end
void va_end (__gnuc_va_list); /* Defined in libgcc.a */ void va_end (__gnuc_va_list); /* Defined in libgcc.a */
#endif #endif
#define va_end(__AP) ((void)0) #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 /* We cast to void * and then to TYPE * because this avoids
a warning about increasing the alignment requirement. */ a warning about increasing the alignment requirement. */
/* The __mips64 cases are reversed from the 32 bit cases, because the standard /* 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 */ ...@@ -106,5 +206,6 @@ void va_end (__gnuc_va_list); /* Defined in libgcc.a */
+ __va_rounded_size(__type))))[-1] + __va_rounded_size(__type))))[-1]
#endif #endif
#endif #endif
#endif /* ! (defined (__mips_eabi) && ! defined (__mips_soft_float)) */
#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */ #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