summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorSandra Loosemore <sandra@codesourcery.com>2007-05-23 16:03:00 -0400
committerSandra Loosemore <sandra@gcc.gnu.org>2007-05-23 16:03:00 -0400
commita38e0142a8424e5d53b673ecaaa2976982a84834 (patch)
treecd02dcb528cfcda488ff2971a284e216d7dbe59b /gcc/config
parent70c1e0331bd30847a68d7eb2a8a4fd1e5463ea57 (diff)
downloadgcc-a38e0142a8424e5d53b673ecaaa2976982a84834.tar.gz
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
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/mips/mips.c323
-rw-r--r--gcc/config/mips/mips.h15
-rw-r--r--gcc/config/mips/mips16.S845
-rw-r--r--gcc/config/mips/t-elf7
-rw-r--r--gcc/config/mips/t-isa32647
-rw-r--r--gcc/config/mips/t-r39007
6 files changed, 649 insertions, 555 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 37ff3c522c2..07b5b78a6b5 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -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");
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index fff2e660400..0e90d030d34 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -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)
diff --git a/gcc/config/mips/mips16.S b/gcc/config/mips/mips16.S
index 5894a862f5c..17e7d0e92b5 100644
--- a/gcc/config/mips/mips16.S
+++ b/gcc/config/mips/mips16.S
@@ -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 */
diff --git a/gcc/config/mips/t-elf b/gcc/config/mips/t-elf
index f2da07d1bcd..e66520b77d4 100644
--- a/gcc/config/mips/t-elf
+++ b/gcc/config/mips/t-elf
@@ -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.
diff --git a/gcc/config/mips/t-isa3264 b/gcc/config/mips/t-isa3264
index 6604fbe09b2..be1fc867540 100644
--- a/gcc/config/mips/t-isa3264
+++ b/gcc/config/mips/t-isa3264
@@ -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.
diff --git a/gcc/config/mips/t-r3900 b/gcc/config/mips/t-r3900
index 3bc8c47279d..12455985074 100644
--- a/gcc/config/mips/t-r3900
+++ b/gcc/config/mips/t-r3900
@@ -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.