* PATCH: mips16 float and complex support
@ 2007-05-23 0:37 Sandra Loosemore
2007-05-23 7:59 ` Richard Sandiford
0 siblings, 1 reply; 3+ messages in thread
From: Sandra Loosemore @ 2007-05-23 0:37 UTC (permalink / raw)
To: GCC Patches
[-- Attachment #1: Type: text/plain, Size: 495 bytes --]
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
[-- Attachment #2: 06-mips16-hardfloat.log --]
[-- Type: text/x-log, Size: 4919 bytes --]
2007-05-22 Sandra Loosemore <sandra@codesourcery.com>
Nigel Stephens <nigel@mips.com>
Richard Sandiford <richard@codesourcery.com>
gcc/
Fix up MIPS16 hard float and add support for complex.
* config/mips/mips.h (TARGET_HARD_FLOAT_ABI): New.
(TARGET_SOFT_FLOAT_ABI): New.
(TARGET_CPU_CPP_BUILTINS): Define __mips_hard_float and
__mips_soft_float to reflect the ABI in use, not whether the
FPU is directly accessible (e.g., in MIPS16 mode).
(UNITS_PER_HWFPVALUE): Use TARGET_SOFT_FLOAT_ABI.
(UNITS_PER_FPVALUE): Likewise.
* config/mips/mips.c (mips_expand_call): Remove redundant
TARGET_MIPS16 check.
(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.
[-- Attachment #3: 06-mips16-hardfloat.patch --]
[-- Type: text/x-patch, Size: 71643 bytes --]
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 <stdlib.h>
+
+ /* All the function pointers are declared and initialized in
+ mips16-stubs-2.c. */
+
+ extern double the_result;
+
+ extern void v0 (void);
+ extern void v1 (float);
+ extern void v5 (float, float);
+ extern void v9 (float, double);
+ extern void v2 (double);
+ extern void v6 (double, float);
+ extern void v10 (double, double);
+
+ extern float f0 (void);
+ extern float f1 (float);
+ extern float f5 (float, float);
+ extern float f9 (float, double);
+ extern float f2 (double);
+ extern float f6 (double, float);
+ extern float f10 (double, double);
+
+ extern double d0 (void);
+ extern double d1 (float);
+ extern double d5 (float, float);
+ extern double d9 (float, double);
+ extern double d2 (double);
+ extern double d6 (double, float);
+ extern double d10 (double, double);
+
+ extern _Complex float cf0 (void);
+ extern _Complex float cf1 (float);
+ extern _Complex float cf5 (float, float);
+ extern _Complex float cf9 (float, double);
+ extern _Complex float cf2 (double);
+ extern _Complex float cf6 (double, float);
+ extern _Complex float cf10 (double, double);
+
+ extern _Complex double cd0 (void);
+ extern _Complex double cd1 (float);
+ extern _Complex double cd5 (float, float);
+ extern _Complex double cd9 (float, double);
+ extern _Complex double cd2 (double);
+ extern _Complex double cd6 (double, float);
+ extern _Complex double cd10 (double, double);
+
+ extern void (*pv0) (void);
+ extern void (*pv1) (float);
+ extern void (*pv5) (float, float);
+ extern void (*pv9) (float, double);
+ extern void (*pv2) (double);
+ extern void (*pv6) (double, float);
+ extern void (*pv10) (double, double);
+
+ extern float (*pf0) (void);
+ extern float (*pf1) (float);
+ extern float (*pf5) (float, float);
+ extern float (*pf9) (float, double);
+ extern float (*pf2) (double);
+ extern float (*pf6) (double, float);
+ extern float (*pf10) (double, double);
+
+ extern double (*pd0) (void);
+ extern double (*pd1) (float);
+ extern double (*pd5) (float, float);
+ extern double (*pd9) (float, double);
+ extern double (*pd2) (double);
+ extern double (*pd6) (double, float);
+ extern double (*pd10) (double, double);
+
+ extern _Complex float (*pcf0) (void);
+ extern _Complex float (*pcf1) (float);
+ extern _Complex float (*pcf5) (float, float);
+ extern _Complex float (*pcf9) (float, double);
+ extern _Complex float (*pcf2) (double);
+ extern _Complex float (*pcf6) (double, float);
+ extern _Complex float (*pcf10) (double, double);
+
+ extern _Complex double (*pcd0) (void);
+ extern _Complex double (*pcd1) (float);
+ extern _Complex double (*pcd5) (float, float);
+ extern _Complex double (*pcd9) (float, double);
+ extern _Complex double (*pcd2) (double);
+ extern _Complex double (*pcd6) (double, float);
+ extern _Complex double (*pcd10) (double, double);
+
+ /* Macros for results checking. */
+ #define CHECK_RESULT(x, y) if ((x) != (y)) abort ()
+ #define CHECK_VOID_RESULT(x, y) CHECK_RESULT (((x), the_result), y)
+
+ /* Call functions through pointers and and check against expected results. */
+ void
+ test (void)
+ {
+
+ CHECK_VOID_RESULT (v0 (), 1.0);
+ CHECK_VOID_RESULT (v1 (1.0), 2.0);
+ CHECK_VOID_RESULT (v5 (5.0, 6.0), 12.0);
+ CHECK_VOID_RESULT (v9 (9.0, 10.0), 20.0);
+ CHECK_VOID_RESULT (v2 (2.0), 3.0);
+ CHECK_VOID_RESULT (v6 (6.0, 7.0), 14.0);
+ CHECK_VOID_RESULT (v10 (10.0, 11.0), 22.0);
+
+ CHECK_RESULT (f0 (), 1.0);
+ CHECK_RESULT (f1 (1.0), 2.0);
+ CHECK_RESULT (f5 (5.0, 6.0), 12.0);
+ CHECK_RESULT (f9 (9.0, 10.0), 20.0);
+ CHECK_RESULT (f2 (2.0), 3.0);
+ CHECK_RESULT (f6 (6.0, 7.0), 14.0);
+ CHECK_RESULT (f10 (10.0, 11.0), 22.0);
+
+ CHECK_RESULT (d0 (), 1.0);
+ CHECK_RESULT (d1 (1.0), 2.0);
+ CHECK_RESULT (d5 (5.0, 6.0), 12.0);
+ CHECK_RESULT (d9 (9.0, 10.0), 20.0);
+ CHECK_RESULT (d2 (2.0), 3.0);
+ CHECK_RESULT (d6 (6.0, 7.0), 14.0);
+ CHECK_RESULT (d10 (10.0, 11.0), 22.0);
+
+ CHECK_RESULT (cf0 (), 1.0 + 0.0i);
+ CHECK_RESULT (cf1 (1.0), 2.0 + 1.0i);
+ CHECK_RESULT (cf5 (5.0, 6.0), 12.0 + 5.0i);
+ CHECK_RESULT (cf9 (9.0, 10.0), 20.0 + 9.0i);
+ CHECK_RESULT (cf2 (2.0), 3.0 + 2.0i);
+ CHECK_RESULT (cf6 (6.0, 7.0), 14.0 + 6.0i);
+ CHECK_RESULT (cf10 (10.0, 11.0), 22.0 + 10.0i);
+
+ CHECK_RESULT (cd0 (), 1.0 + 0.0i);
+ CHECK_RESULT (cd1 (1.0), 2.0 + 1.0i);
+ CHECK_RESULT (cd5 (5.0, 6.0), 12.0 + 5.0i);
+ CHECK_RESULT (cd9 (9.0, 10.0), 20.0 + 9.0i);
+ CHECK_RESULT (cd2 (2.0), 3.0 + 2.0i);
+ CHECK_RESULT (cd6 (6.0, 7.0), 14.0 + 6.0i);
+ CHECK_RESULT (cd10 (10.0, 11.0), 22.0 + 10.0i);
+
+ CHECK_VOID_RESULT ((*pv0) (), 1.0);
+ CHECK_VOID_RESULT ((*pv1) (1.0), 2.0);
+ CHECK_VOID_RESULT ((*pv5) (5.0, 6.0), 12.0);
+ CHECK_VOID_RESULT ((*pv9) (9.0, 10.0), 20.0);
+ CHECK_VOID_RESULT ((*pv2) (2.0), 3.0);
+ CHECK_VOID_RESULT ((*pv6) (6.0, 7.0), 14.0);
+ CHECK_VOID_RESULT ((*pv10) (10.0, 11.0), 22.0);
+
+ CHECK_RESULT ((*pf0) (), 1.0);
+ CHECK_RESULT ((*pf1) (1.0), 2.0);
+ CHECK_RESULT ((*pf5) (5.0, 6.0), 12.0);
+ CHECK_RESULT ((*pf9) (9.0, 10.0), 20.0);
+ CHECK_RESULT ((*pf2) (2.0), 3.0);
+ CHECK_RESULT ((*pf6) (6.0, 7.0), 14.0);
+ CHECK_RESULT ((*pf10) (10.0, 11.0), 22.0);
+
+ CHECK_RESULT ((*pd0) (), 1.0);
+ CHECK_RESULT ((*pd1) (1.0), 2.0);
+ CHECK_RESULT ((*pd5) (5.0, 6.0), 12.0);
+ CHECK_RESULT ((*pd9) (9.0, 10.0), 20.0);
+ CHECK_RESULT ((*pd2) (2.0), 3.0);
+ CHECK_RESULT ((*pd6) (6.0, 7.0), 14.0);
+ CHECK_RESULT ((*pd10) (10.0, 11.0), 22.0);
+
+ CHECK_RESULT ((*pcf0) (), 1.0 + 0.0i);
+ CHECK_RESULT ((*pcf1) (1.0), 2.0 + 1.0i);
+ CHECK_RESULT ((*pcf5) (5.0, 6.0), 12.0 + 5.0i);
+ CHECK_RESULT ((*pcf9) (9.0, 10.0), 20.0 + 9.0i);
+ CHECK_RESULT ((*pcf2) (2.0), 3.0 + 2.0i);
+ CHECK_RESULT ((*pcf6) (6.0, 7.0), 14.0 + 6.0i);
+ CHECK_RESULT ((*pcf10) (10.0, 11.0), 22.0 + 10.0i);
+
+ CHECK_RESULT ((*pcd0) (), 1.0 + 0.0i);
+ CHECK_RESULT ((*pcd1) (1.0), 2.0 + 1.0i);
+ CHECK_RESULT ((*pcd5) (5.0, 6.0), 12.0 + 5.0i);
+ CHECK_RESULT ((*pcd9) (9.0, 10.0), 20.0 + 9.0i);
+ CHECK_RESULT ((*pcd2) (2.0), 3.0 + 2.0i);
+ CHECK_RESULT ((*pcd6) (6.0, 7.0), 14.0 + 6.0i);
+ CHECK_RESULT ((*pcd10) (10.0, 11.0), 22.0 + 10.0i);
+ }
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
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: PATCH: mips16 float and complex support
2007-05-23 0:37 PATCH: mips16 float and complex support Sandra Loosemore
@ 2007-05-23 7:59 ` Richard Sandiford
2007-05-23 20:05 ` Sandra Loosemore
0 siblings, 1 reply; 3+ messages in thread
From: Richard Sandiford @ 2007-05-23 7:59 UTC (permalink / raw)
To: Sandra Loosemore; +Cc: GCC Patches
Sandra Loosemore <sandra@codesourcery.com> writes:
> *************** 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
Please move mips_arg_regno before this function and replace the above
if-else block with:
return mips_arg_regno (mode, TARGET_HARD_FLOAT);
> + /* Return a two-character string representing a function floating
> + point return mode, used to name MIPS16 function stubs. */
Nit, but: "floating point" -> "floating-point"? (Probably my fault.)
> + /* 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. */
"pased" -> "passed" and "single register" -> "single-register".
(Definitely my fault, sorry.)
OK with those changes. Thanks for putting so much effort into this.
Richard
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: PATCH: mips16 float and complex support
2007-05-23 7:59 ` Richard Sandiford
@ 2007-05-23 20:05 ` Sandra Loosemore
0 siblings, 0 replies; 3+ messages in thread
From: Sandra Loosemore @ 2007-05-23 20:05 UTC (permalink / raw)
To: GCC Patches, richard
[-- Attachment #1: Type: text/plain, Size: 168 bytes --]
Richard Sandiford wrote:
> OK with those changes. Thanks for putting so much effort into this.
OK, the patch has been committed with the suggested tweaks.
-Sandra
[-- Attachment #2: 06-mips16-hardfloat.log --]
[-- Type: text/x-log, Size: 4914 bytes --]
2007-05-23 Sandra Loosemore <sandra@codesourcery.com>
Nigel Stephens <nigel@mips.com>
Richard Sandiford <richard@codesourcery.com>
gcc/
Fix up MIPS16 hard float and add support for complex.
* config/mips/mips.h (TARGET_HARD_FLOAT_ABI): New.
(TARGET_SOFT_FLOAT_ABI): New.
(TARGET_CPU_CPP_BUILTINS): Define __mips_hard_float and
__mips_soft_float to reflect the ABI in use, not whether the
FPU is directly accessible (e.g., in MIPS16 mode).
(UNITS_PER_HWFPVALUE): Use TARGET_SOFT_FLOAT_ABI.
(UNITS_PER_FPVALUE): Likewise.
* config/mips/mips.c (mips_expand_call): Remove redundant
TARGET_MIPS16 check.
(mips_arg_regno): New.
(function_arg_advance): When setting bits in cum->fp_code for
MIPS16, don't subtract 1 from cum->arg_number, since it is now
zero-based.
(function_arg): Use mips_arg_regno.
(mips_return_mode_in_fpr_p): New.
(mips16_call_stub_mode_suffix): New.
(mips16_cfun_returns_in_fpr_p): New.
(mips_save_reg_p): Use mips16_cfun_returns_in_fpr_p.
(mips_output_function_prologue): Test mips16_hard_float, not
!TARGET_SOFT_FLOAT, to decide when a function stub is required.
(mips_expand_epilogue): Call MIPS16 helper routines to copy
return value into a floating-point register.
(mips_can_use_return_insn): Use mips16_cfun_returns_in_fpr_p.
(mips_function_value): Rewrite to use mips_return_mode_in_fpr_p.
(mips16_fp_args): Handle MIPS32r2 ISA which supports
TARGET_FLOAT64, and use mfhc1/mthc1 to copy the most significant
word of double arguments from or to the high bits of 64-bit
floating point registers.
(build_mips16_function_stub): Fill in DECL_RESULT for stubdecl.
(mips16_fpret_double): New helper function.
(build_mips16_call_stub): Use mips16_return_mode_in_fpr_p. Add
support for complex modes. Fill in DECL_RESULT for stubdecl.
(mips_init_libfuncs): Remove redundant TARGET_MIPS16 check.
* config/mips/mips16.S
(RET, ARG1, ARG2): New.
(MERGE_GPRf, MERGE_GPRt): New.
(DELAYt, DELAYf): New.
(MOVE_SF_BYTE0, MOVE_SI_BYTE0): New.
(MOVE_SF_BYTE4, MOVE_SF_BYTE8): New.
(MOVE_DF_BYTE0, MOVE_DF_BYTE8): New.
(MOVE_SF_RET, MOVE_SC_RET, MOVE_DF_RET, MOVE_DC_RET, MOVE_SI_RET): New.
(SFOP): Renamed to...
(OPSF3): This, and macro-ified. Updated all uses.
(SFOP2): Renamed to...
(OPSF2): This, and macro-ified. Updated all uses.
(SFCMP): Renamed to...
(CMPSF): This, and macro-ified. Updated all uses.
(SFREVCMP): Renamed to...
(REVCMPSF): This, and macro-ified. Updated all uses.
(__mips16_floatsisf, __mips16_fix_truncsfsi): Macro-ified.
(LDDBL1, LDDBL2, RETDBL): Deleted.
(DFOP): Renamed to...
(OPDF3): This, and macro-ified. Updated all uses.
(DFOP2): Renamed to...
(OPDF2): This, and macro-ified. Updated all uses.
(__mips16_extendsfdf2, __mips16_truncdfsf2): Macro-ified.
(DFCMP): Renamed to...
(CMPDF): This, and macro-ified. Updated all uses.
(DFREVCMP): Renamed to...
(REVCMPDF): This, and macro-ified. Updated all uses.
(__mips16_floatsidf, __mips16_fix_truncdfsi): Macro-ified.
(RET_FUNCTION): New.
(__mips16_ret_sf, __mips16_ret_df): Macro-ified.
(__mips16_ret_sc, __mips16_ret_dc): New.
(STUB_ARGS_0, STUB_ARGS_1, STUB_ARGS_5, STUB_ARGS_9, STUB_ARGS_2,
STUB_ARGS_6, STUB_ARGS_10): New.
(CALL_STUB_NO_RET): New.
(__mips16_call_stub_1): Macro-ified.
(__mips16_call_stub_5): Macro-ified.
(__mips16_call_stub_2): Macro-ified.
(__mips16_call_stub_6): Macro-ified.
(__mips16_call_stub_9): Macro-ified.
(__mips16_call_stub_10): Macro-ified.
(CALL_STUB_RET): New.
(__mips16_call_stub_sf_0): Macro-ified.
(__mips16_call_stub_sf_1): Macro-ified.
(__mips16_call_stub_sf_5): Macro-ified.
(__mips16_call_stub_sf_2): Macro-ified.
(__mips16_call_stub_sf_6): Macro-ified.
(__mips16_call_stub_sf_9): Macro-ified.
(__mips16_call_stub_sf_10): Macro-ified.
(__mips16_call_stub_df_0): Macro-ified.
(__mips16_call_stub_df_1): Macro-ified.
(__mips16_call_stub_df_5): Macro-ified.
(__mips16_call_stub_df_2): Macro-ified.
(__mips16_call_stub_df_6): Macro-ified.
(__mips16_call_stub_df_9): Macro-ified.
(__mips16_call_stub_df_10): Macro-ified.
(__mips16_call_stub_sc_0): New.
(__mips16_call_stub_sc_1): New.
(__mips16_call_stub_sc_5): New.
(__mips16_call_stub_sc_2): New.
(__mips16_call_stub_sc_6): New.
(__mips16_call_stub_sc_9): New.
(__mips16_call_stub_sc_10): New.
(__mips16_call_stub_dc_0): New.
(__mips16_call_stub_dc_1): New.
(__mips16_call_stub_dc_5): New.
(__mips16_call_stub_dc_2): New.
(__mips16_call_stub_dc_6): New.
(__mips16_call_stub_dc_9): New.
(__mips16_call_stub_dc_10): New.
* config/mips/t-elf (LIB1ASMFUNCS): Add MIPS16 floating-point stubs.
* config/mips/t-isa3264 (LIB1ASMFUNCS): Likewise.
* config/mips/t-r2900 (LIB1ASMFUNCS): Likewise.
gcc/testsuite/
* gcc.target/mips/inter/mips16_stubs_1_main.c: New.
* gcc.target/mips/inter/mips16_stubs_1_x.c: New.
* gcc.target/mips/inter/mips16_stubs_1_y.c: New.
* gcc.target/mips/inter/mips16-inter.exp: New.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2007-05-23 20:05 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-05-23 0:37 PATCH: mips16 float and complex support Sandra Loosemore
2007-05-23 7:59 ` Richard Sandiford
2007-05-23 20:05 ` Sandra Loosemore
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).