diff options
author | Sandra Loosemore <sandra@codesourcery.com> | 2007-05-23 16:03:00 -0400 |
---|---|---|
committer | Sandra Loosemore <sandra@gcc.gnu.org> | 2007-05-23 16:03:00 -0400 |
commit | a38e0142a8424e5d53b673ecaaa2976982a84834 (patch) | |
tree | cd02dcb528cfcda488ff2971a284e216d7dbe59b /gcc/config | |
parent | 70c1e0331bd30847a68d7eb2a8a4fd1e5463ea57 (diff) | |
download | gcc-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.c | 323 | ||||
-rw-r--r-- | gcc/config/mips/mips.h | 15 | ||||
-rw-r--r-- | gcc/config/mips/mips16.S | 845 | ||||
-rw-r--r-- | gcc/config/mips/t-elf | 7 | ||||
-rw-r--r-- | gcc/config/mips/t-isa3264 | 7 | ||||
-rw-r--r-- | gcc/config/mips/t-r3900 | 7 |
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. |