From a38e0142a8424e5d53b673ecaaa2976982a84834 Mon Sep 17 00:00:00 2001 From: Sandra Loosemore Date: Wed, 23 May 2007 16:03:00 -0400 Subject: [PATCH] Fix up MIPS16 hard float and add support for complex. 2007-05-23 Sandra Loosemore Nigel Stephens Richard Sandiford 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 Co-Authored-By: Richard Sandiford From-SVN: r124999 --- gcc/ChangeLog | 115 +++ gcc/config/mips/mips.c | 323 +++++--- gcc/config/mips/mips.h | 15 +- gcc/config/mips/mips16.S | 845 ++++++++++----------- gcc/config/mips/t-elf | 7 +- gcc/config/mips/t-isa3264 | 7 +- gcc/config/mips/t-r3900 | 7 +- gcc/testsuite/ChangeLog | 9 + .../gcc.target/mips/inter/mips16-inter.exp | 48 ++ .../gcc.target/mips/inter/mips16_stubs_1_main.c | 10 + .../gcc.target/mips/inter/mips16_stubs_1_x.c | 176 +++++ .../gcc.target/mips/inter/mips16_stubs_1_y.c | 133 ++++ 12 files changed, 1140 insertions(+), 555 deletions(-) create mode 100644 gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp create mode 100644 gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c create mode 100644 gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c create mode 100644 gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 941700e..414b1eb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,118 @@ +2007-05-23 Sandra Loosemore + Nigel Stephens + Richard Sandiford + + Fix up MIPS16 hard float and add support for complex. + + * config/mips/mips.h (TARGET_HARD_FLOAT_ABI): New. + (TARGET_SOFT_FLOAT_ABI): New. + (TARGET_CPU_CPP_BUILTINS): Define __mips_hard_float and + __mips_soft_float to reflect the ABI in use, not whether the + FPU is directly accessible (e.g., in MIPS16 mode). + (UNITS_PER_HWFPVALUE): Use TARGET_SOFT_FLOAT_ABI. + (UNITS_PER_FPVALUE): Likewise. + + * config/mips/mips.c (mips_expand_call): Remove redundant + TARGET_MIPS16 check. + (mips_arg_regno): New. + (function_arg_advance): When setting bits in cum->fp_code for + MIPS16, don't subtract 1 from cum->arg_number, since it is now + zero-based. + (function_arg): Use mips_arg_regno. + (mips_return_mode_in_fpr_p): New. + (mips16_call_stub_mode_suffix): New. + (mips16_cfun_returns_in_fpr_p): New. + (mips_save_reg_p): Use mips16_cfun_returns_in_fpr_p. + (mips_output_function_prologue): Test mips16_hard_float, not + !TARGET_SOFT_FLOAT, to decide when a function stub is required. + (mips_expand_epilogue): Call MIPS16 helper routines to copy + return value into a floating-point register. + (mips_can_use_return_insn): Use mips16_cfun_returns_in_fpr_p. + (mips_function_value): Rewrite to use mips_return_mode_in_fpr_p. + (mips16_fp_args): Handle MIPS32r2 ISA which supports + TARGET_FLOAT64, and use mfhc1/mthc1 to copy the most significant + word of double arguments from or to the high bits of 64-bit + floating point registers. + (build_mips16_function_stub): Fill in DECL_RESULT for stubdecl. + (mips16_fpret_double): New helper function. + (build_mips16_call_stub): Use mips16_return_mode_in_fpr_p. Add + support for complex modes. Fill in DECL_RESULT for stubdecl. + (mips_init_libfuncs): Remove redundant TARGET_MIPS16 check. + + * config/mips/mips16.S + (RET, ARG1, ARG2): New. + (MERGE_GPRf, MERGE_GPRt): New. + (DELAYt, DELAYf): New. + (MOVE_SF_BYTE0, MOVE_SI_BYTE0): New. + (MOVE_SF_BYTE4, MOVE_SF_BYTE8): New. + (MOVE_DF_BYTE0, MOVE_DF_BYTE8): New. + (MOVE_SF_RET, MOVE_SC_RET, MOVE_DF_RET, MOVE_DC_RET, MOVE_SI_RET): New. + (SFOP): Renamed to... + (OPSF3): This, and macro-ified. Updated all uses. + (SFOP2): Renamed to... + (OPSF2): This, and macro-ified. Updated all uses. + (SFCMP): Renamed to... + (CMPSF): This, and macro-ified. Updated all uses. + (SFREVCMP): Renamed to... + (REVCMPSF): This, and macro-ified. Updated all uses. + (__mips16_floatsisf, __mips16_fix_truncsfsi): Macro-ified. + (LDDBL1, LDDBL2, RETDBL): Deleted. + (DFOP): Renamed to... + (OPDF3): This, and macro-ified. Updated all uses. + (DFOP2): Renamed to... + (OPDF2): This, and macro-ified. Updated all uses. + (__mips16_extendsfdf2, __mips16_truncdfsf2): Macro-ified. + (DFCMP): Renamed to... + (CMPDF): This, and macro-ified. Updated all uses. + (DFREVCMP): Renamed to... + (REVCMPDF): This, and macro-ified. Updated all uses. + (__mips16_floatsidf, __mips16_fix_truncdfsi): Macro-ified. + (RET_FUNCTION): New. + (__mips16_ret_sf, __mips16_ret_df): Macro-ified. + (__mips16_ret_sc, __mips16_ret_dc): New. + (STUB_ARGS_0, STUB_ARGS_1, STUB_ARGS_5, STUB_ARGS_9, STUB_ARGS_2, + STUB_ARGS_6, STUB_ARGS_10): New. + (CALL_STUB_NO_RET): New. + (__mips16_call_stub_1): Macro-ified. + (__mips16_call_stub_5): Macro-ified. + (__mips16_call_stub_2): Macro-ified. + (__mips16_call_stub_6): Macro-ified. + (__mips16_call_stub_9): Macro-ified. + (__mips16_call_stub_10): Macro-ified. + (CALL_STUB_RET): New. + (__mips16_call_stub_sf_0): Macro-ified. + (__mips16_call_stub_sf_1): Macro-ified. + (__mips16_call_stub_sf_5): Macro-ified. + (__mips16_call_stub_sf_2): Macro-ified. + (__mips16_call_stub_sf_6): Macro-ified. + (__mips16_call_stub_sf_9): Macro-ified. + (__mips16_call_stub_sf_10): Macro-ified. + (__mips16_call_stub_df_0): Macro-ified. + (__mips16_call_stub_df_1): Macro-ified. + (__mips16_call_stub_df_5): Macro-ified. + (__mips16_call_stub_df_2): Macro-ified. + (__mips16_call_stub_df_6): Macro-ified. + (__mips16_call_stub_df_9): Macro-ified. + (__mips16_call_stub_df_10): Macro-ified. + (__mips16_call_stub_sc_0): New. + (__mips16_call_stub_sc_1): New. + (__mips16_call_stub_sc_5): New. + (__mips16_call_stub_sc_2): New. + (__mips16_call_stub_sc_6): New. + (__mips16_call_stub_sc_9): New. + (__mips16_call_stub_sc_10): New. + (__mips16_call_stub_dc_0): New. + (__mips16_call_stub_dc_1): New. + (__mips16_call_stub_dc_5): New. + (__mips16_call_stub_dc_2): New. + (__mips16_call_stub_dc_6): New. + (__mips16_call_stub_dc_9): New. + (__mips16_call_stub_dc_10): New. + + * config/mips/t-elf (LIB1ASMFUNCS): Add MIPS16 floating-point stubs. + * config/mips/t-isa3264 (LIB1ASMFUNCS): Likewise. + * config/mips/t-r2900 (LIB1ASMFUNCS): Likewise. + 2007-05-23 Ian Lance Taylor * doc/invoke.texi (Invoking GCC): Document that the order of the diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 37ff3c5..07b5b78 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 fff2e66..0e90d03 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 5894a86..17e7d0e9 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 f2da07d..e66520b 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 6604fbe..be1fc86 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 3bc8c47..1245598 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. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fc9ecb2..988a41b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2007-05-23 Sandra Loosemore + Nigel Stephens + Richard Sandiford + + * gcc.target/mips/inter/mips16_stubs_1_main.c: New. + * gcc.target/mips/inter/mips16_stubs_1_x.c: New. + * gcc.target/mips/inter/mips16_stubs_1_y.c: New. + * gcc.target/mips/inter/mips16-inter.exp: New. + 2007-05-23 Kazu Hirata * gcc.dg/bf-spl1.c, gcc.dg/m68k-pic-1.c: Enable on fido-*-*. diff --git a/gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp b/gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp new file mode 100644 index 0000000..dc28dad --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp @@ -0,0 +1,48 @@ +# Run compatibility tests in which the "alt" compiler tries to force +# MIPS16 mode. + +# We can only guarantee MIPS16 runtime support for certain targets. +if { ![istarget mipsisa*-*-elf*] && ![istarget mips64vr*-*-elf*] } { + return +} + +# Save the old value of CFLAGS_FOR_TARGET, if any. +global saved_CFLAGS_FOR_TARGET +if { [info exists CFLAGS_FOR_TARGET] } { + set saved_CFLAGS_FOR_TARGET $CFLAGS_FOR_TARGET +} else { + unset -nocomplain saved_CFLAGS_FOR_TARGET +} + +# The "alt" compiler is the normal compiler with an extra "-mips16" argument. +proc compat-use-alt-compiler { } { + global saved_CFLAGS_FOR_TARGET CFLAGS_FOR_TARGET + + if { [info exists saved_CFLAGS_FOR_TARGET] } { + set CFLAGS_FOR_TARGET [concat $saved_CFLAGS_FOR_TARGET "-mips16"] + } else { + set CFLAGS_FOR_TARGET "-mips16" + } +} + +# Make the compiler under test the default. +proc compat-use-tst-compiler { } { + global saved_CFLAGS_FOR_TARGET CFLAGS_FOR_TARGET + + if { [info exists saved_CFLAGS_FOR_TARGET] } { + set CFLAGS_FOR_TARGET $saved_CFLAGS_FOR_TARGET + } else { + unset -nocomplain CFLAGS_FOR_TARGET + } +} + +load_lib gcc.exp +load_lib compat.exp + +gcc_init +foreach src [lsort [find $srcdir/$subdir mips16_*_main.c]] { + if { [runtest_file_p $runtests $src] } { + compat-execute $src "mips16_inter" 1 + } +} +compat-use-tst-compiler diff --git a/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c b/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c new file mode 100644 index 0000000..df18c76 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c @@ -0,0 +1,10 @@ +extern void init (void); +extern void test (void); + +int +main (void) +{ + init (); + test (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c b/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c new file mode 100644 index 0000000..076b399 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c @@ -0,0 +1,176 @@ +#include + +/* All the function pointers are declared and initialized in + mips16-stubs-2.c. */ + +extern double the_result; + +extern void v0 (void); +extern void v1 (float); +extern void v5 (float, float); +extern void v9 (float, double); +extern void v2 (double); +extern void v6 (double, float); +extern void v10 (double, double); + +extern float f0 (void); +extern float f1 (float); +extern float f5 (float, float); +extern float f9 (float, double); +extern float f2 (double); +extern float f6 (double, float); +extern float f10 (double, double); + +extern double d0 (void); +extern double d1 (float); +extern double d5 (float, float); +extern double d9 (float, double); +extern double d2 (double); +extern double d6 (double, float); +extern double d10 (double, double); + +extern _Complex float cf0 (void); +extern _Complex float cf1 (float); +extern _Complex float cf5 (float, float); +extern _Complex float cf9 (float, double); +extern _Complex float cf2 (double); +extern _Complex float cf6 (double, float); +extern _Complex float cf10 (double, double); + +extern _Complex double cd0 (void); +extern _Complex double cd1 (float); +extern _Complex double cd5 (float, float); +extern _Complex double cd9 (float, double); +extern _Complex double cd2 (double); +extern _Complex double cd6 (double, float); +extern _Complex double cd10 (double, double); + +extern void (*pv0) (void); +extern void (*pv1) (float); +extern void (*pv5) (float, float); +extern void (*pv9) (float, double); +extern void (*pv2) (double); +extern void (*pv6) (double, float); +extern void (*pv10) (double, double); + +extern float (*pf0) (void); +extern float (*pf1) (float); +extern float (*pf5) (float, float); +extern float (*pf9) (float, double); +extern float (*pf2) (double); +extern float (*pf6) (double, float); +extern float (*pf10) (double, double); + +extern double (*pd0) (void); +extern double (*pd1) (float); +extern double (*pd5) (float, float); +extern double (*pd9) (float, double); +extern double (*pd2) (double); +extern double (*pd6) (double, float); +extern double (*pd10) (double, double); + +extern _Complex float (*pcf0) (void); +extern _Complex float (*pcf1) (float); +extern _Complex float (*pcf5) (float, float); +extern _Complex float (*pcf9) (float, double); +extern _Complex float (*pcf2) (double); +extern _Complex float (*pcf6) (double, float); +extern _Complex float (*pcf10) (double, double); + +extern _Complex double (*pcd0) (void); +extern _Complex double (*pcd1) (float); +extern _Complex double (*pcd5) (float, float); +extern _Complex double (*pcd9) (float, double); +extern _Complex double (*pcd2) (double); +extern _Complex double (*pcd6) (double, float); +extern _Complex double (*pcd10) (double, double); + +/* Macros for results checking. */ +#define CHECK_RESULT(x, y) if ((x) != (y)) abort () +#define CHECK_VOID_RESULT(x, y) CHECK_RESULT (((x), the_result), y) + +/* Call functions through pointers and and check against expected results. */ +void +test (void) +{ + + CHECK_VOID_RESULT (v0 (), 1.0); + CHECK_VOID_RESULT (v1 (1.0), 2.0); + CHECK_VOID_RESULT (v5 (5.0, 6.0), 12.0); + CHECK_VOID_RESULT (v9 (9.0, 10.0), 20.0); + CHECK_VOID_RESULT (v2 (2.0), 3.0); + CHECK_VOID_RESULT (v6 (6.0, 7.0), 14.0); + CHECK_VOID_RESULT (v10 (10.0, 11.0), 22.0); + + CHECK_RESULT (f0 (), 1.0); + CHECK_RESULT (f1 (1.0), 2.0); + CHECK_RESULT (f5 (5.0, 6.0), 12.0); + CHECK_RESULT (f9 (9.0, 10.0), 20.0); + CHECK_RESULT (f2 (2.0), 3.0); + CHECK_RESULT (f6 (6.0, 7.0), 14.0); + CHECK_RESULT (f10 (10.0, 11.0), 22.0); + + CHECK_RESULT (d0 (), 1.0); + CHECK_RESULT (d1 (1.0), 2.0); + CHECK_RESULT (d5 (5.0, 6.0), 12.0); + CHECK_RESULT (d9 (9.0, 10.0), 20.0); + CHECK_RESULT (d2 (2.0), 3.0); + CHECK_RESULT (d6 (6.0, 7.0), 14.0); + CHECK_RESULT (d10 (10.0, 11.0), 22.0); + + CHECK_RESULT (cf0 (), 1.0 + 0.0i); + CHECK_RESULT (cf1 (1.0), 2.0 + 1.0i); + CHECK_RESULT (cf5 (5.0, 6.0), 12.0 + 5.0i); + CHECK_RESULT (cf9 (9.0, 10.0), 20.0 + 9.0i); + CHECK_RESULT (cf2 (2.0), 3.0 + 2.0i); + CHECK_RESULT (cf6 (6.0, 7.0), 14.0 + 6.0i); + CHECK_RESULT (cf10 (10.0, 11.0), 22.0 + 10.0i); + + CHECK_RESULT (cd0 (), 1.0 + 0.0i); + CHECK_RESULT (cd1 (1.0), 2.0 + 1.0i); + CHECK_RESULT (cd5 (5.0, 6.0), 12.0 + 5.0i); + CHECK_RESULT (cd9 (9.0, 10.0), 20.0 + 9.0i); + CHECK_RESULT (cd2 (2.0), 3.0 + 2.0i); + CHECK_RESULT (cd6 (6.0, 7.0), 14.0 + 6.0i); + CHECK_RESULT (cd10 (10.0, 11.0), 22.0 + 10.0i); + + CHECK_VOID_RESULT ((*pv0) (), 1.0); + CHECK_VOID_RESULT ((*pv1) (1.0), 2.0); + CHECK_VOID_RESULT ((*pv5) (5.0, 6.0), 12.0); + CHECK_VOID_RESULT ((*pv9) (9.0, 10.0), 20.0); + CHECK_VOID_RESULT ((*pv2) (2.0), 3.0); + CHECK_VOID_RESULT ((*pv6) (6.0, 7.0), 14.0); + CHECK_VOID_RESULT ((*pv10) (10.0, 11.0), 22.0); + + CHECK_RESULT ((*pf0) (), 1.0); + CHECK_RESULT ((*pf1) (1.0), 2.0); + CHECK_RESULT ((*pf5) (5.0, 6.0), 12.0); + CHECK_RESULT ((*pf9) (9.0, 10.0), 20.0); + CHECK_RESULT ((*pf2) (2.0), 3.0); + CHECK_RESULT ((*pf6) (6.0, 7.0), 14.0); + CHECK_RESULT ((*pf10) (10.0, 11.0), 22.0); + + CHECK_RESULT ((*pd0) (), 1.0); + CHECK_RESULT ((*pd1) (1.0), 2.0); + CHECK_RESULT ((*pd5) (5.0, 6.0), 12.0); + CHECK_RESULT ((*pd9) (9.0, 10.0), 20.0); + CHECK_RESULT ((*pd2) (2.0), 3.0); + CHECK_RESULT ((*pd6) (6.0, 7.0), 14.0); + CHECK_RESULT ((*pd10) (10.0, 11.0), 22.0); + + CHECK_RESULT ((*pcf0) (), 1.0 + 0.0i); + CHECK_RESULT ((*pcf1) (1.0), 2.0 + 1.0i); + CHECK_RESULT ((*pcf5) (5.0, 6.0), 12.0 + 5.0i); + CHECK_RESULT ((*pcf9) (9.0, 10.0), 20.0 + 9.0i); + CHECK_RESULT ((*pcf2) (2.0), 3.0 + 2.0i); + CHECK_RESULT ((*pcf6) (6.0, 7.0), 14.0 + 6.0i); + CHECK_RESULT ((*pcf10) (10.0, 11.0), 22.0 + 10.0i); + + CHECK_RESULT ((*pcd0) (), 1.0 + 0.0i); + CHECK_RESULT ((*pcd1) (1.0), 2.0 + 1.0i); + CHECK_RESULT ((*pcd5) (5.0, 6.0), 12.0 + 5.0i); + CHECK_RESULT ((*pcd9) (9.0, 10.0), 20.0 + 9.0i); + CHECK_RESULT ((*pcd2) (2.0), 3.0 + 2.0i); + CHECK_RESULT ((*pcd6) (6.0, 7.0), 14.0 + 6.0i); + CHECK_RESULT ((*pcd10) (10.0, 11.0), 22.0 + 10.0i); +} diff --git a/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c b/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c new file mode 100644 index 0000000..b7a4d7f --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c @@ -0,0 +1,133 @@ +/* All test functions return the sum of arguments, plus 1. + Void-returning functions put the result in the_result. + Complex-returning functions return their signature number as the + (constant) imaginary part of the result. */ + +double the_result; + +void v0 (void) { the_result = 1.0; } +void v1 (float x) { the_result = 1.0 + x; } +void v5 (float x, float y) { the_result = 1.0 + x + y; } +void v9 (float x, double y) { the_result = 1.0 + x + y; } +void v2 (double x) { the_result = 1.0 + x; } +void v6 (double x, float y) { the_result = 1.0 + x + y; } +void v10 (double x, double y) { the_result = 1.0 + x + y; } + +float f0 (void) { return 1.0; } +float f1 (float x) { return 1.0 + x; } +float f5 (float x, float y) { return 1.0 + x + y; } +float f9 (float x, double y) { return 1.0 + x + y; } +float f2 (double x) { return 1.0 + x; } +float f6 (double x, float y) { return 1.0 + x + y; } +float f10 (double x, double y) { return 1.0 + x + y; } + +double d0 (void) { return 1.0; } +double d1 (float x) { return 1.0 + x; } +double d5 (float x, float y) { return 1.0 + x + y; } +double d9 (float x, double y) { return 1.0 + x + y; } +double d2 (double x) { return 1.0 + x; } +double d6 (double x, float y) { return 1.0 + x + y; } +double d10 (double x, double y) { return 1.0 + x + y; } + +_Complex float cf0 (void) { return 1.0 + 0.0i; } +_Complex float cf1 (float x) { return 1.0 + x + 1.0i; } +_Complex float cf5 (float x, float y) { return 1.0 + x + y + 5.0i; } +_Complex float cf9 (float x, double y) { return 1.0 + x + y + 9.0i; } +_Complex float cf2 (double x) { return 1.0 + x + 2.0i; } +_Complex float cf6 (double x, float y) { return 1.0 + x + y + 6.0i; } +_Complex float cf10 (double x, double y) { return 1.0 + x + y + 10.0i; } + +_Complex double cd0 (void) { return 1.0 + 0.0i; } +_Complex double cd1 (float x) { return 1.0 + x + 1.0i; } +_Complex double cd5 (float x, float y) { return 1.0 + x + y + 5.0i; } +_Complex double cd9 (float x, double y) { return 1.0 + x + y + 9.0i; } +_Complex double cd2 (double x) { return 1.0 + x + 2.0i; } +_Complex double cd6 (double x, float y) { return 1.0 + x + y + 6.0i; } +_Complex double cd10 (double x, double y) { return 1.0 + x + y + 10.0i; } + + +/* Declare and initialize all the pointer-to-function variables. */ + +void (*pv0) (void); +void (*pv1) (float); +void (*pv5) (float, float); +void (*pv9) (float, double); +void (*pv2) (double); +void (*pv6) (double, float); +void (*pv10) (double, double); + +float (*pf0) (void); +float (*pf1) (float); +float (*pf5) (float, float); +float (*pf9) (float, double); +float (*pf2) (double); +float (*pf6) (double, float); +float (*pf10) (double, double); + +double (*pd0) (void); +double (*pd1) (float); +double (*pd5) (float, float); +double (*pd9) (float, double); +double (*pd2) (double); +double (*pd6) (double, float); +double (*pd10) (double, double); + +_Complex float (*pcf0) (void); +_Complex float (*pcf1) (float); +_Complex float (*pcf5) (float, float); +_Complex float (*pcf9) (float, double); +_Complex float (*pcf2) (double); +_Complex float (*pcf6) (double, float); +_Complex float (*pcf10) (double, double); + +_Complex double (*pcd0) (void); +_Complex double (*pcd1) (float); +_Complex double (*pcd5) (float, float); +_Complex double (*pcd9) (float, double); +_Complex double (*pcd2) (double); +_Complex double (*pcd6) (double, float); +_Complex double (*pcd10) (double, double); + +void +init (void) +{ + pv0 = v0; + pv1 = v1; + pv5 = v5; + pv9 = v9; + pv2 = v2; + pv6 = v6; + pv10 = v10; + + pf0 = f0; + pf1 = f1; + pf5 = f5; + pf9 = f9; + pf2 = f2; + pf6 = f6; + pf10 = f10; + + pd0 = d0; + pd1 = d1; + pd5 = d5; + pd9 = d9; + pd2 = d2; + pd6 = d6; + pd10 = d10; + + pcf0 = cf0; + pcf1 = cf1; + pcf5 = cf5; + pcf9 = cf9; + pcf2 = cf2; + pcf6 = cf6; + pcf10 = cf10; + + pcd0 = cd0; + pcd1 = cd1; + pcd5 = cd5; + pcd9 = cd9; + pcd2 = cd2; + pcd6 = cd6; + pcd10 = cd10; +} -- 2.7.4