From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10581 invoked by alias); 23 May 2007 00:37:50 -0000 Received: (qmail 10566 invoked by uid 22791); 23 May 2007 00:37:40 -0000 X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (65.74.133.4) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 23 May 2007 00:37:29 +0000 Received: (qmail 15667 invoked from network); 23 May 2007 00:37:25 -0000 Received: from unknown (HELO ?192.168.2.3?) (sandra@127.0.0.2) by mail.codesourcery.com with ESMTPA; 23 May 2007 00:37:25 -0000 Message-ID: <46538D21.5020007@codesourcery.com> Date: Wed, 23 May 2007 00:37:00 -0000 From: Sandra Loosemore User-Agent: Thunderbird 1.5 (X11/20051201) MIME-Version: 1.0 To: GCC Patches Subject: PATCH: mips16 float and complex support Content-Type: multipart/mixed; boundary="------------070502060501000700090309" Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2007-05/txt/msg01512.txt.bz2 This is a multi-part message in MIME format. --------------070502060501000700090309 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 495 This patch does some major cleanup to fix bugs in the mips16 support for hardware floating point. It also adds support for complex return values. I've tested this in a mips32r2 -mabi=32 -mips16 configuration, where it cleans up 120+ test failures, and also with -mfp64 added to that, where it gets rid of ~250 failures. There's also a new test case included to test all the combinations of stub functions for interoperability between mips16 and non-mips16 mode. OK to commit? -Sandra --------------070502060501000700090309 Content-Type: text/x-log; name="06-mips16-hardfloat.log" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="06-mips16-hardfloat.log" Content-length: 4919 2007-05-22 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. (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): Check for TARGET_MIPS16. (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. (mips_arg_regno): New. (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. --------------070502060501000700090309 Content-Type: text/x-patch; name="06-mips16-hardfloat.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="06-mips16-hardfloat.patch" Content-length: 71643 Index: gcc/config/mips/mips.h =================================================================== *** gcc/config/mips/mips.h (revision 124934) --- gcc/config/mips/mips.h (working copy) *************** extern const struct mips_rtx_cost_data * *** 288,293 **** --- 288,298 ---- #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 *************** extern const struct mips_rtx_cost_data * *** 406,414 **** builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS64"); \ } \ \ ! if (TARGET_HARD_FLOAT) \ builtin_define ("__mips_hard_float"); \ ! else if (TARGET_SOFT_FLOAT) \ builtin_define ("__mips_soft_float"); \ \ if (TARGET_SINGLE_FLOAT) \ --- 411,421 ---- builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS64"); \ } \ \ ! /* 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 \ builtin_define ("__mips_soft_float"); \ \ if (TARGET_SINGLE_FLOAT) \ *************** extern const struct mips_rtx_cost_data * *** 1033,1044 **** /* 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) /* The largest size of value that can be held in floating-point registers. */ #define UNITS_PER_FPVALUE \ ! (TARGET_SOFT_FLOAT ? 0 \ : TARGET_SINGLE_FLOAT ? UNITS_PER_FPREG \ : LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT) --- 1040,1051 ---- /* 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_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_ABI ? 0 \ : TARGET_SINGLE_FLOAT ? UNITS_PER_FPREG \ : LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT) Index: gcc/config/mips/mips.c =================================================================== *** gcc/config/mips/mips.c (revision 124934) --- gcc/config/mips/mips.c (working copy) *************** mips_expand_call (rtx result, rtx addr, *** 3490,3497 **** mips_load_call_address (addr, orig_addr, sibcall_p); } ! if (TARGET_MIPS16 ! && mips16_hard_float && build_mips16_call_stub (result, addr, args_size, aux == 0 ? 0 : (int) GET_MODE (aux))) return; --- 3490,3496 ---- mips_load_call_address (addr, orig_addr, sibcall_p); } ! if (mips16_hard_float && build_mips16_call_stub (result, addr, args_size, aux == 0 ? 0 : (int) GET_MODE (aux))) return; *************** function_arg_advance (CUMULATIVE_ARGS *c *** 3895,3901 **** 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); if (mips_abi != ABI_EABI || !info.fpr_p) cum->num_gprs = info.reg_offset + info.reg_words; --- 3894,3900 ---- 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 * 2); if (mips_abi != ABI_EABI || !info.fpr_p) cum->num_gprs = info.reg_offset + info.reg_words; *************** function_arg (const CUMULATIVE_ARGS *cum *** 4032,4038 **** } } ! 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 --- 4031,4037 ---- } } ! if (!info.fpr_p || TARGET_MIPS16) 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 *************** mips_global_pointer (void) *** 6303,6308 **** --- 6302,6352 ---- } + /* 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 *************** mips_save_reg_p (unsigned int regno) *** 6337,6346 **** 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. */ --- 6381,6386 ---- *************** mips_save_reg_p (unsigned int regno) *** 6351,6360 **** 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) return true; } --- 6391,6397 ---- value into the floating point registers if the return value is floating point. */ if (regno == GP_REG_FIRST + 31 ! && mips16_cfun_returns_in_fpr_p ()) return true; } *************** mips_output_function_prologue (FILE *fil *** 6739,6745 **** 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 && current_function_args_info.fp_code != 0) build_mips16_function_stub (file); --- 6776,6782 ---- 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 (mips16_hard_float && current_function_args_info.fp_code != 0) build_mips16_function_stub (file); *************** mips_expand_epilogue (int sibcall_p) *** 7069,7074 **** --- 7106,7138 ---- 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 *************** mips_expand_epilogue (int sibcall_p) *** 7175,7198 **** 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 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) return 0; if (cfun->machine->frame.initialized) --- 7239,7254 ---- int mips_can_use_return_insn (void) { if (! reload_completed) return 0; if (regs_ever_live[31] || current_function_profile) return 0; ! /* 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 (mips16_cfun_returns_in_fpr_p ()) return 0; if (cfun->machine->frame.initialized) *************** mips_function_value (tree valtype, tree *** 7617,7639 **** 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 (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); return gen_rtx_REG (mode, GP_RETURN); } --- 7673,7697 ---- return gen_rtx_REG (mode, GP_RETURN); } ! 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 (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); } *************** mips16_gp_pseudo_reg (void) *** 7966,7971 **** --- 8024,8047 ---- return cfun->machine->mips16_gp_pseudo_rtx; } + /* INFO describes an argument that is pased 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; + } + /* Write out code to move floating point arguments in or out of general registers. Output the instructions to FILE. FP_CODE is the code describing which arguments are present (see the comment at *************** mips16_fp_args (FILE *file, int fp_code, *** 7978,7983 **** --- 8054,8060 ---- 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); *************** mips16_fp_args (FILE *file, int fp_code, *** 7986,8028 **** s = "mfc1"; else s = "mtc1"; ! gparg = GP_ARG_FIRST; ! fparg = FP_ARG_FIRST; for (f = (unsigned int) fp_code; f != 0; f >>= 2) { if ((f & 3) == 1) ! { ! if ((fparg & 1) != 0) ! ++fparg; ! fprintf (file, "\t%s\t%s,%s\n", s, ! reg_names[gparg], reg_names[fparg]); ! } 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; ! } ! } else gcc_unreachable (); ! ++gparg; ! ++fparg; } } --- 8063,8112 ---- s = "mfc1"; else s = "mtc1"; ! ! 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) ! mode = SFmode; else if ((f & 3) == 2) ! mode = DFmode; else gcc_unreachable (); ! 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); } } *************** build_mips16_function_stub (FILE *file) *** 8049,8054 **** --- 8133,8139 ---- 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; *************** struct mips16_stub *** 8122,8127 **** --- 8207,8253 ---- 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 *************** static struct mips16_stub *mips16_stubs; *** 8143,8149 **** int build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code) { ! int fpret; const char *fnname; char *secname, *stubname; struct mips16_stub *l; --- 8269,8275 ---- int build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code) { ! int fpret = 0; const char *fnname; char *secname, *stubname; struct mips16_stub *l; *************** build_mips16_call_stub (rtx retval, rtx *** 8153,8166 **** /* 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) 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); /* 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 --- 8279,8291 ---- /* 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 (!mips16_hard_float) return 0; /* Figure out whether the value might come back in a floating point register. */ ! 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 *************** build_mips16_call_stub (rtx retval, rtx *** 8178,8188 **** 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 --- 8303,8308 ---- *************** build_mips16_call_stub (rtx retval, rtx *** 8197,8207 **** /* ??? 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); id = get_identifier (buf); stub_fn = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (id)); --- 8317,8330 ---- /* ??? If this code is modified to support other ABI's, we need to handle PARALLEL return values here. */ ! 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)); *************** build_mips16_call_stub (rtx retval, rtx *** 8277,8282 **** --- 8400,8406 ---- 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 *************** build_mips16_call_stub (rtx retval, rtx *** 8339,8344 **** --- 8463,8489 ---- 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) *************** mips_init_libfuncs (void) *** 9190,9196 **** set_optab_libfunc (smod_optab, SImode, "__vr4120_modsi3"); } ! if (TARGET_MIPS16 && mips16_hard_float) { set_optab_libfunc (add_optab, SFmode, "__mips16_addsf3"); set_optab_libfunc (sub_optab, SFmode, "__mips16_subsf3"); --- 9335,9341 ---- set_optab_libfunc (smod_optab, SImode, "__vr4120_modsi3"); } ! if (mips16_hard_float) { set_optab_libfunc (add_optab, SFmode, "__mips16_addsf3"); set_optab_libfunc (sub_optab, SFmode, "__mips16_subsf3"); Index: gcc/config/mips/mips16.S =================================================================== *** gcc/config/mips/mips16.S (revision 124934) --- gcc/config/mips/mips16.S (working copy) *************** Boston, MA 02110-1301, USA. */ *** 49,117 **** #define ENDFN(NAME) .end NAME ! /* Single precision math. */ ! /* This macro defines a function which loads two single precision ! values, performs an operation, and returns the single precision ! result. */ ! #define SFOP(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; \ ENDFN (NAME) #ifdef L_m16addsf3 ! SFOP(__mips16_addsf3, add.s) #endif #ifdef L_m16subsf3 ! SFOP(__mips16_subsf3, sub.s) #endif #ifdef L_m16mulsf3 ! SFOP(__mips16_mulsf3, mul.s) #endif #ifdef L_m16divsf3 ! SFOP(__mips16_divsf3, div.s) #endif ! #define SFOP2(NAME, OPCODE) \ STARTFN (NAME); \ ! .set noreorder; \ ! mtc1 $4,$f0; \ ! nop; \ ! OPCODE $f0,$f0; \ ! mfc1 $2,$f0; \ ! j $31; \ ! nop; \ ! .set reorder; \ ENDFN (NAME) #ifdef L_m16negsf2 ! SFOP2(__mips16_negsf2, neg.s) #endif #ifdef L_m16abssf2 ! SFOP2(__mips16_abssf2, abs.s) #endif ! /* 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 SFCMP(NAME, OPCODE, TRUE, FALSE) \ STARTFN (NAME); \ ! mtc1 $4,$f0; \ ! mtc1 $5,$f2; \ ! OPCODE $f0,$f2; \ li $2,TRUE; \ bc1t 1f; \ li $2,FALSE; \ --- 49,252 ---- #define ENDFN(NAME) .end NAME ! /* ARG1 ! The FPR that holds the first floating-point argument. ! ARG2 ! The FPR that holds the second floating-point argument. ! 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); \ ! MOVE_SF_BYTE0 (t); \ ! MOVE_SF_BYTE4 (t); \ ! OPCODE RET,ARG1,ARG2; \ ! MOVE_SF_RET (f, $31); \ ENDFN (NAME) #ifdef L_m16addsf3 ! OPSF3 (__mips16_addsf3, add.s) #endif #ifdef L_m16subsf3 ! OPSF3 (__mips16_subsf3, sub.s) #endif #ifdef L_m16mulsf3 ! OPSF3 (__mips16_mulsf3, mul.s) #endif #ifdef L_m16divsf3 ! OPSF3 (__mips16_divsf3, div.s) #endif ! /* 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); \ ! MOVE_SF_BYTE0 (t); \ ! OPCODE RET,ARG1; \ ! MOVE_SF_RET (f, $31); \ ENDFN (NAME) #ifdef L_m16negsf2 ! OPSF2 (__mips16_negsf2, neg.s) #endif #ifdef L_m16abssf2 ! OPSF2 (__mips16_abssf2, abs.s) #endif ! /* Single-precision comparisons. */ ! /* 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 CMPSF(NAME, OPCODE, TRUE, FALSE) \ STARTFN (NAME); \ ! MOVE_SF_BYTE0 (t); \ ! MOVE_SF_BYTE4 (t); \ ! OPCODE ARG1,ARG2; \ li $2,TRUE; \ bc1t 1f; \ li $2,FALSE; \ *************** STARTFN (NAME); \ *** 119,131 **** j $31; \ ENDFN (NAME) ! /* This macro is like SFCMP, but it reverses the comparison. */ ! #define SFREVCMP(NAME, OPCODE, TRUE, FALSE) \ STARTFN (NAME); \ ! mtc1 $4,$f0; \ ! mtc1 $5,$f2; \ ! OPCODE $f2,$f0; \ li $2,TRUE; \ bc1t 1f; \ li $2,FALSE; \ --- 254,266 ---- j $31; \ ENDFN (NAME) ! /* Like CMPSF, but reverse the comparison operands. */ ! #define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \ STARTFN (NAME); \ ! MOVE_SF_BYTE0 (t); \ ! MOVE_SF_BYTE4 (t); \ ! OPCODE ARG2,ARG1; \ li $2,TRUE; \ bc1t 1f; \ li $2,FALSE; \ *************** STARTFN (NAME); \ *** 134,322 **** ENDFN (NAME) #ifdef L_m16eqsf2 ! SFCMP(__mips16_eqsf2, c.eq.s, 0, 1) #endif #ifdef L_m16nesf2 ! SFCMP(__mips16_nesf2, c.eq.s, 0, 1) #endif #ifdef L_m16gtsf2 ! SFREVCMP(__mips16_gtsf2, c.lt.s, 1, 0) #endif #ifdef L_m16gesf2 ! SFREVCMP(__mips16_gesf2, c.le.s, 0, -1) #endif #ifdef L_m16lesf2 ! SFCMP(__mips16_lesf2, c.le.s, 0, 1) #endif #ifdef L_m16ltsf2 ! SFCMP(__mips16_ltsf2, c.lt.s, -1, 0) #endif ! /* 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 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 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. */ ! ! /* Load the first double precision operand. */ ! ! #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) \ STARTFN (NAME); \ ! .set noreorder; \ ! LDDBL1; \ ! LDDBL2; \ ! nop; \ ! OPCODE $f0,$f12,$f14; \ ! RETDBL; \ ! j $31; \ ! nop; \ ! .set reorder; \ ENDFN (NAME) #ifdef L_m16adddf3 ! DFOP(__mips16_adddf3, add.d) #endif #ifdef L_m16subdf3 ! DFOP(__mips16_subdf3, sub.d) #endif #ifdef L_m16muldf3 ! DFOP(__mips16_muldf3, mul.d) #endif #ifdef L_m16divdf3 ! DFOP(__mips16_divdf3, div.d) #endif ! #define DFOP2(NAME, OPCODE) \ STARTFN (NAME); \ ! .set noreorder; \ ! LDDBL1; \ ! nop; \ ! OPCODE $f0,$f12; \ ! RETDBL; \ ! j $31; \ ! nop; \ ! .set reorder; \ ENDFN (NAME) #ifdef L_m16negdf2 ! DFOP2(__mips16_negdf2, neg.d) #endif #ifdef L_m16absdf2 ! DFOP2(__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 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 ENDFN (__mips16_truncdfsf2) #endif ! /* 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 DFCMP(NAME, OPCODE, TRUE, FALSE) \ STARTFN (NAME); \ ! LDDBL1; \ ! LDDBL2; \ ! OPCODE $f12,$f14; \ li $2,TRUE; \ bc1t 1f; \ li $2,FALSE; \ --- 269,386 ---- ENDFN (NAME) #ifdef L_m16eqsf2 ! CMPSF (__mips16_eqsf2, c.eq.s, 0, 1) #endif #ifdef L_m16nesf2 ! CMPSF (__mips16_nesf2, c.eq.s, 0, 1) #endif #ifdef L_m16gtsf2 ! REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0) #endif #ifdef L_m16gesf2 ! REVCMPSF (__mips16_gesf2, c.le.s, 0, -1) #endif #ifdef L_m16lesf2 ! CMPSF (__mips16_lesf2, c.le.s, 0, 1) #endif #ifdef L_m16ltsf2 ! CMPSF (__mips16_ltsf2, c.lt.s, -1, 0) #endif ! /* Single-precision conversions. */ #ifdef L_m16fltsisf STARTFN (__mips16_floatsisf) ! 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) ! 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) ! /* Double-precision math. */ ! /* Define a function NAME that loads two double-precision values, ! performs FPU operation OPCODE on them, and returns the double- ! precision result. */ ! #define OPDF3(NAME, OPCODE) \ STARTFN (NAME); \ ! MOVE_DF_BYTE0 (t); \ ! MOVE_DF_BYTE8 (t); \ ! OPCODE RET,ARG1,ARG2; \ ! MOVE_DF_RET (f, $31); \ ENDFN (NAME) #ifdef L_m16adddf3 ! OPDF3 (__mips16_adddf3, add.d) #endif #ifdef L_m16subdf3 ! OPDF3 (__mips16_subdf3, sub.d) #endif #ifdef L_m16muldf3 ! OPDF3 (__mips16_muldf3, mul.d) #endif #ifdef L_m16divdf3 ! OPDF3 (__mips16_divdf3, div.d) #endif ! /* 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); \ ! MOVE_DF_BYTE0 (t); \ ! OPCODE RET,ARG1; \ ! MOVE_DF_RET (f, $31); \ ENDFN (NAME) #ifdef L_m16negdf2 ! OPDF2 (__mips16_negdf2, neg.d) #endif #ifdef L_m16absdf2 ! OPDF2 (__mips16_absdf2, abs.d) #endif /* Conversions between single and double precision. */ #ifdef L_m16extsfdf2 STARTFN (__mips16_extendsfdf2) ! MOVE_SF_BYTE0 (t) ! cvt.d.s RET,ARG1 ! MOVE_DF_RET (f, $31) ENDFN (__mips16_extendsfdf2) #endif #ifdef L_m16trdfsf2 STARTFN (__mips16_truncdfsf2) ! MOVE_DF_BYTE0 (t) ! cvt.s.d RET,ARG1 ! MOVE_SF_RET (f, $31) ENDFN (__mips16_truncdfsf2) #endif ! /* Double-precision comparisons. */ ! /* 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 CMPDF(NAME, OPCODE, TRUE, FALSE) \ STARTFN (NAME); \ ! MOVE_DF_BYTE0 (t); \ ! MOVE_DF_BYTE8 (t); \ ! OPCODE ARG1,ARG2; \ li $2,TRUE; \ bc1t 1f; \ li $2,FALSE; \ *************** STARTFN (NAME); \ *** 324,336 **** j $31; \ ENDFN (NAME) ! /* This macro is like DFCMP, but it reverses the comparison. */ ! #define DFREVCMP(NAME, OPCODE, TRUE, FALSE) \ STARTFN (NAME); \ ! LDDBL1; \ ! LDDBL2; \ ! OPCODE $f14,$f12; \ li $2,TRUE; \ bc1t 1f; \ li $2,FALSE; \ --- 388,400 ---- j $31; \ ENDFN (NAME) ! /* Like CMPDF, but reverse the comparison operands. */ ! #define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \ STARTFN (NAME); \ ! MOVE_DF_BYTE0 (t); \ ! MOVE_DF_BYTE8 (t); \ ! OPCODE ARG2,ARG1; \ li $2,TRUE; \ bc1t 1f; \ li $2,FALSE; \ *************** STARTFN (NAME); \ *** 339,512 **** ENDFN (NAME) #ifdef L_m16eqdf2 ! DFCMP(__mips16_eqdf2, c.eq.d, 0, 1) #endif #ifdef L_m16nedf2 ! DFCMP(__mips16_nedf2, c.eq.d, 0, 1) #endif #ifdef L_m16gtdf2 ! DFREVCMP(__mips16_gtdf2, c.lt.d, 1, 0) #endif #ifdef L_m16gedf2 ! DFREVCMP(__mips16_gedf2, c.le.d, 0, -1) #endif #ifdef L_m16ledf2 ! DFCMP(__mips16_ledf2, c.le.d, 0, 1) #endif #ifdef L_m16ltdf2 ! DFCMP(__mips16_ltdf2, c.lt.d, -1, 0) #endif ! /* 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 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 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. */ #ifdef L_m16retsf ! STARTFN (__mips16_ret_sf) ! .set noreorder ! j $31 ! mtc1 $2,$f0 ! .set reorder ! ENDFN (__mips16_ret_sf) #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 #endif ! .set reorder ! ENDFN (__mips16_ret_df) #endif #endif /* !__mips_single_float */ /* 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. */ #ifdef L_m16stub1 ! /* (float) */ ! STARTFN (__mips16_call_stub_1) ! .set noreorder ! mtc1 $4,$f12 ! j $2 ! nop ! .set reorder ! ENDFN (__mips16_call_stub_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) #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) #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) #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) #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) #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 will arrange to preserve $18, so these functions are free to use it to hold the return address. --- 403,527 ---- ENDFN (NAME) #ifdef L_m16eqdf2 ! CMPDF (__mips16_eqdf2, c.eq.d, 0, 1) #endif #ifdef L_m16nedf2 ! CMPDF (__mips16_nedf2, c.eq.d, 0, 1) #endif #ifdef L_m16gtdf2 ! REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0) #endif #ifdef L_m16gedf2 ! REVCMPDF (__mips16_gedf2, c.le.d, 0, -1) #endif #ifdef L_m16ledf2 ! CMPDF (__mips16_ledf2, c.le.d, 0, 1) #endif #ifdef L_m16ltdf2 ! CMPDF (__mips16_ltdf2, c.lt.d, -1, 0) #endif ! /* Double-precision conversions. */ #ifdef L_m16fltsidf STARTFN (__mips16_floatsidf) ! 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) ! MOVE_DF_BYTE0 (t) ! trunc.w.d RET,ARG1,$4 ! MOVE_SI_RET (f, $31) ENDFN (__mips16_fix_truncdfsi) #endif #endif /* !__mips_single_float */ ! /* 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 ! 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 ! RET_FUNCTION (__mips16_ret_df, DF) #endif ! ! #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 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 ! CALL_STUB_NO_RET (__mips16_call_stub_1, 1) #endif #ifdef L_m16stub5 ! CALL_STUB_NO_RET (__mips16_call_stub_5, 5) #endif #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) #ifdef L_m16stub2 ! CALL_STUB_NO_RET (__mips16_call_stub_2, 2) #endif #ifdef L_m16stub6 ! CALL_STUB_NO_RET (__mips16_call_stub_6, 6) #endif #ifdef L_m16stub9 ! CALL_STUB_NO_RET (__mips16_call_stub_9, 9) #endif #ifdef L_m16stub10 ! 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, 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. *************** STARTFN (__mips16_call_stub_10) *** 517,739 **** being called is 16 bits, in which case the copy is unnecessary; however, it's faster to always do the copy. */ #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) #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) #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) #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) #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) #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) #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) #endif /* Now we have the same set of functions again, except that this time the function being called returns an DFmode value. */ #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) #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) #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) #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) #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) #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) #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) #endif #endif /* !__mips_single_float */ --- 532,674 ---- 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 ! CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF) #endif #ifdef L_m16stubsf1 ! CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF) #endif #ifdef L_m16stubsf5 ! CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF) #endif #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) #ifdef L_m16stubsf2 ! CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF) #endif #ifdef L_m16stubsf6 ! CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF) #endif #ifdef L_m16stubsf9 ! CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF) #endif #ifdef L_m16stubsf10 ! 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 ! CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF) #endif #ifdef L_m16stubdf1 ! CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF) #endif ! #ifdef L_m16stubdf5 ! CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF) #endif ! #ifdef L_m16stubdf2 ! CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF) #endif #ifdef L_m16stubdf6 ! CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF) #endif #ifdef L_m16stubdf9 ! CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF) #endif #ifdef L_m16stubdf10 ! 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 */ Index: gcc/config/mips/t-elf =================================================================== *** gcc/config/mips/t-elf (revision 124934) --- gcc/config/mips/t-elf (working copy) *************** LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m1 *** 19,29 **** _m16eqdf2 _m16nedf2 _m16gtdf2 _m16gedf2 _m16ledf2 _m16ltdf2 \ _m16fltsidf _m16fix_truncdfsi \ _m16retsf _m16retdf \ _m16stub1 _m16stub2 _m16stub5 _m16stub6 _m16stub9 _m16stub10 \ _m16stubsf0 _m16stubsf1 _m16stubsf2 _m16stubsf5 _m16stubsf6 \ _m16stubsf9 _m16stubsf10 \ _m16stubdf0 _m16stubdf1 _m16stubdf2 _m16stubdf5 _m16stubdf6 \ ! _m16stubdf9 _m16stubdf10 # We must build libgcc2.a with -G 0, in case the user wants to link # without the $gp register. --- 19,34 ---- _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 \ ! _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. Index: gcc/config/mips/t-isa3264 =================================================================== *** gcc/config/mips/t-isa3264 (revision 124934) --- gcc/config/mips/t-isa3264 (working copy) *************** LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m1 *** 19,29 **** _m16eqdf2 _m16nedf2 _m16gtdf2 _m16gedf2 _m16ledf2 _m16ltdf2 \ _m16fltsidf _m16fix_truncdfsi \ _m16retsf _m16retdf \ _m16stub1 _m16stub2 _m16stub5 _m16stub6 _m16stub9 _m16stub10 \ _m16stubsf0 _m16stubsf1 _m16stubsf2 _m16stubsf5 _m16stubsf6 \ _m16stubsf9 _m16stubsf10 \ _m16stubdf0 _m16stubdf1 _m16stubdf2 _m16stubdf5 _m16stubdf6 \ ! _m16stubdf9 _m16stubdf10 # We must build libgcc2.a with -G 0, in case the user wants to link # without the $gp register. --- 19,34 ---- _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 \ ! _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. Index: gcc/config/mips/t-r3900 =================================================================== *** gcc/config/mips/t-r3900 (revision 124934) --- gcc/config/mips/t-r3900 (working copy) *************** LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m1 *** 7,17 **** _m16eqdf2 _m16nedf2 _m16gtdf2 _m16gedf2 _m16ledf2 _m16ltdf2 \ _m16fltsidf _m16fix_truncdfsi \ _m16retsf _m16retdf \ _m16stub1 _m16stub2 _m16stub5 _m16stub6 _m16stub9 _m16stub10 \ _m16stubsf0 _m16stubsf1 _m16stubsf2 _m16stubsf5 _m16stubsf6 \ _m16stubsf9 _m16stubsf10 \ _m16stubdf0 _m16stubdf1 _m16stubdf2 _m16stubdf5 _m16stubdf6 \ ! _m16stubdf9 _m16stubdf10 # We must build libgcc2.a with -G 0, in case the user wants to link # without the $gp register. --- 7,22 ---- _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 \ ! _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. Index: gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c =================================================================== *** gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c (revision 0) --- gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c (revision 0) *************** *** 0 **** --- 1,10 ---- + extern void init (void); + extern void test (void); + + int + main (void) + { + init (); + test (); + return 0; + } Index: gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c =================================================================== *** gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c (revision 0) --- gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c (revision 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); + } Index: gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c =================================================================== *** gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c (revision 0) --- gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c (revision 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; + } Index: gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp =================================================================== *** gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp (revision 0) --- gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp (revision 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 --------------070502060501000700090309--