Commit a38e0142 by Sandra Loosemore Committed by Sandra Loosemore

Fix up MIPS16 hard float and add support for complex.

2007-05-23  Sandra Loosemore  <sandra@codesourcery.com>
	    Nigel Stephens  <nigel@mips.com>
	    Richard Sandiford  <richard@codesourcery.com>

	gcc/
	Fix up MIPS16 hard float and add support for complex.

	* config/mips/mips.h (TARGET_HARD_FLOAT_ABI): New.
	(TARGET_SOFT_FLOAT_ABI): New.
	(TARGET_CPU_CPP_BUILTINS): Define __mips_hard_float and
	__mips_soft_float to reflect the ABI in use, not whether the
	FPU is directly accessible (e.g., in MIPS16 mode).
	(UNITS_PER_HWFPVALUE): Use TARGET_SOFT_FLOAT_ABI.
	(UNITS_PER_FPVALUE): Likewise.

	* config/mips/mips.c (mips_expand_call): Remove redundant
	TARGET_MIPS16 check.
	(mips_arg_regno): New.
	(function_arg_advance): When setting bits in cum->fp_code for
	MIPS16, don't subtract 1 from cum->arg_number, since it is now
	zero-based.
	(function_arg): Use mips_arg_regno.
	(mips_return_mode_in_fpr_p): New.
	(mips16_call_stub_mode_suffix): New.
	(mips16_cfun_returns_in_fpr_p): New.
	(mips_save_reg_p): Use mips16_cfun_returns_in_fpr_p.
	(mips_output_function_prologue): Test mips16_hard_float, not
	!TARGET_SOFT_FLOAT, to decide when a function stub is required.
	(mips_expand_epilogue): Call MIPS16 helper routines to copy
	return value into a floating-point register.
	(mips_can_use_return_insn): Use mips16_cfun_returns_in_fpr_p.
	(mips_function_value): Rewrite to use mips_return_mode_in_fpr_p.
	(mips16_fp_args): Handle MIPS32r2 ISA which supports
	TARGET_FLOAT64, and use mfhc1/mthc1 to copy the most significant
	word of double arguments from or to the high bits of 64-bit
	floating point registers.
	(build_mips16_function_stub): Fill in DECL_RESULT for stubdecl.
	(mips16_fpret_double): New helper function.
	(build_mips16_call_stub): Use mips16_return_mode_in_fpr_p.  Add
	support for complex modes.  Fill in DECL_RESULT for stubdecl.
	(mips_init_libfuncs): Remove redundant TARGET_MIPS16 check.

	* config/mips/mips16.S 
	(RET, ARG1, ARG2): New.
	(MERGE_GPRf, MERGE_GPRt): New.
	(DELAYt, DELAYf): New.
	(MOVE_SF_BYTE0, MOVE_SI_BYTE0): New.
	(MOVE_SF_BYTE4, MOVE_SF_BYTE8): New.
	(MOVE_DF_BYTE0, MOVE_DF_BYTE8): New.
	(MOVE_SF_RET, MOVE_SC_RET, MOVE_DF_RET, MOVE_DC_RET, MOVE_SI_RET): New.
	(SFOP): Renamed to...
	(OPSF3): This, and macro-ified.  Updated all uses.
	(SFOP2): Renamed to...
	(OPSF2): This, and macro-ified.  Updated all uses.
	(SFCMP): Renamed to...
	(CMPSF): This, and macro-ified.  Updated all uses.
	(SFREVCMP): Renamed to...
	(REVCMPSF): This, and macro-ified.  Updated all uses.
	(__mips16_floatsisf, __mips16_fix_truncsfsi): Macro-ified.
	(LDDBL1, LDDBL2, RETDBL): Deleted.
	(DFOP): Renamed to...
	(OPDF3): This, and macro-ified.  Updated all uses.
	(DFOP2): Renamed to...
	(OPDF2): This, and macro-ified.  Updated all uses.
	(__mips16_extendsfdf2, __mips16_truncdfsf2): Macro-ified.
	(DFCMP): Renamed to...
	(CMPDF): This, and macro-ified.  Updated all uses.
	(DFREVCMP): Renamed to...
	(REVCMPDF): This, and macro-ified.  Updated all uses.
	(__mips16_floatsidf, __mips16_fix_truncdfsi): Macro-ified.
	(RET_FUNCTION): New.
	(__mips16_ret_sf, __mips16_ret_df): Macro-ified.
	(__mips16_ret_sc, __mips16_ret_dc): New.
	(STUB_ARGS_0, STUB_ARGS_1, STUB_ARGS_5, STUB_ARGS_9, STUB_ARGS_2,
	STUB_ARGS_6, STUB_ARGS_10): New.
	(CALL_STUB_NO_RET): New.
	(__mips16_call_stub_1): Macro-ified.
	(__mips16_call_stub_5): Macro-ified.
	(__mips16_call_stub_2): Macro-ified.
	(__mips16_call_stub_6): Macro-ified.
	(__mips16_call_stub_9): Macro-ified.
	(__mips16_call_stub_10): Macro-ified.
	(CALL_STUB_RET): New.
	(__mips16_call_stub_sf_0): Macro-ified.
	(__mips16_call_stub_sf_1): Macro-ified.
	(__mips16_call_stub_sf_5): Macro-ified.
	(__mips16_call_stub_sf_2): Macro-ified.
	(__mips16_call_stub_sf_6): Macro-ified.
	(__mips16_call_stub_sf_9): Macro-ified.
	(__mips16_call_stub_sf_10): Macro-ified.
	(__mips16_call_stub_df_0): Macro-ified.
	(__mips16_call_stub_df_1): Macro-ified.
	(__mips16_call_stub_df_5): Macro-ified.
	(__mips16_call_stub_df_2): Macro-ified.
	(__mips16_call_stub_df_6): Macro-ified.
	(__mips16_call_stub_df_9): Macro-ified.
	(__mips16_call_stub_df_10): Macro-ified.
	(__mips16_call_stub_sc_0): New.
	(__mips16_call_stub_sc_1): New.
	(__mips16_call_stub_sc_5): New.
	(__mips16_call_stub_sc_2): New.
	(__mips16_call_stub_sc_6): New.
	(__mips16_call_stub_sc_9): New.
	(__mips16_call_stub_sc_10): New.
	(__mips16_call_stub_dc_0): New.
	(__mips16_call_stub_dc_1): New.
	(__mips16_call_stub_dc_5): New.
	(__mips16_call_stub_dc_2): New.
	(__mips16_call_stub_dc_6): New.
	(__mips16_call_stub_dc_9): New.
	(__mips16_call_stub_dc_10): New.
	
	* config/mips/t-elf (LIB1ASMFUNCS): Add MIPS16 floating-point stubs.
	* config/mips/t-isa3264 (LIB1ASMFUNCS): Likewise.
	* config/mips/t-r2900 (LIB1ASMFUNCS): Likewise.

	gcc/testsuite/
	* gcc.target/mips/inter/mips16_stubs_1_main.c: New.
	* gcc.target/mips/inter/mips16_stubs_1_x.c: New.
	* gcc.target/mips/inter/mips16_stubs_1_y.c: New.
	* gcc.target/mips/inter/mips16-inter.exp: New.


Co-Authored-By: Nigel Stephens <nigel@mips.com>
Co-Authored-By: Richard Sandiford <richard@codesourcery.com>

From-SVN: r124999
parent 70c1e033
2007-05-23 Sandra Loosemore <sandra@codesourcery.com>
Nigel Stephens <nigel@mips.com>
Richard Sandiford <richard@codesourcery.com>
Fix up MIPS16 hard float and add support for complex.
* config/mips/mips.h (TARGET_HARD_FLOAT_ABI): New.
(TARGET_SOFT_FLOAT_ABI): New.
(TARGET_CPU_CPP_BUILTINS): Define __mips_hard_float and
__mips_soft_float to reflect the ABI in use, not whether the
FPU is directly accessible (e.g., in MIPS16 mode).
(UNITS_PER_HWFPVALUE): Use TARGET_SOFT_FLOAT_ABI.
(UNITS_PER_FPVALUE): Likewise.
* config/mips/mips.c (mips_expand_call): Remove redundant
TARGET_MIPS16 check.
(mips_arg_regno): New.
(function_arg_advance): When setting bits in cum->fp_code for
MIPS16, don't subtract 1 from cum->arg_number, since it is now
zero-based.
(function_arg): Use mips_arg_regno.
(mips_return_mode_in_fpr_p): New.
(mips16_call_stub_mode_suffix): New.
(mips16_cfun_returns_in_fpr_p): New.
(mips_save_reg_p): Use mips16_cfun_returns_in_fpr_p.
(mips_output_function_prologue): Test mips16_hard_float, not
!TARGET_SOFT_FLOAT, to decide when a function stub is required.
(mips_expand_epilogue): Call MIPS16 helper routines to copy
return value into a floating-point register.
(mips_can_use_return_insn): Use mips16_cfun_returns_in_fpr_p.
(mips_function_value): Rewrite to use mips_return_mode_in_fpr_p.
(mips16_fp_args): Handle MIPS32r2 ISA which supports
TARGET_FLOAT64, and use mfhc1/mthc1 to copy the most significant
word of double arguments from or to the high bits of 64-bit
floating point registers.
(build_mips16_function_stub): Fill in DECL_RESULT for stubdecl.
(mips16_fpret_double): New helper function.
(build_mips16_call_stub): Use mips16_return_mode_in_fpr_p. Add
support for complex modes. Fill in DECL_RESULT for stubdecl.
(mips_init_libfuncs): Remove redundant TARGET_MIPS16 check.
* config/mips/mips16.S
(RET, ARG1, ARG2): New.
(MERGE_GPRf, MERGE_GPRt): New.
(DELAYt, DELAYf): New.
(MOVE_SF_BYTE0, MOVE_SI_BYTE0): New.
(MOVE_SF_BYTE4, MOVE_SF_BYTE8): New.
(MOVE_DF_BYTE0, MOVE_DF_BYTE8): New.
(MOVE_SF_RET, MOVE_SC_RET, MOVE_DF_RET, MOVE_DC_RET, MOVE_SI_RET): New.
(SFOP): Renamed to...
(OPSF3): This, and macro-ified. Updated all uses.
(SFOP2): Renamed to...
(OPSF2): This, and macro-ified. Updated all uses.
(SFCMP): Renamed to...
(CMPSF): This, and macro-ified. Updated all uses.
(SFREVCMP): Renamed to...
(REVCMPSF): This, and macro-ified. Updated all uses.
(__mips16_floatsisf, __mips16_fix_truncsfsi): Macro-ified.
(LDDBL1, LDDBL2, RETDBL): Deleted.
(DFOP): Renamed to...
(OPDF3): This, and macro-ified. Updated all uses.
(DFOP2): Renamed to...
(OPDF2): This, and macro-ified. Updated all uses.
(__mips16_extendsfdf2, __mips16_truncdfsf2): Macro-ified.
(DFCMP): Renamed to...
(CMPDF): This, and macro-ified. Updated all uses.
(DFREVCMP): Renamed to...
(REVCMPDF): This, and macro-ified. Updated all uses.
(__mips16_floatsidf, __mips16_fix_truncdfsi): Macro-ified.
(RET_FUNCTION): New.
(__mips16_ret_sf, __mips16_ret_df): Macro-ified.
(__mips16_ret_sc, __mips16_ret_dc): New.
(STUB_ARGS_0, STUB_ARGS_1, STUB_ARGS_5, STUB_ARGS_9, STUB_ARGS_2,
STUB_ARGS_6, STUB_ARGS_10): New.
(CALL_STUB_NO_RET): New.
(__mips16_call_stub_1): Macro-ified.
(__mips16_call_stub_5): Macro-ified.
(__mips16_call_stub_2): Macro-ified.
(__mips16_call_stub_6): Macro-ified.
(__mips16_call_stub_9): Macro-ified.
(__mips16_call_stub_10): Macro-ified.
(CALL_STUB_RET): New.
(__mips16_call_stub_sf_0): Macro-ified.
(__mips16_call_stub_sf_1): Macro-ified.
(__mips16_call_stub_sf_5): Macro-ified.
(__mips16_call_stub_sf_2): Macro-ified.
(__mips16_call_stub_sf_6): Macro-ified.
(__mips16_call_stub_sf_9): Macro-ified.
(__mips16_call_stub_sf_10): Macro-ified.
(__mips16_call_stub_df_0): Macro-ified.
(__mips16_call_stub_df_1): Macro-ified.
(__mips16_call_stub_df_5): Macro-ified.
(__mips16_call_stub_df_2): Macro-ified.
(__mips16_call_stub_df_6): Macro-ified.
(__mips16_call_stub_df_9): Macro-ified.
(__mips16_call_stub_df_10): Macro-ified.
(__mips16_call_stub_sc_0): New.
(__mips16_call_stub_sc_1): New.
(__mips16_call_stub_sc_5): New.
(__mips16_call_stub_sc_2): New.
(__mips16_call_stub_sc_6): New.
(__mips16_call_stub_sc_9): New.
(__mips16_call_stub_sc_10): New.
(__mips16_call_stub_dc_0): New.
(__mips16_call_stub_dc_1): New.
(__mips16_call_stub_dc_5): New.
(__mips16_call_stub_dc_2): New.
(__mips16_call_stub_dc_6): New.
(__mips16_call_stub_dc_9): New.
(__mips16_call_stub_dc_10): New.
* config/mips/t-elf (LIB1ASMFUNCS): Add MIPS16 floating-point stubs.
* config/mips/t-isa3264 (LIB1ASMFUNCS): Likewise.
* config/mips/t-r2900 (LIB1ASMFUNCS): Likewise.
2007-05-23 Ian Lance Taylor <iant@google.com>
* doc/invoke.texi (Invoking GCC): Document that the order of the
......
......@@ -3490,8 +3490,7 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
mips_load_call_address (addr, orig_addr, sibcall_p);
}
if (TARGET_MIPS16
&& mips16_hard_float
if (mips16_hard_float
&& build_mips16_call_stub (result, addr, args_size,
aux == 0 ? 0 : (int) GET_MODE (aux)))
return;
......@@ -3878,6 +3877,24 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
}
/* INFO describes an argument that is passed in a single-register value.
Return the register it uses, assuming that FPRs are available if
HARD_FLOAT_P. */
static unsigned int
mips_arg_regno (const struct mips_arg_info *info, bool hard_float_p)
{
if (!info->fpr_p || !hard_float_p)
return GP_ARG_FIRST + info->reg_offset;
else if (mips_abi == ABI_32 && TARGET_DOUBLE_FLOAT && info->reg_offset > 0)
/* In o32, the second argument is always passed in $f14
for TARGET_DOUBLE_FLOAT, regardless of whether the
first argument was a word or doubleword. */
return FP_ARG_FIRST + 2;
else
return FP_ARG_FIRST + info->reg_offset;
}
/* Implement FUNCTION_ARG_ADVANCE. */
void
......@@ -3895,7 +3912,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
for an explanation of what this code does. It assumes the O32
ABI, which passes at most 2 arguments in float registers. */
if (cum->arg_number < 2 && info.fpr_p)
cum->fp_code += (mode == SFmode ? 1 : 2) << ((cum->arg_number - 1) * 2);
cum->fp_code += (mode == SFmode ? 1 : 2) << (cum->arg_number * 2);
if (mips_abi != ABI_EABI || !info.fpr_p)
cum->num_gprs = info.reg_offset + info.reg_words;
......@@ -4032,15 +4049,7 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
}
}
if (!info.fpr_p)
return gen_rtx_REG (mode, GP_ARG_FIRST + info.reg_offset);
else if (mips_abi == ABI_32 && TARGET_DOUBLE_FLOAT && info.reg_offset > 0)
/* In o32, the second argument is always passed in $f14
for TARGET_DOUBLE_FLOAT, regardless of whether the
first argument was a word or doubleword. */
return gen_rtx_REG (mode, FP_ARG_FIRST + 2);
else
return gen_rtx_REG (mode, FP_ARG_FIRST + info.reg_offset);
return gen_rtx_REG (mode, mips_arg_regno (&info, TARGET_HARD_FLOAT));
}
......@@ -6303,6 +6312,51 @@ mips_global_pointer (void)
}
/* Return true if the function return value MODE will get returned in a
floating-point register. */
static bool
mips_return_mode_in_fpr_p (enum machine_mode mode)
{
return ((GET_MODE_CLASS (mode) == MODE_FLOAT
|| GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
&& GET_MODE_UNIT_SIZE (mode) <= UNITS_PER_HWFPVALUE);
}
/* Return a two-character string representing a function floating-point
return mode, used to name MIPS16 function stubs. */
static const char *
mips16_call_stub_mode_suffix (enum machine_mode mode)
{
if (mode == SFmode)
return "sf";
else if (mode == DFmode)
return "df";
else if (mode == SCmode)
return "sc";
else if (mode == DCmode)
return "dc";
else if (mode == V2SFmode)
return "df";
else
gcc_unreachable ();
}
/* Return true if the current function returns its value in a floating-point
register in MIPS16 mode. */
static bool
mips16_cfun_returns_in_fpr_p (void)
{
tree return_type = DECL_RESULT (current_function_decl);
return (mips16_hard_float
&& !aggregate_value_p (return_type, current_function_decl)
&& mips_return_mode_in_fpr_p (DECL_MODE (return_type)));
}
/* Return true if the current function must save REGNO. */
static bool
......@@ -6337,10 +6391,6 @@ mips_save_reg_p (unsigned int regno)
if (TARGET_MIPS16)
{
tree return_type;
return_type = DECL_RESULT (current_function_decl);
/* $18 is a special case in mips16 code. It may be used to call
a function which returns a floating point value, but it is
marked in call_used_regs. */
......@@ -6351,10 +6401,7 @@ mips_save_reg_p (unsigned int regno)
value into the floating point registers if the return value is
floating point. */
if (regno == GP_REG_FIRST + 31
&& mips16_hard_float
&& !aggregate_value_p (return_type, current_function_decl)
&& GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
&& GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE)
&& mips16_cfun_returns_in_fpr_p ())
return true;
}
......@@ -6739,7 +6786,7 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
floating point arguments. The linker will arrange for any 32-bit
functions to call this stub, which will then jump to the 16-bit
function proper. */
if (TARGET_MIPS16 && !TARGET_SOFT_FLOAT
if (mips16_hard_float
&& current_function_args_info.fp_code != 0)
build_mips16_function_stub (file);
......@@ -7069,6 +7116,33 @@ mips_expand_epilogue (int sibcall_p)
emit_jump_insn (gen_return ());
return;
}
/* In mips16 mode, if the return value should go into a floating-point
register, we need to call a helper routine to copy it over. */
if (mips16_cfun_returns_in_fpr_p ())
{
char *name;
rtx func;
rtx insn;
rtx retval;
rtx call;
tree id;
tree return_type;
enum machine_mode return_mode;
return_type = DECL_RESULT (current_function_decl);
return_mode = DECL_MODE (return_type);
name = ACONCAT (("__mips16_ret_",
mips16_call_stub_mode_suffix (return_mode),
NULL));
id = get_identifier (name);
func = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (id));
retval = gen_rtx_REG (return_mode, GP_RETURN);
call = gen_call_value_internal (retval, func, const0_rtx);
insn = emit_call_insn (call);
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), retval);
}
/* Split the frame into two. STEP1 is the amount of stack we should
deallocate before restoring the registers. STEP2 is the amount we
......@@ -7175,24 +7249,16 @@ mips_expand_epilogue (int sibcall_p)
int
mips_can_use_return_insn (void)
{
tree return_type;
if (! reload_completed)
return 0;
if (regs_ever_live[31] || current_function_profile)
return 0;
return_type = DECL_RESULT (current_function_decl);
/* In mips16 mode, a function which returns a floating point value
/* In mips16 mode, a function that returns a floating point value
needs to arrange to copy the return value into the floating point
registers. */
if (TARGET_MIPS16
&& mips16_hard_float
&& ! aggregate_value_p (return_type, current_function_decl)
&& GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
&& GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE)
if (mips16_cfun_returns_in_fpr_p ())
return 0;
if (cfun->machine->frame.initialized)
......@@ -7617,23 +7683,25 @@ mips_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
return gen_rtx_REG (mode, GP_RETURN);
}
if ((GET_MODE_CLASS (mode) == MODE_FLOAT
|| GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
&& GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
return gen_rtx_REG (mode, FP_RETURN);
/* Handle long doubles for n32 & n64. */
if (mode == TFmode)
return mips_return_fpr_pair (mode,
DImode, 0,
DImode, GET_MODE_SIZE (mode) / 2);
if (!TARGET_MIPS16)
{
/* Handle long doubles for n32 & n64. */
if (mode == TFmode)
return mips_return_fpr_pair (mode,
DImode, 0,
DImode, GET_MODE_SIZE (mode) / 2);
if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
&& GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)
return mips_return_fpr_pair (mode,
GET_MODE_INNER (mode), 0,
GET_MODE_INNER (mode),
GET_MODE_SIZE (mode) / 2);
if (mips_return_mode_in_fpr_p (mode))
{
if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
return mips_return_fpr_pair (mode,
GET_MODE_INNER (mode), 0,
GET_MODE_INNER (mode),
GET_MODE_SIZE (mode) / 2);
else
return gen_rtx_REG (mode, FP_RETURN);
}
}
return gen_rtx_REG (mode, GP_RETURN);
}
......@@ -7978,6 +8046,7 @@ mips16_fp_args (FILE *file, int fp_code, int from_fp_p)
const char *s;
int gparg, fparg;
unsigned int f;
CUMULATIVE_ARGS cum;
/* This code only works for the original 32-bit ABI and the O64 ABI. */
gcc_assert (TARGET_OLDABI);
......@@ -7986,43 +8055,50 @@ mips16_fp_args (FILE *file, int fp_code, int from_fp_p)
s = "mfc1";
else
s = "mtc1";
gparg = GP_ARG_FIRST;
fparg = FP_ARG_FIRST;
init_cumulative_args (&cum, NULL, NULL);
for (f = (unsigned int) fp_code; f != 0; f >>= 2)
{
enum machine_mode mode;
struct mips_arg_info info;
if ((f & 3) == 1)
{
if ((fparg & 1) != 0)
++fparg;
fprintf (file, "\t%s\t%s,%s\n", s,
reg_names[gparg], reg_names[fparg]);
}
mode = SFmode;
else if ((f & 3) == 2)
{
if (TARGET_64BIT)
fprintf (file, "\td%s\t%s,%s\n", s,
reg_names[gparg], reg_names[fparg]);
else
{
if ((fparg & 1) != 0)
++fparg;
if (TARGET_BIG_ENDIAN)
fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
reg_names[gparg], reg_names[fparg + 1], s,
reg_names[gparg + 1], reg_names[fparg]);
else
fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
reg_names[gparg], reg_names[fparg], s,
reg_names[gparg + 1], reg_names[fparg + 1]);
++gparg;
++fparg;
}
}
mode = DFmode;
else
gcc_unreachable ();
++gparg;
++fparg;
mips_arg_info (&cum, mode, NULL, true, &info);
gparg = mips_arg_regno (&info, false);
fparg = mips_arg_regno (&info, true);
if (mode == SFmode)
fprintf (file, "\t%s\t%s,%s\n", s,
reg_names[gparg], reg_names[fparg]);
else if (TARGET_64BIT)
fprintf (file, "\td%s\t%s,%s\n", s,
reg_names[gparg], reg_names[fparg]);
else if (ISA_HAS_MXHC1)
/* -mips32r2 -mfp64 */
fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n",
s,
reg_names[gparg + (WORDS_BIG_ENDIAN ? 1 : 0)],
reg_names[fparg],
from_fp_p ? "mfhc1" : "mthc1",
reg_names[gparg + (WORDS_BIG_ENDIAN ? 0 : 1)],
reg_names[fparg]);
else if (TARGET_BIG_ENDIAN)
fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
reg_names[gparg], reg_names[fparg + 1], s,
reg_names[gparg + 1], reg_names[fparg]);
else
fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
reg_names[gparg], reg_names[fparg], s,
reg_names[gparg + 1], reg_names[fparg + 1]);
function_arg_advance (&cum, mode, NULL, true);
}
}
......@@ -8049,6 +8125,7 @@ build_mips16_function_stub (FILE *file)
stubdecl = build_decl (FUNCTION_DECL, stubid,
build_function_type (void_type_node, NULL_TREE));
DECL_SECTION_NAME (stubdecl) = build_string (strlen (secname), secname);
DECL_RESULT (stubdecl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
fprintf (file, "\t# Stub function for %s (", current_function_name ());
need_comma = 0;
......@@ -8122,6 +8199,47 @@ struct mips16_stub
static struct mips16_stub *mips16_stubs;
/* Emit code to return a double value from a mips16 stub. GPREG is the
first GP reg to use, FPREG is the first FP reg to use. */
static void
mips16_fpret_double (int gpreg, int fpreg)
{
if (TARGET_64BIT)
fprintf (asm_out_file, "\tdmfc1\t%s,%s\n",
reg_names[gpreg], reg_names[fpreg]);
else if (TARGET_FLOAT64)
{
fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
reg_names[gpreg + WORDS_BIG_ENDIAN],
reg_names[fpreg]);
fprintf (asm_out_file, "\tmfhc1\t%s,%s\n",
reg_names[gpreg + !WORDS_BIG_ENDIAN],
reg_names[fpreg]);
}
else
{
if (TARGET_BIG_ENDIAN)
{
fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
reg_names[gpreg + 0],
reg_names[fpreg + 1]);
fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
reg_names[gpreg + 1],
reg_names[fpreg + 0]);
}
else
{
fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
reg_names[gpreg + 0],
reg_names[fpreg + 0]);
fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
reg_names[gpreg + 1],
reg_names[fpreg + 1]);
}
}
}
/* Build a call stub for a mips16 call. A stub is needed if we are
passing any floating point values which should go into the floating
point registers. If we are, and the call turns out to be to a
......@@ -8143,7 +8261,7 @@ static struct mips16_stub *mips16_stubs;
int
build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
{
int fpret;
int fpret = 0;
const char *fnname;
char *secname, *stubname;
struct mips16_stub *l;
......@@ -8153,14 +8271,13 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
/* We don't need to do anything if we aren't in mips16 mode, or if
we were invoked with the -msoft-float option. */
if (! TARGET_MIPS16 || ! mips16_hard_float)
if (!mips16_hard_float)
return 0;
/* Figure out whether the value might come back in a floating point
register. */
fpret = (retval != 0
&& GET_MODE_CLASS (GET_MODE (retval)) == MODE_FLOAT
&& GET_MODE_SIZE (GET_MODE (retval)) <= UNITS_PER_FPVALUE);
if (retval)
fpret = mips_return_mode_in_fpr_p (GET_MODE (retval));
/* We don't need to do anything if there were no floating point
arguments and the value will not be returned in a floating point
......@@ -8178,11 +8295,6 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
require more sophisticated support. */
gcc_assert (TARGET_OLDABI);
/* We can only handle SFmode and DFmode floating point return
values. */
if (fpret)
gcc_assert (GET_MODE (retval) == SFmode || GET_MODE (retval) == DFmode);
/* If we're calling via a function pointer, then we must always call
via a stub. There are magic stubs provided in libgcc.a for each
of the required cases. Each of them expects the function address
......@@ -8197,11 +8309,14 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
/* ??? If this code is modified to support other ABI's, we need
to handle PARALLEL return values here. */
sprintf (buf, "__mips16_call_stub_%s%d",
(fpret
? (GET_MODE (retval) == SFmode ? "sf_" : "df_")
: ""),
fp_code);
if (fpret)
sprintf (buf, "__mips16_call_stub_%s_%d",
mips16_call_stub_mode_suffix (GET_MODE (retval)),
fp_code);
else
sprintf (buf, "__mips16_call_stub_%d",
fp_code);
id = get_identifier (buf);
stub_fn = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (id));
......@@ -8277,6 +8392,7 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
stubdecl = build_decl (FUNCTION_DECL, stubid,
build_function_type (void_type_node, NULL_TREE));
DECL_SECTION_NAME (stubdecl) = build_string (strlen (secname), secname);
DECL_RESULT (stubdecl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
fprintf (asm_out_file, "\t# Stub function to call %s%s (",
(fpret
......@@ -8339,6 +8455,27 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
if (GET_MODE (retval) == SFmode)
fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
reg_names[GP_REG_FIRST + 2], reg_names[FP_REG_FIRST + 0]);
else if (GET_MODE (retval) == SCmode)
{
fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
reg_names[GP_REG_FIRST + 2],
reg_names[FP_REG_FIRST + 0]);
fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
reg_names[GP_REG_FIRST + 3],
reg_names[FP_REG_FIRST + MAX_FPRS_PER_FMT]);
}
else if (GET_MODE (retval) == DFmode
|| GET_MODE (retval) == V2SFmode)
{
mips16_fpret_double (GP_REG_FIRST + 2, FP_REG_FIRST + 0);
}
else if (GET_MODE (retval) == DCmode)
{
mips16_fpret_double (GP_REG_FIRST + 2,
FP_REG_FIRST + 0);
mips16_fpret_double (GP_REG_FIRST + 4,
FP_REG_FIRST + MAX_FPRS_PER_FMT);
}
else
{
if (TARGET_BIG_ENDIAN)
......@@ -9190,7 +9327,7 @@ mips_init_libfuncs (void)
set_optab_libfunc (smod_optab, SImode, "__vr4120_modsi3");
}
if (TARGET_MIPS16 && mips16_hard_float)
if (mips16_hard_float)
{
set_optab_libfunc (add_optab, SFmode, "__mips16_addsf3");
set_optab_libfunc (sub_optab, SFmode, "__mips16_subsf3");
......
......@@ -288,6 +288,11 @@ extern const struct mips_rtx_cost_data *mips_cost;
#define TARGET_OLDABI (mips_abi == ABI_32 || mips_abi == ABI_O64)
#define TARGET_NEWABI (mips_abi == ABI_N32 || mips_abi == ABI_64)
/* Similar to TARGET_HARD_FLOAT and TARGET_SOFT_FLOAT, but reflect the ABI
in use rather than whether the FPU is directly accessible. */
#define TARGET_HARD_FLOAT_ABI (TARGET_HARD_FLOAT || mips16_hard_float)
#define TARGET_SOFT_FLOAT_ABI (!TARGET_HARD_FLOAT_ABI)
/* IRIX specific stuff. */
#define TARGET_IRIX 0
#define TARGET_IRIX6 0
......@@ -406,9 +411,11 @@ extern const struct mips_rtx_cost_data *mips_cost;
builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS64"); \
} \
\
if (TARGET_HARD_FLOAT) \
/* These defines reflect the ABI in use, not whether the \
FPU is directly accessible. */ \
if (TARGET_HARD_FLOAT_ABI) \
builtin_define ("__mips_hard_float"); \
else if (TARGET_SOFT_FLOAT) \
else \
builtin_define ("__mips_soft_float"); \
\
if (TARGET_SINGLE_FLOAT) \
......@@ -1033,12 +1040,12 @@ extern const struct mips_rtx_cost_data *mips_cost;
/* The largest size of value that can be held in floating-point
registers and moved with a single instruction. */
#define UNITS_PER_HWFPVALUE \
(TARGET_SOFT_FLOAT ? 0 : MAX_FPRS_PER_FMT * UNITS_PER_FPREG)
(TARGET_SOFT_FLOAT_ABI ? 0 : MAX_FPRS_PER_FMT * UNITS_PER_FPREG)
/* The largest size of value that can be held in floating-point
registers. */
#define UNITS_PER_FPVALUE \
(TARGET_SOFT_FLOAT ? 0 \
(TARGET_SOFT_FLOAT_ABI ? 0 \
: TARGET_SINGLE_FLOAT ? UNITS_PER_FPREG \
: LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT)
......
......@@ -49,69 +49,204 @@ Boston, MA 02110-1301, USA. */
#define ENDFN(NAME) .end NAME
/* Single precision math. */
/* ARG1
The FPR that holds the first floating-point argument.
/* This macro defines a function which loads two single precision
values, performs an operation, and returns the single precision
result. */
ARG2
The FPR that holds the second floating-point argument.
#define SFOP(NAME, OPCODE) \
RET
The FPR that holds a floating-point return value. */
#define RET $f0
#define ARG1 $f12
#ifdef __mips64
#define ARG2 $f13
#else
#define ARG2 $f14
#endif
/* Set 64-bit register GPR so that its high 32 bits contain HIGH_FPR
and so that its low 32 bits contain LOW_FPR. */
#define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR) \
.set noat; \
mfc1 GPR, HIGH_FPR; \
mfc1 $1, LOW_FPR; \
dsll GPR, GPR, 32; \
or GPR, GPR, $1; \
.set at
/* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of
GPR to LOW_FPR. */
#define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR) \
.set noat; \
dsrl $1, GPR, 32; \
mtc1 GPR, LOW_FPR; \
mtc1 $1, HIGH_FPR; \
.set at
/* Jump to T, and use "OPCODE, OP2" to implement a delayed move. */
#define DELAYt(T, OPCODE, OP2) \
.set noreorder; \
jr T; \
OPCODE, OP2; \
.set reorder
/* Use "OPCODE. OP2" and jump to T. */
#define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
/* MOVE_SF_BYTE0(D)
Move the first single-precision floating-point argument between
GPRs and FPRs.
MOVE_SI_BYTE0(D)
Likewise the first single-precision integer argument.
MOVE_SF_BYTE4(D)
Move the second single-precision floating-point argument between
GPRs and FPRs, given that the first argument occupies 4 bytes.
MOVE_SF_BYTE8(D)
Move the second single-precision floating-point argument between
GPRs and FPRs, given that the first argument occupies 8 bytes.
MOVE_DF_BYTE0(D)
Move the first double-precision floating-point argument between
GPRs and FPRs.
MOVE_DF_BYTE8(D)
Likewise the second double-precision floating-point argument.
MOVE_SF_RET(D, T)
Likewise a single-precision floating-point return value,
then jump to T.
MOVE_SC_RET(D, T)
Likewise a complex single-precision floating-point return value.
MOVE_DF_RET(D, T)
Likewise a double-precision floating-point return value.
MOVE_DC_RET(D, T)
Likewise a complex double-precision floating-point return value.
MOVE_SI_RET(D, T)
Likewise a single-precision integer return value.
The D argument is "t" to move to FPRs and "f" to move from FPRs.
The return macros may assume that the target of the jump does not
use a floating-point register. */
#define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
#define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
#if defined(__mips64) && defined(__MIPSEB__)
#define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T
#elif defined(__mips64)
/* The high 32 bits of $2 correspond to the second word in memory;
i.e. the imaginary part. */
#define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
#elif __mips_fpr == 64
#define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
#else
#define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
#endif
#if defined(__mips64)
#define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
#define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13
#define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13
#else
#define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
#define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14
#define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14
#endif
#define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D)
#if defined(__mips64)
#define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12
#define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
#define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
#define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
#elif __mips_fpr == 64 && defined(__MIPSEB__)
#define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
#define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
#define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
#define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, T)
#elif __mips_fpr == 64
#define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
#define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
#define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
#define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, T)
#elif defined(__MIPSEB__)
/* FPRs are little-endian. */
#define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
#define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14
#define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0)
#define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T)
#else
#define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13
#define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15
#define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
#define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T)
#endif
/* Single-precision math. */
/* Define a function NAME that loads two single-precision values,
performs FPU operation OPCODE on them, and returns the single-
precision result. */
#define OPSF3(NAME, OPCODE) \
STARTFN (NAME); \
.set noreorder; \
mtc1 $4,$f0; \
mtc1 $5,$f2; \
nop; \
OPCODE $f0,$f0,$f2; \
mfc1 $2,$f0; \
j $31; \
nop; \
.set reorder; \
MOVE_SF_BYTE0 (t); \
MOVE_SF_BYTE4 (t); \
OPCODE RET,ARG1,ARG2; \
MOVE_SF_RET (f, $31); \
ENDFN (NAME)
#ifdef L_m16addsf3
SFOP(__mips16_addsf3, add.s)
OPSF3 (__mips16_addsf3, add.s)
#endif
#ifdef L_m16subsf3
SFOP(__mips16_subsf3, sub.s)
OPSF3 (__mips16_subsf3, sub.s)
#endif
#ifdef L_m16mulsf3
SFOP(__mips16_mulsf3, mul.s)
OPSF3 (__mips16_mulsf3, mul.s)
#endif
#ifdef L_m16divsf3
SFOP(__mips16_divsf3, div.s)
OPSF3 (__mips16_divsf3, div.s)
#endif
#define SFOP2(NAME, OPCODE) \
/* Define a function NAME that loads a single-precision value,
performs FPU operation OPCODE on it, and returns the single-
precision result. */
#define OPSF2(NAME, OPCODE) \
STARTFN (NAME); \
.set noreorder; \
mtc1 $4,$f0; \
nop; \
OPCODE $f0,$f0; \
mfc1 $2,$f0; \
j $31; \
nop; \
.set reorder; \
MOVE_SF_BYTE0 (t); \
OPCODE RET,ARG1; \
MOVE_SF_RET (f, $31); \
ENDFN (NAME)
#ifdef L_m16negsf2
SFOP2(__mips16_negsf2, neg.s)
OPSF2 (__mips16_negsf2, neg.s)
#endif
#ifdef L_m16abssf2
SFOP2(__mips16_abssf2, abs.s)
OPSF2 (__mips16_abssf2, abs.s)
#endif
/* Single precision comparisons. */
/* Single-precision comparisons. */
/* This macro defines a function which loads two single precision
values, performs a floating point comparison, and returns the
specified values according to whether the comparison is true or
false. */
/* Define a function NAME that loads two single-precision values,
performs floating point comparison OPCODE, and returns TRUE or
FALSE depending on the result. */
#define SFCMP(NAME, OPCODE, TRUE, FALSE) \
#define CMPSF(NAME, OPCODE, TRUE, FALSE) \
STARTFN (NAME); \
mtc1 $4,$f0; \
mtc1 $5,$f2; \
OPCODE $f0,$f2; \
MOVE_SF_BYTE0 (t); \
MOVE_SF_BYTE4 (t); \
OPCODE ARG1,ARG2; \
li $2,TRUE; \
bc1t 1f; \
li $2,FALSE; \
......@@ -119,13 +254,13 @@ STARTFN (NAME); \
j $31; \
ENDFN (NAME)
/* This macro is like SFCMP, but it reverses the comparison. */
/* Like CMPSF, but reverse the comparison operands. */
#define SFREVCMP(NAME, OPCODE, TRUE, FALSE) \
#define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \
STARTFN (NAME); \
mtc1 $4,$f0; \
mtc1 $5,$f2; \
OPCODE $f2,$f0; \
MOVE_SF_BYTE0 (t); \
MOVE_SF_BYTE4 (t); \
OPCODE ARG2,ARG1; \
li $2,TRUE; \
bc1t 1f; \
li $2,FALSE; \
......@@ -134,189 +269,118 @@ STARTFN (NAME); \
ENDFN (NAME)
#ifdef L_m16eqsf2
SFCMP(__mips16_eqsf2, c.eq.s, 0, 1)
CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
#endif
#ifdef L_m16nesf2
SFCMP(__mips16_nesf2, c.eq.s, 0, 1)
CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
#endif
#ifdef L_m16gtsf2
SFREVCMP(__mips16_gtsf2, c.lt.s, 1, 0)
REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
#endif
#ifdef L_m16gesf2
SFREVCMP(__mips16_gesf2, c.le.s, 0, -1)
REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
#endif
#ifdef L_m16lesf2
SFCMP(__mips16_lesf2, c.le.s, 0, 1)
CMPSF (__mips16_lesf2, c.le.s, 0, 1)
#endif
#ifdef L_m16ltsf2
SFCMP(__mips16_ltsf2, c.lt.s, -1, 0)
CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
#endif
/* Single precision conversions. */
/* Single-precision conversions. */
#ifdef L_m16fltsisf
STARTFN (__mips16_floatsisf)
.set noreorder
mtc1 $4,$f0
nop
cvt.s.w $f0,$f0
mfc1 $2,$f0
j $31
nop
.set reorder
MOVE_SF_BYTE0 (t)
cvt.s.w RET,ARG1
MOVE_SF_RET (f, $31)
ENDFN (__mips16_floatsisf)
#endif
#ifdef L_m16fix_truncsfsi
STARTFN (__mips16_fix_truncsfsi)
.set noreorder
mtc1 $4,$f0
nop
trunc.w.s $f0,$f0,$4
mfc1 $2,$f0
j $31
nop
.set reorder
MOVE_SF_BYTE0 (t)
trunc.w.s RET,ARG1,$4
MOVE_SI_RET (f, $31)
ENDFN (__mips16_fix_truncsfsi)
#endif
#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
/* The double precision operations. We need to use different code
based on the preprocessor symbol __mips64, because the way in which
double precision values will change. Without __mips64, the value
is passed in two 32-bit registers. With __mips64, the value is
passed in a single 64-bit register. */
/* Double-precision math. */
/* Load the first double precision operand. */
/* Define a function NAME that loads two double-precision values,
performs FPU operation OPCODE on them, and returns the double-
precision result. */
#if defined(__mips64)
#define LDDBL1 dmtc1 $4,$f12
#elif defined(__mipsfp64)
#define LDDBL1 sw $4,0($29); sw $5,4($29); l.d $f12,0($29)
#elif defined(__MIPSEB__)
#define LDDBL1 mtc1 $4,$f13; mtc1 $5,$f12
#else
#define LDDBL1 mtc1 $4,$f12; mtc1 $5,$f13
#endif
/* Load the second double precision operand. */
#if defined(__mips64)
/* XXX this should be $6 for Algo arg passing model */
#define LDDBL2 dmtc1 $5,$f14
#elif defined(__mipsfp64)
#define LDDBL2 sw $6,8($29); sw $7,12($29); l.d $f14,8($29)
#elif defined(__MIPSEB__)
#define LDDBL2 mtc1 $6,$f15; mtc1 $7,$f14
#else
#define LDDBL2 mtc1 $6,$f14; mtc1 $7,$f15
#endif
/* Move the double precision return value to the right place. */
#if defined(__mips64)
#define RETDBL dmfc1 $2,$f0
#elif defined(__mipsfp64)
#define RETDBL s.d $f0,0($29); lw $2,0($29); lw $3,4($29)
#elif defined(__MIPSEB__)
#define RETDBL mfc1 $2,$f1; mfc1 $3,$f0
#else
#define RETDBL mfc1 $2,$f0; mfc1 $3,$f1
#endif
/* Double precision math. */
/* This macro defines a function which loads two double precision
values, performs an operation, and returns the double precision
result. */
#define DFOP(NAME, OPCODE) \
#define OPDF3(NAME, OPCODE) \
STARTFN (NAME); \
.set noreorder; \
LDDBL1; \
LDDBL2; \
nop; \
OPCODE $f0,$f12,$f14; \
RETDBL; \
j $31; \
nop; \
.set reorder; \
MOVE_DF_BYTE0 (t); \
MOVE_DF_BYTE8 (t); \
OPCODE RET,ARG1,ARG2; \
MOVE_DF_RET (f, $31); \
ENDFN (NAME)
#ifdef L_m16adddf3
DFOP(__mips16_adddf3, add.d)
OPDF3 (__mips16_adddf3, add.d)
#endif
#ifdef L_m16subdf3
DFOP(__mips16_subdf3, sub.d)
OPDF3 (__mips16_subdf3, sub.d)
#endif
#ifdef L_m16muldf3
DFOP(__mips16_muldf3, mul.d)
OPDF3 (__mips16_muldf3, mul.d)
#endif
#ifdef L_m16divdf3
DFOP(__mips16_divdf3, div.d)
OPDF3 (__mips16_divdf3, div.d)
#endif
#define DFOP2(NAME, OPCODE) \
/* Define a function NAME that loads a double-precision value,
performs FPU operation OPCODE on it, and returns the double-
precision result. */
#define OPDF2(NAME, OPCODE) \
STARTFN (NAME); \
.set noreorder; \
LDDBL1; \
nop; \
OPCODE $f0,$f12; \
RETDBL; \
j $31; \
nop; \
.set reorder; \
MOVE_DF_BYTE0 (t); \
OPCODE RET,ARG1; \
MOVE_DF_RET (f, $31); \
ENDFN (NAME)
#ifdef L_m16negdf2
DFOP2(__mips16_negdf2, neg.d)
OPDF2 (__mips16_negdf2, neg.d)
#endif
#ifdef L_m16absdf2
DFOP2(__mips16_absdf2, abs.d)
OPDF2 (__mips16_absdf2, abs.d)
#endif
/* Conversions between single and double precision. */
#ifdef L_m16extsfdf2
STARTFN (__mips16_extendsfdf2)
.set noreorder
mtc1 $4,$f12
nop
cvt.d.s $f0,$f12
RETDBL
j $31
nop
.set reorder
MOVE_SF_BYTE0 (t)
cvt.d.s RET,ARG1
MOVE_DF_RET (f, $31)
ENDFN (__mips16_extendsfdf2)
#endif
#ifdef L_m16trdfsf2
STARTFN (__mips16_truncdfsf2)
.set noreorder
LDDBL1
nop
cvt.s.d $f0,$f12
mfc1 $2,$f0
j $31
nop
.set reorder
MOVE_DF_BYTE0 (t)
cvt.s.d RET,ARG1
MOVE_SF_RET (f, $31)
ENDFN (__mips16_truncdfsf2)
#endif
/* Double precision comparisons. */
/* Double-precision comparisons. */
/* This macro defines a function which loads two double precision
values, performs a floating point comparison, and returns the
specified values according to whether the comparison is true or
false. */
/* Define a function NAME that loads two double-precision values,
performs floating point comparison OPCODE, and returns TRUE or
FALSE depending on the result. */
#define DFCMP(NAME, OPCODE, TRUE, FALSE) \
#define CMPDF(NAME, OPCODE, TRUE, FALSE) \
STARTFN (NAME); \
LDDBL1; \
LDDBL2; \
OPCODE $f12,$f14; \
MOVE_DF_BYTE0 (t); \
MOVE_DF_BYTE8 (t); \
OPCODE ARG1,ARG2; \
li $2,TRUE; \
bc1t 1f; \
li $2,FALSE; \
......@@ -324,13 +388,13 @@ STARTFN (NAME); \
j $31; \
ENDFN (NAME)
/* This macro is like DFCMP, but it reverses the comparison. */
/* Like CMPDF, but reverse the comparison operands. */
#define DFREVCMP(NAME, OPCODE, TRUE, FALSE) \
#define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \
STARTFN (NAME); \
LDDBL1; \
LDDBL2; \
OPCODE $f14,$f12; \
MOVE_DF_BYTE0 (t); \
MOVE_DF_BYTE8 (t); \
OPCODE ARG2,ARG1; \
li $2,TRUE; \
bc1t 1f; \
li $2,FALSE; \
......@@ -339,174 +403,125 @@ STARTFN (NAME); \
ENDFN (NAME)
#ifdef L_m16eqdf2
DFCMP(__mips16_eqdf2, c.eq.d, 0, 1)
CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
#endif
#ifdef L_m16nedf2
DFCMP(__mips16_nedf2, c.eq.d, 0, 1)
CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
#endif
#ifdef L_m16gtdf2
DFREVCMP(__mips16_gtdf2, c.lt.d, 1, 0)
REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
#endif
#ifdef L_m16gedf2
DFREVCMP(__mips16_gedf2, c.le.d, 0, -1)
REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
#endif
#ifdef L_m16ledf2
DFCMP(__mips16_ledf2, c.le.d, 0, 1)
CMPDF (__mips16_ledf2, c.le.d, 0, 1)
#endif
#ifdef L_m16ltdf2
DFCMP(__mips16_ltdf2, c.lt.d, -1, 0)
CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
#endif
/* Double precision conversions. */
/* Double-precision conversions. */
#ifdef L_m16fltsidf
STARTFN (__mips16_floatsidf)
.set noreorder
mtc1 $4,$f12
nop
cvt.d.w $f0,$f12
RETDBL
j $31
nop
.set reorder
MOVE_SI_BYTE0 (t)
cvt.d.w RET,ARG1
MOVE_DF_RET (f, $31)
ENDFN (__mips16_floatsidf)
#endif
#ifdef L_m16fix_truncdfsi
STARTFN (__mips16_fix_truncdfsi)
.set noreorder
LDDBL1
nop
trunc.w.d $f0,$f12,$4
mfc1 $2,$f0
j $31
nop
.set reorder
MOVE_DF_BYTE0 (t)
trunc.w.d RET,ARG1,$4
MOVE_SI_RET (f, $31)
ENDFN (__mips16_fix_truncdfsi)
#endif
#endif /* !__mips_single_float */
/* These functions are used to return floating point values from
mips16 functions. In this case we can put mtc1 in a jump delay slot,
because we know that the next instruction will not refer to a floating
point register. */
/* Define a function NAME that moves a return value of mode MODE from
FPRs to GPRs. */
#define RET_FUNCTION(NAME, MODE) \
STARTFN (NAME); \
MOVE_##MODE##_RET (t, $31); \
ENDFN (NAME)
#ifdef L_m16retsf
STARTFN (__mips16_ret_sf)
.set noreorder
j $31
mtc1 $2,$f0
.set reorder
ENDFN (__mips16_ret_sf)
RET_FUNCTION (__mips16_ret_sf, SF)
#endif
#ifdef L_m16retsc
RET_FUNCTION (__mips16_ret_sc, SC)
#endif
#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
#ifdef L_m16retdf
STARTFN (__mips16_ret_df)
.set noreorder
#if defined(__mips64)
j $31
dmtc1 $2,$f0
#elif defined(__mipsfp64)
sw $2,0($29)
sw $3,4($29)
l.d $f0,0($29)
#elif defined(__MIPSEB__)
mtc1 $2,$f1
j $31
mtc1 $3,$f0
#else
mtc1 $2,$f0
j $31
mtc1 $3,$f1
RET_FUNCTION (__mips16_ret_df, DF)
#endif
.set reorder
ENDFN (__mips16_ret_df)
#ifdef L_m16retdc
RET_FUNCTION (__mips16_ret_dc, DC)
#endif
#endif /* !__mips_single_float */
/* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
classify the first and second arguments as follows:
1: a single-precision argument
2: a double-precision argument
0: no argument, or not one of the above. */
#define STUB_ARGS_0 /* () */
#define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */
#define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */
#define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */
#define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */
#define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */
#define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */
/* These functions are used by 16-bit code when calling via a function
pointer. They must copy the floating point arguments from the gp
regs into the fp regs. The function to call will be in $2. The
exact set of floating point arguments to copy is encoded in the
function name; the final number is an fp_code, as described in
mips.h in the comment about CUMULATIVE_ARGS. */
pointer. They must copy the floating point arguments from the GPRs
to FPRs and then call function $2. */
#define CALL_STUB_NO_RET(NAME, CODE) \
STARTFN (NAME); \
STUB_ARGS_##CODE; \
jr $2; \
ENDFN (NAME)
#ifdef L_m16stub1
/* (float) */
STARTFN (__mips16_call_stub_1)
.set noreorder
mtc1 $4,$f12
j $2
nop
.set reorder
ENDFN (__mips16_call_stub_1)
CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
#endif
#ifdef L_m16stub5
/* (float, float) */
STARTFN (__mips16_call_stub_5)
.set noreorder
mtc1 $4,$f12
mtc1 $5,$f14
j $2
nop
.set reorder
ENDFN (__mips16_call_stub_5)
CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
#endif
#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
#ifdef L_m16stub2
/* (double) */
STARTFN (__mips16_call_stub_2)
.set noreorder
LDDBL1
j $2
nop
.set reorder
ENDFN (__mips16_call_stub_2)
CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
#endif
#ifdef L_m16stub6
/* (double, float) */
STARTFN (__mips16_call_stub_6)
.set noreorder
LDDBL1
mtc1 $6,$f14
j $2
nop
.set reorder
ENDFN (__mips16_call_stub_6)
CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
#endif
#ifdef L_m16stub9
/* (float, double) */
STARTFN (__mips16_call_stub_9)
.set noreorder
mtc1 $4,$f12
LDDBL2
j $2
nop
.set reorder
ENDFN (__mips16_call_stub_9)
CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
#endif
#ifdef L_m16stub10
/* (double, double) */
STARTFN (__mips16_call_stub_10)
.set noreorder
LDDBL1
LDDBL2
j $2
nop
.set reorder
ENDFN (__mips16_call_stub_10)
CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
#endif
#endif /* !__mips_single_float */
/* Now we have the same set of functions, except that this time the
function being called returns an SFmode value. The calling
function being called returns an SFmode, SCmode, DFmode or DCmode
value; we need to instantiate a set for each case. The calling
function will arrange to preserve $18, so these functions are free
to use it to hold the return address.
......@@ -517,223 +532,143 @@ STARTFN (__mips16_call_stub_10)
being called is 16 bits, in which case the copy is unnecessary;
however, it's faster to always do the copy. */
#define CALL_STUB_RET(NAME, CODE, MODE) \
STARTFN (NAME); \
move $18,$31; \
STUB_ARGS_##CODE; \
jalr $2; \
MOVE_##MODE##_RET (f, $18); \
ENDFN (NAME)
/* First, instantiate the single-float set. */
#ifdef L_m16stubsf0
/* () */
STARTFN (__mips16_call_stub_sf_0)
.set noreorder
move $18,$31
jal $2
nop
mfc1 $2,$f0
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_sf_0)
CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
#endif
#ifdef L_m16stubsf1
/* (float) */
STARTFN (__mips16_call_stub_sf_1)
.set noreorder
mtc1 $4,$f12
move $18,$31
jal $2
nop
mfc1 $2,$f0
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_sf_1)
CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
#endif
#ifdef L_m16stubsf5
/* (float, float) */
STARTFN (__mips16_call_stub_sf_5)
.set noreorder
mtc1 $4,$f12
mtc1 $5,$f14
move $18,$31
jal $2
nop
mfc1 $2,$f0
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_sf_5)
CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
#endif
#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
#ifdef L_m16stubsf2
/* (double) */
STARTFN (__mips16_call_stub_sf_2)
.set noreorder
LDDBL1
move $18,$31
jal $2
nop
mfc1 $2,$f0
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_sf_2)
CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
#endif
#ifdef L_m16stubsf6
/* (double, float) */
STARTFN (__mips16_call_stub_sf_6)
.set noreorder
LDDBL1
mtc1 $6,$f14
move $18,$31
jal $2
nop
mfc1 $2,$f0
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_sf_6)
CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
#endif
#ifdef L_m16stubsf9
/* (float, double) */
STARTFN (__mips16_call_stub_sf_9)
.set noreorder
mtc1 $4,$f12
LDDBL2
move $18,$31
jal $2
nop
mfc1 $2,$f0
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_sf_9)
CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
#endif
#ifdef L_m16stubsf10
/* (double, double) */
STARTFN (__mips16_call_stub_sf_10)
.set noreorder
LDDBL1
LDDBL2
move $18,$31
jal $2
nop
mfc1 $2,$f0
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_sf_10)
CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
#endif
#endif /* !__mips_single_float */
/* Now we have the same set of functions again, except that this time
the function being called returns an DFmode value. */
#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
#ifdef L_m16stubdf0
/* () */
STARTFN (__mips16_call_stub_df_0)
.set noreorder
move $18,$31
jal $2
nop
RETDBL
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_df_0)
CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
#endif
#ifdef L_m16stubdf1
/* (float) */
STARTFN (__mips16_call_stub_df_1)
.set noreorder
mtc1 $4,$f12
move $18,$31
jal $2
nop
RETDBL
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_df_1)
CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
#endif
#ifdef L_m16stubdf2
/* (double) */
STARTFN (__mips16_call_stub_df_2)
.set noreorder
LDDBL1
move $18,$31
jal $2
nop
RETDBL
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_df_2)
#ifdef L_m16stubdf5
CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
#endif
#ifdef L_m16stubdf5
/* (float, float) */
STARTFN (__mips16_call_stub_df_5)
.set noreorder
mtc1 $4,$f12
mtc1 $5,$f14
move $18,$31
jal $2
nop
RETDBL
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_df_5)
#ifdef L_m16stubdf2
CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
#endif
#ifdef L_m16stubdf6
/* (double, float) */
STARTFN (__mips16_call_stub_df_6)
.set noreorder
LDDBL1
mtc1 $6,$f14
move $18,$31
jal $2
nop
RETDBL
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_df_6)
CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
#endif
#ifdef L_m16stubdf9
/* (float, double) */
STARTFN (__mips16_call_stub_df_9)
.set noreorder
mtc1 $4,$f12
LDDBL2
move $18,$31
jal $2
nop
RETDBL
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_df_9)
CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
#endif
#ifdef L_m16stubdf10
/* (double, double) */
STARTFN (__mips16_call_stub_df_10)
.set noreorder
LDDBL1
LDDBL2
move $18,$31
jal $2
nop
RETDBL
j $18
nop
.set reorder
ENDFN (__mips16_call_stub_df_10)
CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
#endif
#endif /* !__mips_single_float */
/* Ho hum. Here we have the same set of functions again, this time
for when the function being called returns an SCmode value. */
#ifdef L_m16stubsc0
CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
#endif
#ifdef L_m16stubsc1
CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
#endif
#ifdef L_m16stubsc5
CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
#endif
#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
#ifdef L_m16stubsc2
CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
#endif
#ifdef L_m16stubsc6
CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
#endif
#ifdef L_m16stubsc9
CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
#endif
#ifdef L_m16stubsc10
CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
#endif
#endif /* !__mips_single_float */
/* Finally, another set of functions for DCmode. */
#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
#ifdef L_m16stubdc0
CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
#endif
#ifdef L_m16stubdc1
CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
#endif
#ifdef L_m16stubdc5
CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
#endif
#ifdef L_m16stubdc2
CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
#endif
#ifdef L_m16stubdc6
CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
#endif
#ifdef L_m16stubdc9
CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
#endif
#ifdef L_m16stubdc10
CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
#endif
#endif /* !__mips_single_float */
......@@ -19,11 +19,16 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m16mulsf3 _m16divsf3 \
_m16eqdf2 _m16nedf2 _m16gtdf2 _m16gedf2 _m16ledf2 _m16ltdf2 \
_m16fltsidf _m16fix_truncdfsi \
_m16retsf _m16retdf \
_m16retsc _m16retdc \
_m16stub1 _m16stub2 _m16stub5 _m16stub6 _m16stub9 _m16stub10 \
_m16stubsf0 _m16stubsf1 _m16stubsf2 _m16stubsf5 _m16stubsf6 \
_m16stubsf9 _m16stubsf10 \
_m16stubdf0 _m16stubdf1 _m16stubdf2 _m16stubdf5 _m16stubdf6 \
_m16stubdf9 _m16stubdf10
_m16stubdf9 _m16stubdf10 \
_m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \
_m16stubsc9 _m16stubsc10 \
_m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \
_m16stubdc9 _m16stubdc10
# We must build libgcc2.a with -G 0, in case the user wants to link
# without the $gp register.
......
......@@ -19,11 +19,16 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m16mulsf3 _m16divsf3 \
_m16eqdf2 _m16nedf2 _m16gtdf2 _m16gedf2 _m16ledf2 _m16ltdf2 \
_m16fltsidf _m16fix_truncdfsi \
_m16retsf _m16retdf \
_m16retsc _m16retdc \
_m16stub1 _m16stub2 _m16stub5 _m16stub6 _m16stub9 _m16stub10 \
_m16stubsf0 _m16stubsf1 _m16stubsf2 _m16stubsf5 _m16stubsf6 \
_m16stubsf9 _m16stubsf10 \
_m16stubdf0 _m16stubdf1 _m16stubdf2 _m16stubdf5 _m16stubdf6 \
_m16stubdf9 _m16stubdf10
_m16stubdf9 _m16stubdf10 \
_m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \
_m16stubsc9 _m16stubsc10 \
_m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \
_m16stubdc9 _m16stubdc10
# We must build libgcc2.a with -G 0, in case the user wants to link
# without the $gp register.
......
......@@ -7,11 +7,16 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m16mulsf3 _m16divsf3 \
_m16eqdf2 _m16nedf2 _m16gtdf2 _m16gedf2 _m16ledf2 _m16ltdf2 \
_m16fltsidf _m16fix_truncdfsi \
_m16retsf _m16retdf \
_m16retsc _m16retdc \
_m16stub1 _m16stub2 _m16stub5 _m16stub6 _m16stub9 _m16stub10 \
_m16stubsf0 _m16stubsf1 _m16stubsf2 _m16stubsf5 _m16stubsf6 \
_m16stubsf9 _m16stubsf10 \
_m16stubdf0 _m16stubdf1 _m16stubdf2 _m16stubdf5 _m16stubdf6 \
_m16stubdf9 _m16stubdf10
_m16stubdf9 _m16stubdf10 \
_m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \
_m16stubsc9 _m16stubsc10 \
_m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \
_m16stubdc9 _m16stubdc10
# We must build libgcc2.a with -G 0, in case the user wants to link
# without the $gp register.
......
2007-05-23 Sandra Loosemore <sandra@codesourcery.com>
Nigel Stephens <nigel@mips.com>
Richard Sandiford <richard@codesourcery.com>
* gcc.target/mips/inter/mips16_stubs_1_main.c: New.
* gcc.target/mips/inter/mips16_stubs_1_x.c: New.
* gcc.target/mips/inter/mips16_stubs_1_y.c: New.
* gcc.target/mips/inter/mips16-inter.exp: New.
2007-05-23 Kazu Hirata <kazu@codesourcery.com>
* gcc.dg/bf-spl1.c, gcc.dg/m68k-pic-1.c: Enable on fido-*-*.
# Run compatibility tests in which the "alt" compiler tries to force
# MIPS16 mode.
# We can only guarantee MIPS16 runtime support for certain targets.
if { ![istarget mipsisa*-*-elf*] && ![istarget mips64vr*-*-elf*] } {
return
}
# Save the old value of CFLAGS_FOR_TARGET, if any.
global saved_CFLAGS_FOR_TARGET
if { [info exists CFLAGS_FOR_TARGET] } {
set saved_CFLAGS_FOR_TARGET $CFLAGS_FOR_TARGET
} else {
unset -nocomplain saved_CFLAGS_FOR_TARGET
}
# The "alt" compiler is the normal compiler with an extra "-mips16" argument.
proc compat-use-alt-compiler { } {
global saved_CFLAGS_FOR_TARGET CFLAGS_FOR_TARGET
if { [info exists saved_CFLAGS_FOR_TARGET] } {
set CFLAGS_FOR_TARGET [concat $saved_CFLAGS_FOR_TARGET "-mips16"]
} else {
set CFLAGS_FOR_TARGET "-mips16"
}
}
# Make the compiler under test the default.
proc compat-use-tst-compiler { } {
global saved_CFLAGS_FOR_TARGET CFLAGS_FOR_TARGET
if { [info exists saved_CFLAGS_FOR_TARGET] } {
set CFLAGS_FOR_TARGET $saved_CFLAGS_FOR_TARGET
} else {
unset -nocomplain CFLAGS_FOR_TARGET
}
}
load_lib gcc.exp
load_lib compat.exp
gcc_init
foreach src [lsort [find $srcdir/$subdir mips16_*_main.c]] {
if { [runtest_file_p $runtests $src] } {
compat-execute $src "mips16_inter" 1
}
}
compat-use-tst-compiler
extern void init (void);
extern void test (void);
int
main (void)
{
init ();
test ();
return 0;
}
#include <stdlib.h>
/* All the function pointers are declared and initialized in
mips16-stubs-2.c. */
extern double the_result;
extern void v0 (void);
extern void v1 (float);
extern void v5 (float, float);
extern void v9 (float, double);
extern void v2 (double);
extern void v6 (double, float);
extern void v10 (double, double);
extern float f0 (void);
extern float f1 (float);
extern float f5 (float, float);
extern float f9 (float, double);
extern float f2 (double);
extern float f6 (double, float);
extern float f10 (double, double);
extern double d0 (void);
extern double d1 (float);
extern double d5 (float, float);
extern double d9 (float, double);
extern double d2 (double);
extern double d6 (double, float);
extern double d10 (double, double);
extern _Complex float cf0 (void);
extern _Complex float cf1 (float);
extern _Complex float cf5 (float, float);
extern _Complex float cf9 (float, double);
extern _Complex float cf2 (double);
extern _Complex float cf6 (double, float);
extern _Complex float cf10 (double, double);
extern _Complex double cd0 (void);
extern _Complex double cd1 (float);
extern _Complex double cd5 (float, float);
extern _Complex double cd9 (float, double);
extern _Complex double cd2 (double);
extern _Complex double cd6 (double, float);
extern _Complex double cd10 (double, double);
extern void (*pv0) (void);
extern void (*pv1) (float);
extern void (*pv5) (float, float);
extern void (*pv9) (float, double);
extern void (*pv2) (double);
extern void (*pv6) (double, float);
extern void (*pv10) (double, double);
extern float (*pf0) (void);
extern float (*pf1) (float);
extern float (*pf5) (float, float);
extern float (*pf9) (float, double);
extern float (*pf2) (double);
extern float (*pf6) (double, float);
extern float (*pf10) (double, double);
extern double (*pd0) (void);
extern double (*pd1) (float);
extern double (*pd5) (float, float);
extern double (*pd9) (float, double);
extern double (*pd2) (double);
extern double (*pd6) (double, float);
extern double (*pd10) (double, double);
extern _Complex float (*pcf0) (void);
extern _Complex float (*pcf1) (float);
extern _Complex float (*pcf5) (float, float);
extern _Complex float (*pcf9) (float, double);
extern _Complex float (*pcf2) (double);
extern _Complex float (*pcf6) (double, float);
extern _Complex float (*pcf10) (double, double);
extern _Complex double (*pcd0) (void);
extern _Complex double (*pcd1) (float);
extern _Complex double (*pcd5) (float, float);
extern _Complex double (*pcd9) (float, double);
extern _Complex double (*pcd2) (double);
extern _Complex double (*pcd6) (double, float);
extern _Complex double (*pcd10) (double, double);
/* Macros for results checking. */
#define CHECK_RESULT(x, y) if ((x) != (y)) abort ()
#define CHECK_VOID_RESULT(x, y) CHECK_RESULT (((x), the_result), y)
/* Call functions through pointers and and check against expected results. */
void
test (void)
{
CHECK_VOID_RESULT (v0 (), 1.0);
CHECK_VOID_RESULT (v1 (1.0), 2.0);
CHECK_VOID_RESULT (v5 (5.0, 6.0), 12.0);
CHECK_VOID_RESULT (v9 (9.0, 10.0), 20.0);
CHECK_VOID_RESULT (v2 (2.0), 3.0);
CHECK_VOID_RESULT (v6 (6.0, 7.0), 14.0);
CHECK_VOID_RESULT (v10 (10.0, 11.0), 22.0);
CHECK_RESULT (f0 (), 1.0);
CHECK_RESULT (f1 (1.0), 2.0);
CHECK_RESULT (f5 (5.0, 6.0), 12.0);
CHECK_RESULT (f9 (9.0, 10.0), 20.0);
CHECK_RESULT (f2 (2.0), 3.0);
CHECK_RESULT (f6 (6.0, 7.0), 14.0);
CHECK_RESULT (f10 (10.0, 11.0), 22.0);
CHECK_RESULT (d0 (), 1.0);
CHECK_RESULT (d1 (1.0), 2.0);
CHECK_RESULT (d5 (5.0, 6.0), 12.0);
CHECK_RESULT (d9 (9.0, 10.0), 20.0);
CHECK_RESULT (d2 (2.0), 3.0);
CHECK_RESULT (d6 (6.0, 7.0), 14.0);
CHECK_RESULT (d10 (10.0, 11.0), 22.0);
CHECK_RESULT (cf0 (), 1.0 + 0.0i);
CHECK_RESULT (cf1 (1.0), 2.0 + 1.0i);
CHECK_RESULT (cf5 (5.0, 6.0), 12.0 + 5.0i);
CHECK_RESULT (cf9 (9.0, 10.0), 20.0 + 9.0i);
CHECK_RESULT (cf2 (2.0), 3.0 + 2.0i);
CHECK_RESULT (cf6 (6.0, 7.0), 14.0 + 6.0i);
CHECK_RESULT (cf10 (10.0, 11.0), 22.0 + 10.0i);
CHECK_RESULT (cd0 (), 1.0 + 0.0i);
CHECK_RESULT (cd1 (1.0), 2.0 + 1.0i);
CHECK_RESULT (cd5 (5.0, 6.0), 12.0 + 5.0i);
CHECK_RESULT (cd9 (9.0, 10.0), 20.0 + 9.0i);
CHECK_RESULT (cd2 (2.0), 3.0 + 2.0i);
CHECK_RESULT (cd6 (6.0, 7.0), 14.0 + 6.0i);
CHECK_RESULT (cd10 (10.0, 11.0), 22.0 + 10.0i);
CHECK_VOID_RESULT ((*pv0) (), 1.0);
CHECK_VOID_RESULT ((*pv1) (1.0), 2.0);
CHECK_VOID_RESULT ((*pv5) (5.0, 6.0), 12.0);
CHECK_VOID_RESULT ((*pv9) (9.0, 10.0), 20.0);
CHECK_VOID_RESULT ((*pv2) (2.0), 3.0);
CHECK_VOID_RESULT ((*pv6) (6.0, 7.0), 14.0);
CHECK_VOID_RESULT ((*pv10) (10.0, 11.0), 22.0);
CHECK_RESULT ((*pf0) (), 1.0);
CHECK_RESULT ((*pf1) (1.0), 2.0);
CHECK_RESULT ((*pf5) (5.0, 6.0), 12.0);
CHECK_RESULT ((*pf9) (9.0, 10.0), 20.0);
CHECK_RESULT ((*pf2) (2.0), 3.0);
CHECK_RESULT ((*pf6) (6.0, 7.0), 14.0);
CHECK_RESULT ((*pf10) (10.0, 11.0), 22.0);
CHECK_RESULT ((*pd0) (), 1.0);
CHECK_RESULT ((*pd1) (1.0), 2.0);
CHECK_RESULT ((*pd5) (5.0, 6.0), 12.0);
CHECK_RESULT ((*pd9) (9.0, 10.0), 20.0);
CHECK_RESULT ((*pd2) (2.0), 3.0);
CHECK_RESULT ((*pd6) (6.0, 7.0), 14.0);
CHECK_RESULT ((*pd10) (10.0, 11.0), 22.0);
CHECK_RESULT ((*pcf0) (), 1.0 + 0.0i);
CHECK_RESULT ((*pcf1) (1.0), 2.0 + 1.0i);
CHECK_RESULT ((*pcf5) (5.0, 6.0), 12.0 + 5.0i);
CHECK_RESULT ((*pcf9) (9.0, 10.0), 20.0 + 9.0i);
CHECK_RESULT ((*pcf2) (2.0), 3.0 + 2.0i);
CHECK_RESULT ((*pcf6) (6.0, 7.0), 14.0 + 6.0i);
CHECK_RESULT ((*pcf10) (10.0, 11.0), 22.0 + 10.0i);
CHECK_RESULT ((*pcd0) (), 1.0 + 0.0i);
CHECK_RESULT ((*pcd1) (1.0), 2.0 + 1.0i);
CHECK_RESULT ((*pcd5) (5.0, 6.0), 12.0 + 5.0i);
CHECK_RESULT ((*pcd9) (9.0, 10.0), 20.0 + 9.0i);
CHECK_RESULT ((*pcd2) (2.0), 3.0 + 2.0i);
CHECK_RESULT ((*pcd6) (6.0, 7.0), 14.0 + 6.0i);
CHECK_RESULT ((*pcd10) (10.0, 11.0), 22.0 + 10.0i);
}
/* All test functions return the sum of arguments, plus 1.
Void-returning functions put the result in the_result.
Complex-returning functions return their signature number as the
(constant) imaginary part of the result. */
double the_result;
void v0 (void) { the_result = 1.0; }
void v1 (float x) { the_result = 1.0 + x; }
void v5 (float x, float y) { the_result = 1.0 + x + y; }
void v9 (float x, double y) { the_result = 1.0 + x + y; }
void v2 (double x) { the_result = 1.0 + x; }
void v6 (double x, float y) { the_result = 1.0 + x + y; }
void v10 (double x, double y) { the_result = 1.0 + x + y; }
float f0 (void) { return 1.0; }
float f1 (float x) { return 1.0 + x; }
float f5 (float x, float y) { return 1.0 + x + y; }
float f9 (float x, double y) { return 1.0 + x + y; }
float f2 (double x) { return 1.0 + x; }
float f6 (double x, float y) { return 1.0 + x + y; }
float f10 (double x, double y) { return 1.0 + x + y; }
double d0 (void) { return 1.0; }
double d1 (float x) { return 1.0 + x; }
double d5 (float x, float y) { return 1.0 + x + y; }
double d9 (float x, double y) { return 1.0 + x + y; }
double d2 (double x) { return 1.0 + x; }
double d6 (double x, float y) { return 1.0 + x + y; }
double d10 (double x, double y) { return 1.0 + x + y; }
_Complex float cf0 (void) { return 1.0 + 0.0i; }
_Complex float cf1 (float x) { return 1.0 + x + 1.0i; }
_Complex float cf5 (float x, float y) { return 1.0 + x + y + 5.0i; }
_Complex float cf9 (float x, double y) { return 1.0 + x + y + 9.0i; }
_Complex float cf2 (double x) { return 1.0 + x + 2.0i; }
_Complex float cf6 (double x, float y) { return 1.0 + x + y + 6.0i; }
_Complex float cf10 (double x, double y) { return 1.0 + x + y + 10.0i; }
_Complex double cd0 (void) { return 1.0 + 0.0i; }
_Complex double cd1 (float x) { return 1.0 + x + 1.0i; }
_Complex double cd5 (float x, float y) { return 1.0 + x + y + 5.0i; }
_Complex double cd9 (float x, double y) { return 1.0 + x + y + 9.0i; }
_Complex double cd2 (double x) { return 1.0 + x + 2.0i; }
_Complex double cd6 (double x, float y) { return 1.0 + x + y + 6.0i; }
_Complex double cd10 (double x, double y) { return 1.0 + x + y + 10.0i; }
/* Declare and initialize all the pointer-to-function variables. */
void (*pv0) (void);
void (*pv1) (float);
void (*pv5) (float, float);
void (*pv9) (float, double);
void (*pv2) (double);
void (*pv6) (double, float);
void (*pv10) (double, double);
float (*pf0) (void);
float (*pf1) (float);
float (*pf5) (float, float);
float (*pf9) (float, double);
float (*pf2) (double);
float (*pf6) (double, float);
float (*pf10) (double, double);
double (*pd0) (void);
double (*pd1) (float);
double (*pd5) (float, float);
double (*pd9) (float, double);
double (*pd2) (double);
double (*pd6) (double, float);
double (*pd10) (double, double);
_Complex float (*pcf0) (void);
_Complex float (*pcf1) (float);
_Complex float (*pcf5) (float, float);
_Complex float (*pcf9) (float, double);
_Complex float (*pcf2) (double);
_Complex float (*pcf6) (double, float);
_Complex float (*pcf10) (double, double);
_Complex double (*pcd0) (void);
_Complex double (*pcd1) (float);
_Complex double (*pcd5) (float, float);
_Complex double (*pcd9) (float, double);
_Complex double (*pcd2) (double);
_Complex double (*pcd6) (double, float);
_Complex double (*pcd10) (double, double);
void
init (void)
{
pv0 = v0;
pv1 = v1;
pv5 = v5;
pv9 = v9;
pv2 = v2;
pv6 = v6;
pv10 = v10;
pf0 = f0;
pf1 = f1;
pf5 = f5;
pf9 = f9;
pf2 = f2;
pf6 = f6;
pf10 = f10;
pd0 = d0;
pd1 = d1;
pd5 = d5;
pd9 = d9;
pd2 = d2;
pd6 = d6;
pd10 = d10;
pcf0 = cf0;
pcf1 = cf1;
pcf5 = cf5;
pcf9 = cf9;
pcf2 = cf2;
pcf6 = cf6;
pcf10 = cf10;
pcd0 = cd0;
pcd1 = cd1;
pcd5 = cd5;
pcd9 = cd9;
pcd2 = cd2;
pcd6 = cd6;
pcd10 = cd10;
}
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