]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix up MIPS16 hard float and add support for complex.
authorSandra Loosemore <sandra@codesourcery.com>
Wed, 23 May 2007 20:03:00 +0000 (16:03 -0400)
committerSandra Loosemore <sandra@gcc.gnu.org>
Wed, 23 May 2007 20:03:00 +0000 (16:03 -0400)
2007-05-23  Sandra Loosemore  <sandra@codesourcery.com>
    Nigel Stephens  <nigel@mips.com>
    Richard Sandiford  <richard@codesourcery.com>

gcc/
Fix up MIPS16 hard float and add support for complex.

* config/mips/mips.h (TARGET_HARD_FLOAT_ABI): New.
(TARGET_SOFT_FLOAT_ABI): New.
(TARGET_CPU_CPP_BUILTINS): Define __mips_hard_float and
__mips_soft_float to reflect the ABI in use, not whether the
FPU is directly accessible (e.g., in MIPS16 mode).
(UNITS_PER_HWFPVALUE): Use TARGET_SOFT_FLOAT_ABI.
(UNITS_PER_FPVALUE): Likewise.

* config/mips/mips.c (mips_expand_call): Remove redundant
TARGET_MIPS16 check.
(mips_arg_regno): New.
(function_arg_advance): When setting bits in cum->fp_code for
MIPS16, don't subtract 1 from cum->arg_number, since it is now
zero-based.
(function_arg): Use mips_arg_regno.
(mips_return_mode_in_fpr_p): New.
(mips16_call_stub_mode_suffix): New.
(mips16_cfun_returns_in_fpr_p): New.
(mips_save_reg_p): Use mips16_cfun_returns_in_fpr_p.
(mips_output_function_prologue): Test mips16_hard_float, not
!TARGET_SOFT_FLOAT, to decide when a function stub is required.
(mips_expand_epilogue): Call MIPS16 helper routines to copy
return value into a floating-point register.
(mips_can_use_return_insn): Use mips16_cfun_returns_in_fpr_p.
(mips_function_value): Rewrite to use mips_return_mode_in_fpr_p.
(mips16_fp_args): Handle MIPS32r2 ISA which supports
TARGET_FLOAT64, and use mfhc1/mthc1 to copy the most significant
word of double arguments from or to the high bits of 64-bit
floating point registers.
(build_mips16_function_stub): Fill in DECL_RESULT for stubdecl.
(mips16_fpret_double): New helper function.
(build_mips16_call_stub): Use mips16_return_mode_in_fpr_p.  Add
support for complex modes.  Fill in DECL_RESULT for stubdecl.
(mips_init_libfuncs): Remove redundant TARGET_MIPS16 check.

* config/mips/mips16.S
(RET, ARG1, ARG2): New.
(MERGE_GPRf, MERGE_GPRt): New.
(DELAYt, DELAYf): New.
(MOVE_SF_BYTE0, MOVE_SI_BYTE0): New.
(MOVE_SF_BYTE4, MOVE_SF_BYTE8): New.
(MOVE_DF_BYTE0, MOVE_DF_BYTE8): New.
(MOVE_SF_RET, MOVE_SC_RET, MOVE_DF_RET, MOVE_DC_RET, MOVE_SI_RET): New.
(SFOP): Renamed to...
(OPSF3): This, and macro-ified.  Updated all uses.
(SFOP2): Renamed to...
(OPSF2): This, and macro-ified.  Updated all uses.
(SFCMP): Renamed to...
(CMPSF): This, and macro-ified.  Updated all uses.
(SFREVCMP): Renamed to...
(REVCMPSF): This, and macro-ified.  Updated all uses.
(__mips16_floatsisf, __mips16_fix_truncsfsi): Macro-ified.
(LDDBL1, LDDBL2, RETDBL): Deleted.
(DFOP): Renamed to...
(OPDF3): This, and macro-ified.  Updated all uses.
(DFOP2): Renamed to...
(OPDF2): This, and macro-ified.  Updated all uses.
(__mips16_extendsfdf2, __mips16_truncdfsf2): Macro-ified.
(DFCMP): Renamed to...
(CMPDF): This, and macro-ified.  Updated all uses.
(DFREVCMP): Renamed to...
(REVCMPDF): This, and macro-ified.  Updated all uses.
(__mips16_floatsidf, __mips16_fix_truncdfsi): Macro-ified.
(RET_FUNCTION): New.
(__mips16_ret_sf, __mips16_ret_df): Macro-ified.
(__mips16_ret_sc, __mips16_ret_dc): New.
(STUB_ARGS_0, STUB_ARGS_1, STUB_ARGS_5, STUB_ARGS_9, STUB_ARGS_2,
STUB_ARGS_6, STUB_ARGS_10): New.
(CALL_STUB_NO_RET): New.
(__mips16_call_stub_1): Macro-ified.
(__mips16_call_stub_5): Macro-ified.
(__mips16_call_stub_2): Macro-ified.
(__mips16_call_stub_6): Macro-ified.
(__mips16_call_stub_9): Macro-ified.
(__mips16_call_stub_10): Macro-ified.
(CALL_STUB_RET): New.
(__mips16_call_stub_sf_0): Macro-ified.
(__mips16_call_stub_sf_1): Macro-ified.
(__mips16_call_stub_sf_5): Macro-ified.
(__mips16_call_stub_sf_2): Macro-ified.
(__mips16_call_stub_sf_6): Macro-ified.
(__mips16_call_stub_sf_9): Macro-ified.
(__mips16_call_stub_sf_10): Macro-ified.
(__mips16_call_stub_df_0): Macro-ified.
(__mips16_call_stub_df_1): Macro-ified.
(__mips16_call_stub_df_5): Macro-ified.
(__mips16_call_stub_df_2): Macro-ified.
(__mips16_call_stub_df_6): Macro-ified.
(__mips16_call_stub_df_9): Macro-ified.
(__mips16_call_stub_df_10): Macro-ified.
(__mips16_call_stub_sc_0): New.
(__mips16_call_stub_sc_1): New.
(__mips16_call_stub_sc_5): New.
(__mips16_call_stub_sc_2): New.
(__mips16_call_stub_sc_6): New.
(__mips16_call_stub_sc_9): New.
(__mips16_call_stub_sc_10): New.
(__mips16_call_stub_dc_0): New.
(__mips16_call_stub_dc_1): New.
(__mips16_call_stub_dc_5): New.
(__mips16_call_stub_dc_2): New.
(__mips16_call_stub_dc_6): New.
(__mips16_call_stub_dc_9): New.
(__mips16_call_stub_dc_10): New.

* config/mips/t-elf (LIB1ASMFUNCS): Add MIPS16 floating-point stubs.
* config/mips/t-isa3264 (LIB1ASMFUNCS): Likewise.
* config/mips/t-r2900 (LIB1ASMFUNCS): Likewise.

gcc/testsuite/
* gcc.target/mips/inter/mips16_stubs_1_main.c: New.
* gcc.target/mips/inter/mips16_stubs_1_x.c: New.
* gcc.target/mips/inter/mips16_stubs_1_y.c: New.
* gcc.target/mips/inter/mips16-inter.exp: New.

Co-Authored-By: Nigel Stephens <nigel@mips.com>
Co-Authored-By: Richard Sandiford <richard@codesourcery.com>
From-SVN: r124999

12 files changed:
gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips16.S
gcc/config/mips/t-elf
gcc/config/mips/t-isa3264
gcc/config/mips/t-r3900
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c [new file with mode: 0644]

index 941700ecd49422cb62e862e8aafd55068ebeb222..414b1eb377196c1df282d395d25c9e97e0e06640 100644 (file)
@@ -1,3 +1,118 @@
+2007-05-23  Sandra Loosemore  <sandra@codesourcery.com>
+           Nigel Stephens  <nigel@mips.com>
+           Richard Sandiford  <richard@codesourcery.com>
+
+       Fix up MIPS16 hard float and add support for complex.
+
+       * config/mips/mips.h (TARGET_HARD_FLOAT_ABI): New.
+       (TARGET_SOFT_FLOAT_ABI): New.
+       (TARGET_CPU_CPP_BUILTINS): Define __mips_hard_float and
+       __mips_soft_float to reflect the ABI in use, not whether the
+       FPU is directly accessible (e.g., in MIPS16 mode).
+       (UNITS_PER_HWFPVALUE): Use TARGET_SOFT_FLOAT_ABI.
+       (UNITS_PER_FPVALUE): Likewise.
+
+       * config/mips/mips.c (mips_expand_call): Remove redundant
+       TARGET_MIPS16 check.
+       (mips_arg_regno): New.
+       (function_arg_advance): When setting bits in cum->fp_code for
+       MIPS16, don't subtract 1 from cum->arg_number, since it is now
+       zero-based.
+       (function_arg): Use mips_arg_regno.
+       (mips_return_mode_in_fpr_p): New.
+       (mips16_call_stub_mode_suffix): New.
+       (mips16_cfun_returns_in_fpr_p): New.
+       (mips_save_reg_p): Use mips16_cfun_returns_in_fpr_p.
+       (mips_output_function_prologue): Test mips16_hard_float, not
+       !TARGET_SOFT_FLOAT, to decide when a function stub is required.
+       (mips_expand_epilogue): Call MIPS16 helper routines to copy
+       return value into a floating-point register.
+       (mips_can_use_return_insn): Use mips16_cfun_returns_in_fpr_p.
+       (mips_function_value): Rewrite to use mips_return_mode_in_fpr_p.
+       (mips16_fp_args): Handle MIPS32r2 ISA which supports
+       TARGET_FLOAT64, and use mfhc1/mthc1 to copy the most significant
+       word of double arguments from or to the high bits of 64-bit
+       floating point registers.
+       (build_mips16_function_stub): Fill in DECL_RESULT for stubdecl.
+       (mips16_fpret_double): New helper function.
+       (build_mips16_call_stub): Use mips16_return_mode_in_fpr_p.  Add
+       support for complex modes.  Fill in DECL_RESULT for stubdecl.
+       (mips_init_libfuncs): Remove redundant TARGET_MIPS16 check.
+
+       * config/mips/mips16.S 
+       (RET, ARG1, ARG2): New.
+       (MERGE_GPRf, MERGE_GPRt): New.
+       (DELAYt, DELAYf): New.
+       (MOVE_SF_BYTE0, MOVE_SI_BYTE0): New.
+       (MOVE_SF_BYTE4, MOVE_SF_BYTE8): New.
+       (MOVE_DF_BYTE0, MOVE_DF_BYTE8): New.
+       (MOVE_SF_RET, MOVE_SC_RET, MOVE_DF_RET, MOVE_DC_RET, MOVE_SI_RET): New.
+       (SFOP): Renamed to...
+       (OPSF3): This, and macro-ified.  Updated all uses.
+       (SFOP2): Renamed to...
+       (OPSF2): This, and macro-ified.  Updated all uses.
+       (SFCMP): Renamed to...
+       (CMPSF): This, and macro-ified.  Updated all uses.
+       (SFREVCMP): Renamed to...
+       (REVCMPSF): This, and macro-ified.  Updated all uses.
+       (__mips16_floatsisf, __mips16_fix_truncsfsi): Macro-ified.
+       (LDDBL1, LDDBL2, RETDBL): Deleted.
+       (DFOP): Renamed to...
+       (OPDF3): This, and macro-ified.  Updated all uses.
+       (DFOP2): Renamed to...
+       (OPDF2): This, and macro-ified.  Updated all uses.
+       (__mips16_extendsfdf2, __mips16_truncdfsf2): Macro-ified.
+       (DFCMP): Renamed to...
+       (CMPDF): This, and macro-ified.  Updated all uses.
+       (DFREVCMP): Renamed to...
+       (REVCMPDF): This, and macro-ified.  Updated all uses.
+       (__mips16_floatsidf, __mips16_fix_truncdfsi): Macro-ified.
+       (RET_FUNCTION): New.
+       (__mips16_ret_sf, __mips16_ret_df): Macro-ified.
+       (__mips16_ret_sc, __mips16_ret_dc): New.
+       (STUB_ARGS_0, STUB_ARGS_1, STUB_ARGS_5, STUB_ARGS_9, STUB_ARGS_2,
+       STUB_ARGS_6, STUB_ARGS_10): New.
+       (CALL_STUB_NO_RET): New.
+       (__mips16_call_stub_1): Macro-ified.
+       (__mips16_call_stub_5): Macro-ified.
+       (__mips16_call_stub_2): Macro-ified.
+       (__mips16_call_stub_6): Macro-ified.
+       (__mips16_call_stub_9): Macro-ified.
+       (__mips16_call_stub_10): Macro-ified.
+       (CALL_STUB_RET): New.
+       (__mips16_call_stub_sf_0): Macro-ified.
+       (__mips16_call_stub_sf_1): Macro-ified.
+       (__mips16_call_stub_sf_5): Macro-ified.
+       (__mips16_call_stub_sf_2): Macro-ified.
+       (__mips16_call_stub_sf_6): Macro-ified.
+       (__mips16_call_stub_sf_9): Macro-ified.
+       (__mips16_call_stub_sf_10): Macro-ified.
+       (__mips16_call_stub_df_0): Macro-ified.
+       (__mips16_call_stub_df_1): Macro-ified.
+       (__mips16_call_stub_df_5): Macro-ified.
+       (__mips16_call_stub_df_2): Macro-ified.
+       (__mips16_call_stub_df_6): Macro-ified.
+       (__mips16_call_stub_df_9): Macro-ified.
+       (__mips16_call_stub_df_10): Macro-ified.
+       (__mips16_call_stub_sc_0): New.
+       (__mips16_call_stub_sc_1): New.
+       (__mips16_call_stub_sc_5): New.
+       (__mips16_call_stub_sc_2): New.
+       (__mips16_call_stub_sc_6): New.
+       (__mips16_call_stub_sc_9): New.
+       (__mips16_call_stub_sc_10): New.
+       (__mips16_call_stub_dc_0): New.
+       (__mips16_call_stub_dc_1): New.
+       (__mips16_call_stub_dc_5): New.
+       (__mips16_call_stub_dc_2): New.
+       (__mips16_call_stub_dc_6): New.
+       (__mips16_call_stub_dc_9): New.
+       (__mips16_call_stub_dc_10): New.
+       
+       * config/mips/t-elf (LIB1ASMFUNCS): Add MIPS16 floating-point stubs.
+       * config/mips/t-isa3264 (LIB1ASMFUNCS): Likewise.
+       * config/mips/t-r2900 (LIB1ASMFUNCS): Likewise.
+
 2007-05-23  Ian Lance Taylor  <iant@google.com>
 
        * doc/invoke.texi (Invoking GCC): Document that the order of the
index 37ff3c522c2b99f68d327db1430f4f7a1b6cda04..07b5b78a6b598aed1cd3dbaa1604b6c851d967ce 100644 (file)
@@ -3490,8 +3490,7 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
       mips_load_call_address (addr, orig_addr, sibcall_p);
     }
 
-  if (TARGET_MIPS16
-      && mips16_hard_float
+  if (mips16_hard_float
       && build_mips16_call_stub (result, addr, args_size,
                                 aux == 0 ? 0 : (int) GET_MODE (aux)))
     return;
@@ -3878,6 +3877,24 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
 }
 
 
+/* INFO describes an argument that is passed in a single-register value.
+   Return the register it uses, assuming that FPRs are available if
+   HARD_FLOAT_P.  */
+
+static unsigned int
+mips_arg_regno (const struct mips_arg_info *info, bool hard_float_p)
+{
+  if (!info->fpr_p || !hard_float_p)
+    return GP_ARG_FIRST + info->reg_offset;
+  else if (mips_abi == ABI_32 && TARGET_DOUBLE_FLOAT && info->reg_offset > 0)
+    /* In o32, the second argument is always passed in $f14
+       for TARGET_DOUBLE_FLOAT, regardless of whether the
+       first argument was a word or doubleword.  */
+    return FP_ARG_FIRST + 2;
+  else
+    return FP_ARG_FIRST + info->reg_offset;
+}
+
 /* Implement FUNCTION_ARG_ADVANCE.  */
 
 void
@@ -3895,7 +3912,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
      for an explanation of what this code does.  It assumes the O32
      ABI, which passes at most 2 arguments in float registers.  */
   if (cum->arg_number < 2 && info.fpr_p)
-    cum->fp_code += (mode == SFmode ? 1 : 2) << ((cum->arg_number - 1) * 2);
+    cum->fp_code += (mode == SFmode ? 1 : 2) << (cum->arg_number * 2);
 
   if (mips_abi != ABI_EABI || !info.fpr_p)
     cum->num_gprs = info.reg_offset + info.reg_words;
@@ -4032,15 +4049,7 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
        }
     }
 
-  if (!info.fpr_p)
-    return gen_rtx_REG (mode, GP_ARG_FIRST + info.reg_offset);
-  else if (mips_abi == ABI_32 && TARGET_DOUBLE_FLOAT && info.reg_offset > 0)
-    /* In o32, the second argument is always passed in $f14
-       for TARGET_DOUBLE_FLOAT, regardless of whether the
-       first argument was a word or doubleword.  */
-    return gen_rtx_REG (mode, FP_ARG_FIRST + 2);
-  else
-    return gen_rtx_REG (mode, FP_ARG_FIRST + info.reg_offset);
+  return gen_rtx_REG (mode, mips_arg_regno (&info, TARGET_HARD_FLOAT));
 }
 
 
@@ -6303,6 +6312,51 @@ mips_global_pointer (void)
 }
 
 
+/* Return true if the function return value MODE will get returned in a
+   floating-point register.  */
+
+static bool
+mips_return_mode_in_fpr_p (enum machine_mode mode)
+{
+  return ((GET_MODE_CLASS (mode) == MODE_FLOAT
+          || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
+          || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+         && GET_MODE_UNIT_SIZE (mode) <= UNITS_PER_HWFPVALUE);
+}
+
+/* Return a two-character string representing a function floating-point
+   return mode, used to name MIPS16 function stubs.  */
+
+static const char *
+mips16_call_stub_mode_suffix (enum machine_mode mode)
+{
+  if (mode == SFmode)
+    return "sf";
+  else if (mode == DFmode)
+    return "df";
+  else if (mode == SCmode)
+    return "sc";
+  else if (mode == DCmode)
+    return "dc";
+  else if (mode == V2SFmode)
+    return "df";
+  else
+    gcc_unreachable ();
+}
+
+/* Return true if the current function returns its value in a floating-point
+   register in MIPS16 mode.  */
+
+static bool
+mips16_cfun_returns_in_fpr_p (void)
+{
+  tree return_type = DECL_RESULT (current_function_decl);
+  return (mips16_hard_float
+         && !aggregate_value_p (return_type, current_function_decl)
+         && mips_return_mode_in_fpr_p (DECL_MODE (return_type)));
+}
+
+
 /* Return true if the current function must save REGNO.  */
 
 static bool
@@ -6337,10 +6391,6 @@ mips_save_reg_p (unsigned int regno)
 
   if (TARGET_MIPS16)
     {
-      tree return_type;
-
-      return_type = DECL_RESULT (current_function_decl);
-
       /* $18 is a special case in mips16 code.  It may be used to call
         a function which returns a floating point value, but it is
         marked in call_used_regs.  */
@@ -6351,10 +6401,7 @@ mips_save_reg_p (unsigned int regno)
         value into the floating point registers if the return value is
         floating point.  */
       if (regno == GP_REG_FIRST + 31
-         && mips16_hard_float
-         && !aggregate_value_p (return_type, current_function_decl)
-         && GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
-         && GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE)
+         && mips16_cfun_returns_in_fpr_p ())
        return true;
     }
 
@@ -6739,7 +6786,7 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
      floating point arguments.  The linker will arrange for any 32-bit
      functions to call this stub, which will then jump to the 16-bit
      function proper.  */
-  if (TARGET_MIPS16 && !TARGET_SOFT_FLOAT
+  if (mips16_hard_float
       && current_function_args_info.fp_code != 0)
     build_mips16_function_stub (file);
 
@@ -7069,6 +7116,33 @@ mips_expand_epilogue (int sibcall_p)
       emit_jump_insn (gen_return ());
       return;
     }
+  
+  /* In mips16 mode, if the return value should go into a floating-point
+     register, we need to call a helper routine to copy it over.  */
+  if (mips16_cfun_returns_in_fpr_p ())
+    {
+      char *name;
+      rtx func;
+      rtx insn;
+      rtx retval;
+      rtx call;
+      tree id;
+      tree return_type;
+      enum machine_mode return_mode;
+
+      return_type = DECL_RESULT (current_function_decl);
+      return_mode = DECL_MODE (return_type);
+
+      name = ACONCAT (("__mips16_ret_",
+                      mips16_call_stub_mode_suffix (return_mode),
+                      NULL));
+      id = get_identifier (name);
+      func = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (id));
+      retval = gen_rtx_REG (return_mode, GP_RETURN);
+      call = gen_call_value_internal (retval, func, const0_rtx);
+      insn = emit_call_insn (call);
+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), retval);
+    }
 
   /* Split the frame into two.  STEP1 is the amount of stack we should
      deallocate before restoring the registers.  STEP2 is the amount we
@@ -7175,24 +7249,16 @@ mips_expand_epilogue (int sibcall_p)
 int
 mips_can_use_return_insn (void)
 {
-  tree return_type;
-
   if (! reload_completed)
     return 0;
 
   if (regs_ever_live[31] || current_function_profile)
     return 0;
 
-  return_type = DECL_RESULT (current_function_decl);
-
-  /* In mips16 mode, a function which returns a floating point value
+  /* In mips16 mode, a function that returns a floating point value
      needs to arrange to copy the return value into the floating point
      registers.  */
-  if (TARGET_MIPS16
-      && mips16_hard_float
-      && ! aggregate_value_p (return_type, current_function_decl)
-      && GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
-      && GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE)
+  if (mips16_cfun_returns_in_fpr_p ())
     return 0;
 
   if (cfun->machine->frame.initialized)
@@ -7617,23 +7683,25 @@ mips_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
        return gen_rtx_REG (mode, GP_RETURN);
     }
 
-  if ((GET_MODE_CLASS (mode) == MODE_FLOAT
-       || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
-      && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
-    return gen_rtx_REG (mode, FP_RETURN);
-
-  /* Handle long doubles for n32 & n64.  */
-  if (mode == TFmode)
-    return mips_return_fpr_pair (mode,
-                                DImode, 0,
-                                DImode, GET_MODE_SIZE (mode) / 2);
+  if (!TARGET_MIPS16)
+    {
+      /* Handle long doubles for n32 & n64.  */
+      if (mode == TFmode)
+       return mips_return_fpr_pair (mode,
+                                    DImode, 0,
+                                    DImode, GET_MODE_SIZE (mode) / 2);
 
-  if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-      && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)
-    return mips_return_fpr_pair (mode,
-                                GET_MODE_INNER (mode), 0,
-                                GET_MODE_INNER (mode),
-                                GET_MODE_SIZE (mode) / 2);
+      if (mips_return_mode_in_fpr_p (mode))
+       {
+         if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+           return mips_return_fpr_pair (mode,
+                                        GET_MODE_INNER (mode), 0,
+                                        GET_MODE_INNER (mode),
+                                        GET_MODE_SIZE (mode) / 2);
+         else
+           return gen_rtx_REG (mode, FP_RETURN);
+       }
+    }
 
   return gen_rtx_REG (mode, GP_RETURN);
 }
@@ -7978,6 +8046,7 @@ mips16_fp_args (FILE *file, int fp_code, int from_fp_p)
   const char *s;
   int gparg, fparg;
   unsigned int f;
+  CUMULATIVE_ARGS cum;
 
   /* This code only works for the original 32-bit ABI and the O64 ABI.  */
   gcc_assert (TARGET_OLDABI);
@@ -7986,43 +8055,50 @@ mips16_fp_args (FILE *file, int fp_code, int from_fp_p)
     s = "mfc1";
   else
     s = "mtc1";
-  gparg = GP_ARG_FIRST;
-  fparg = FP_ARG_FIRST;
+
+  init_cumulative_args (&cum, NULL, NULL);
+
   for (f = (unsigned int) fp_code; f != 0; f >>= 2)
     {
+      enum machine_mode mode;
+      struct mips_arg_info info;
+
       if ((f & 3) == 1)
-       {
-         if ((fparg & 1) != 0)
-           ++fparg;
-         fprintf (file, "\t%s\t%s,%s\n", s,
-                  reg_names[gparg], reg_names[fparg]);
-       }
+       mode = SFmode;
       else if ((f & 3) == 2)
-       {
-         if (TARGET_64BIT)
-           fprintf (file, "\td%s\t%s,%s\n", s,
-                    reg_names[gparg], reg_names[fparg]);
-         else
-           {
-             if ((fparg & 1) != 0)
-               ++fparg;
-             if (TARGET_BIG_ENDIAN)
-               fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
-                        reg_names[gparg], reg_names[fparg + 1], s,
-                        reg_names[gparg + 1], reg_names[fparg]);
-             else
-               fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
-                        reg_names[gparg], reg_names[fparg], s,
-                        reg_names[gparg + 1], reg_names[fparg + 1]);
-             ++gparg;
-             ++fparg;
-           }
-       }
+       mode = DFmode;
       else
        gcc_unreachable ();
 
-      ++gparg;
-      ++fparg;
+      mips_arg_info (&cum, mode, NULL, true, &info);
+      gparg = mips_arg_regno (&info, false);
+      fparg = mips_arg_regno (&info, true);
+
+      if (mode == SFmode)
+       fprintf (file, "\t%s\t%s,%s\n", s,
+                reg_names[gparg], reg_names[fparg]);
+      else if (TARGET_64BIT)
+       fprintf (file, "\td%s\t%s,%s\n", s,
+                reg_names[gparg], reg_names[fparg]);
+      else if (ISA_HAS_MXHC1)
+       /* -mips32r2 -mfp64 */
+       fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", 
+                s,
+                reg_names[gparg + (WORDS_BIG_ENDIAN ? 1 : 0)],
+                reg_names[fparg],
+                from_fp_p ? "mfhc1" : "mthc1",
+                reg_names[gparg + (WORDS_BIG_ENDIAN ? 0 : 1)],
+                reg_names[fparg]);
+      else if (TARGET_BIG_ENDIAN)
+       fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
+                reg_names[gparg], reg_names[fparg + 1], s,
+                reg_names[gparg + 1], reg_names[fparg]);
+      else
+       fprintf (file, "\t%s\t%s,%s\n\t%s\t%s,%s\n", s,
+                reg_names[gparg], reg_names[fparg], s,
+                reg_names[gparg + 1], reg_names[fparg + 1]);
+
+      function_arg_advance (&cum, mode, NULL, true);
     }
 }
 
@@ -8049,6 +8125,7 @@ build_mips16_function_stub (FILE *file)
   stubdecl = build_decl (FUNCTION_DECL, stubid,
                         build_function_type (void_type_node, NULL_TREE));
   DECL_SECTION_NAME (stubdecl) = build_string (strlen (secname), secname);
+  DECL_RESULT (stubdecl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
 
   fprintf (file, "\t# Stub function for %s (", current_function_name ());
   need_comma = 0;
@@ -8122,6 +8199,47 @@ struct mips16_stub
 
 static struct mips16_stub *mips16_stubs;
 
+/* Emit code to return a double value from a mips16 stub.  GPREG is the
+   first GP reg to use, FPREG is the first FP reg to use.  */
+
+static void
+mips16_fpret_double (int gpreg, int fpreg)
+{
+  if (TARGET_64BIT)
+    fprintf (asm_out_file, "\tdmfc1\t%s,%s\n",
+            reg_names[gpreg], reg_names[fpreg]);
+  else if (TARGET_FLOAT64)
+    {
+      fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+              reg_names[gpreg + WORDS_BIG_ENDIAN],
+              reg_names[fpreg]);
+      fprintf (asm_out_file, "\tmfhc1\t%s,%s\n",
+              reg_names[gpreg + !WORDS_BIG_ENDIAN],
+              reg_names[fpreg]);
+    }
+  else
+    {
+      if (TARGET_BIG_ENDIAN)
+       {
+         fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                  reg_names[gpreg + 0],
+                  reg_names[fpreg + 1]);
+         fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                  reg_names[gpreg + 1],
+                  reg_names[fpreg + 0]);
+       }
+      else
+       {
+         fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                  reg_names[gpreg + 0],
+                  reg_names[fpreg + 0]);
+         fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                  reg_names[gpreg + 1],
+                  reg_names[fpreg + 1]);
+       }
+    }
+}
+
 /* Build a call stub for a mips16 call.  A stub is needed if we are
    passing any floating point values which should go into the floating
    point registers.  If we are, and the call turns out to be to a
@@ -8143,7 +8261,7 @@ static struct mips16_stub *mips16_stubs;
 int
 build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
 {
-  int fpret;
+  int fpret = 0;
   const char *fnname;
   char *secname, *stubname;
   struct mips16_stub *l;
@@ -8153,14 +8271,13 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
 
   /* We don't need to do anything if we aren't in mips16 mode, or if
      we were invoked with the -msoft-float option.  */
-  if (! TARGET_MIPS16 || ! mips16_hard_float)
+  if (!mips16_hard_float)
     return 0;
 
   /* Figure out whether the value might come back in a floating point
      register.  */
-  fpret = (retval != 0
-          && GET_MODE_CLASS (GET_MODE (retval)) == MODE_FLOAT
-          && GET_MODE_SIZE (GET_MODE (retval)) <= UNITS_PER_FPVALUE);
+  if (retval)
+    fpret = mips_return_mode_in_fpr_p (GET_MODE (retval));
 
   /* We don't need to do anything if there were no floating point
      arguments and the value will not be returned in a floating point
@@ -8178,11 +8295,6 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
      require more sophisticated support.  */
   gcc_assert (TARGET_OLDABI);
 
-  /* We can only handle SFmode and DFmode floating point return
-     values.  */
-  if (fpret)
-    gcc_assert (GET_MODE (retval) == SFmode || GET_MODE (retval) == DFmode);
-
   /* If we're calling via a function pointer, then we must always call
      via a stub.  There are magic stubs provided in libgcc.a for each
      of the required cases.  Each of them expects the function address
@@ -8197,11 +8309,14 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
       /* ??? If this code is modified to support other ABI's, we need
          to handle PARALLEL return values here.  */
 
-      sprintf (buf, "__mips16_call_stub_%s%d",
-              (fpret
-               ? (GET_MODE (retval) == SFmode ? "sf_" : "df_")
-               : ""),
-              fp_code);
+      if (fpret)
+       sprintf (buf, "__mips16_call_stub_%s_%d",
+                mips16_call_stub_mode_suffix (GET_MODE (retval)),
+                fp_code);
+      else
+       sprintf (buf, "__mips16_call_stub_%d",
+                fp_code);
+
       id = get_identifier (buf);
       stub_fn = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (id));
 
@@ -8277,6 +8392,7 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
       stubdecl = build_decl (FUNCTION_DECL, stubid,
                             build_function_type (void_type_node, NULL_TREE));
       DECL_SECTION_NAME (stubdecl) = build_string (strlen (secname), secname);
+      DECL_RESULT (stubdecl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
 
       fprintf (asm_out_file, "\t# Stub function to call %s%s (",
               (fpret
@@ -8339,6 +8455,27 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
          if (GET_MODE (retval) == SFmode)
            fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
                     reg_names[GP_REG_FIRST + 2], reg_names[FP_REG_FIRST + 0]);
+         else if (GET_MODE (retval) == SCmode)
+           {
+             fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                      reg_names[GP_REG_FIRST + 2],
+                      reg_names[FP_REG_FIRST + 0]);
+             fprintf (asm_out_file, "\tmfc1\t%s,%s\n",
+                      reg_names[GP_REG_FIRST + 3],
+                      reg_names[FP_REG_FIRST + MAX_FPRS_PER_FMT]);
+           }
+         else if (GET_MODE (retval) == DFmode
+                  || GET_MODE (retval) == V2SFmode)
+           {
+             mips16_fpret_double (GP_REG_FIRST + 2, FP_REG_FIRST + 0);
+           }
+         else if (GET_MODE (retval) == DCmode)
+           {
+             mips16_fpret_double (GP_REG_FIRST + 2,
+                                  FP_REG_FIRST + 0);
+             mips16_fpret_double (GP_REG_FIRST + 4,
+                                  FP_REG_FIRST + MAX_FPRS_PER_FMT);
+           }
          else
            {
              if (TARGET_BIG_ENDIAN)
@@ -9190,7 +9327,7 @@ mips_init_libfuncs (void)
       set_optab_libfunc (smod_optab, SImode, "__vr4120_modsi3");
     }
 
-  if (TARGET_MIPS16 && mips16_hard_float)
+  if (mips16_hard_float)
     {
       set_optab_libfunc (add_optab, SFmode, "__mips16_addsf3");
       set_optab_libfunc (sub_optab, SFmode, "__mips16_subsf3");
index fff2e660400639b9ac403d11f8685f8e269c1ca9..0e90d030d3478d9c0538ab8d95b87cded38082fc 100644 (file)
@@ -288,6 +288,11 @@ extern const struct mips_rtx_cost_data *mips_cost;
 #define TARGET_OLDABI              (mips_abi == ABI_32 || mips_abi == ABI_O64)
 #define TARGET_NEWABI              (mips_abi == ABI_N32 || mips_abi == ABI_64)
 
+/* Similar to TARGET_HARD_FLOAT and TARGET_SOFT_FLOAT, but reflect the ABI
+   in use rather than whether the FPU is directly accessible.  */
+#define TARGET_HARD_FLOAT_ABI (TARGET_HARD_FLOAT || mips16_hard_float)
+#define TARGET_SOFT_FLOAT_ABI (!TARGET_HARD_FLOAT_ABI)
+
 /* IRIX specific stuff.  */
 #define TARGET_IRIX       0
 #define TARGET_IRIX6      0
@@ -406,9 +411,11 @@ extern const struct mips_rtx_cost_data *mips_cost;
          builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS64");        \
        }                                                       \
                                                                \
-      if (TARGET_HARD_FLOAT)                                   \
+      /* These defines reflect the ABI in use, not whether the  \
+        FPU is directly accessible.  */                        \
+      if (TARGET_HARD_FLOAT_ABI)                               \
        builtin_define ("__mips_hard_float");                   \
-      else if (TARGET_SOFT_FLOAT)                              \
+      else                                                     \
        builtin_define ("__mips_soft_float");                   \
                                                                \
       if (TARGET_SINGLE_FLOAT)                                 \
@@ -1033,12 +1040,12 @@ extern const struct mips_rtx_cost_data *mips_cost;
 /* The largest size of value that can be held in floating-point
    registers and moved with a single instruction.  */
 #define UNITS_PER_HWFPVALUE \
-  (TARGET_SOFT_FLOAT ? 0 : MAX_FPRS_PER_FMT * UNITS_PER_FPREG)
+  (TARGET_SOFT_FLOAT_ABI ? 0 : MAX_FPRS_PER_FMT * UNITS_PER_FPREG)
 
 /* The largest size of value that can be held in floating-point
    registers.  */
 #define UNITS_PER_FPVALUE                      \
-  (TARGET_SOFT_FLOAT ? 0                       \
+  (TARGET_SOFT_FLOAT_ABI ? 0                   \
    : TARGET_SINGLE_FLOAT ? UNITS_PER_FPREG     \
    : LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT)
 
index 5894a862f5cd20cb79cdb577fa4028bb4d66d107..17e7d0e92b55313c6456b0af3e1cf333843baf4a 100644 (file)
@@ -49,69 +49,204 @@ Boston, MA 02110-1301, USA.  */
 
 #define ENDFN(NAME) .end NAME
 
-/* Single precision math.  */
+/* ARG1
+       The FPR that holds the first floating-point argument.
 
-/* This macro defines a function which loads two single precision
-   values, performs an operation, and returns the single precision
-   result.  */
+   ARG2
+       The FPR that holds the second floating-point argument.
 
-#define SFOP(NAME, OPCODE)     \
+   RET
+       The FPR that holds a floating-point return value.  */
+
+#define RET $f0
+#define ARG1 $f12
+#ifdef __mips64
+#define ARG2 $f13
+#else
+#define ARG2 $f14
+#endif
+
+/* Set 64-bit register GPR so that its high 32 bits contain HIGH_FPR
+   and so that its low 32 bits contain LOW_FPR.  */
+#define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR)     \
+       .set    noat;                           \
+       mfc1    GPR, HIGH_FPR;                  \
+       mfc1    $1, LOW_FPR;                    \
+       dsll    GPR, GPR, 32;                   \
+       or      GPR, GPR, $1;                   \
+       .set    at
+
+/* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of
+   GPR to LOW_FPR.  */
+#define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR)     \
+       .set    noat;                           \
+       dsrl    $1, GPR, 32;                    \
+       mtc1    GPR, LOW_FPR;                   \
+       mtc1    $1, HIGH_FPR;                   \
+       .set    at
+
+/* Jump to T, and use "OPCODE, OP2" to implement a delayed move.  */
+#define DELAYt(T, OPCODE, OP2)                 \
+       .set    noreorder;                      \
+       jr      T;                              \
+       OPCODE, OP2;                            \
+       .set    reorder
+
+/* Use "OPCODE. OP2" and jump to T.  */
+#define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
+
+/* MOVE_SF_BYTE0(D)
+       Move the first single-precision floating-point argument between
+       GPRs and FPRs.
+
+   MOVE_SI_BYTE0(D)
+       Likewise the first single-precision integer argument.
+
+   MOVE_SF_BYTE4(D)
+       Move the second single-precision floating-point argument between
+       GPRs and FPRs, given that the first argument occupies 4 bytes.
+
+   MOVE_SF_BYTE8(D)
+       Move the second single-precision floating-point argument between
+       GPRs and FPRs, given that the first argument occupies 8 bytes.
+
+   MOVE_DF_BYTE0(D)
+       Move the first double-precision floating-point argument between
+       GPRs and FPRs.
+
+   MOVE_DF_BYTE8(D)
+       Likewise the second double-precision floating-point argument.
+
+   MOVE_SF_RET(D, T)
+       Likewise a single-precision floating-point return value,
+       then jump to T.
+
+   MOVE_SC_RET(D, T)
+       Likewise a complex single-precision floating-point return value.
+
+   MOVE_DF_RET(D, T)
+       Likewise a double-precision floating-point return value.
+
+   MOVE_DC_RET(D, T)
+       Likewise a complex double-precision floating-point return value.
+
+   MOVE_SI_RET(D, T)
+       Likewise a single-precision integer return value.
+
+   The D argument is "t" to move to FPRs and "f" to move from FPRs.
+   The return macros may assume that the target of the jump does not
+   use a floating-point register.  */
+
+#define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
+#define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
+
+#if defined(__mips64) && defined(__MIPSEB__)
+#define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T
+#elif defined(__mips64)
+/* The high 32 bits of $2 correspond to the second word in memory;
+   i.e. the imaginary part.  */
+#define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
+#elif __mips_fpr == 64
+#define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
+#else
+#define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
+#endif
+
+#if defined(__mips64)
+#define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
+#define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13
+#define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13
+#else
+#define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
+#define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14
+#define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14
+#endif
+#define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D)
+
+#if defined(__mips64)
+#define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12
+#define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
+#define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
+#define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
+#elif __mips_fpr == 64 && defined(__MIPSEB__)
+#define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
+#define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
+#define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
+#define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, T)
+#elif __mips_fpr == 64
+#define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
+#define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
+#define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
+#define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, T)
+#elif defined(__MIPSEB__)
+/* FPRs are little-endian.  */
+#define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
+#define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14
+#define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0)
+#define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T)
+#else
+#define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13
+#define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15
+#define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
+#define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T)
+#endif
+
+/* Single-precision math.  */
+
+/* Define a function NAME that loads two single-precision values,
+   performs FPU operation OPCODE on them, and returns the single-
+   precision result.  */
+
+#define OPSF3(NAME, OPCODE)    \
 STARTFN (NAME);                        \
-       .set    noreorder;      \
-       mtc1    $4,$f0;         \
-       mtc1    $5,$f2;         \
-       nop;                    \
-       OPCODE  $f0,$f0,$f2;    \
-       mfc1    $2,$f0;         \
-       j       $31;            \
-       nop;                    \
-       .set    reorder;        \
+       MOVE_SF_BYTE0 (t);      \
+       MOVE_SF_BYTE4 (t);      \
+       OPCODE  RET,ARG1,ARG2;  \
+       MOVE_SF_RET (f, $31);   \
        ENDFN (NAME)
 
 #ifdef L_m16addsf3
-SFOP(__mips16_addsf3, add.s)
+OPSF3 (__mips16_addsf3, add.s)
 #endif
 #ifdef L_m16subsf3
-SFOP(__mips16_subsf3, sub.s)
+OPSF3 (__mips16_subsf3, sub.s)
 #endif
 #ifdef L_m16mulsf3
-SFOP(__mips16_mulsf3, mul.s)
+OPSF3 (__mips16_mulsf3, mul.s)
 #endif
 #ifdef L_m16divsf3
-SFOP(__mips16_divsf3, div.s)
+OPSF3 (__mips16_divsf3, div.s)
 #endif
 
-#define SFOP2(NAME, OPCODE)    \
+/* Define a function NAME that loads a single-precision value,
+   performs FPU operation OPCODE on it, and returns the single-
+   precision result.  */
+
+#define OPSF2(NAME, OPCODE)    \
 STARTFN (NAME);                        \
-       .set    noreorder;      \
-       mtc1    $4,$f0;         \
-       nop;                    \
-       OPCODE  $f0,$f0;        \
-       mfc1    $2,$f0;         \
-       j       $31;            \
-       nop;                    \
-       .set    reorder;        \
+       MOVE_SF_BYTE0 (t);      \
+       OPCODE  RET,ARG1;       \
+       MOVE_SF_RET (f, $31);   \
        ENDFN (NAME)
 
 #ifdef L_m16negsf2
-SFOP2(__mips16_negsf2, neg.s)
+OPSF2 (__mips16_negsf2, neg.s)
 #endif
 #ifdef L_m16abssf2
-SFOP2(__mips16_abssf2, abs.s)
+OPSF2 (__mips16_abssf2, abs.s)
 #endif
 
-/* Single precision comparisons.  */
+/* Single-precision comparisons.  */
 
-/* This macro defines a function which loads two single precision
-   values, performs a floating point comparison, and returns the
-   specified values according to whether the comparison is true or
-   false.  */
+/* Define a function NAME that loads two single-precision values,
+   performs floating point comparison OPCODE, and returns TRUE or
+   FALSE depending on the result.  */
 
-#define SFCMP(NAME, OPCODE, TRUE, FALSE)       \
+#define CMPSF(NAME, OPCODE, TRUE, FALSE)       \
 STARTFN (NAME);                                        \
-       mtc1    $4,$f0;                         \
-       mtc1    $5,$f2;                         \
-       OPCODE  $f0,$f2;                        \
+       MOVE_SF_BYTE0 (t);                      \
+       MOVE_SF_BYTE4 (t);                      \
+       OPCODE  ARG1,ARG2;                      \
        li      $2,TRUE;                        \
        bc1t    1f;                             \
        li      $2,FALSE;                       \
@@ -119,13 +254,13 @@ STARTFN (NAME);                                   \
        j       $31;                            \
        ENDFN (NAME)
 
-/* This macro is like SFCMP, but it reverses the comparison.  */
+/* Like CMPSF, but reverse the comparison operands.  */
 
-#define SFREVCMP(NAME, OPCODE, TRUE, FALSE)    \
+#define REVCMPSF(NAME, OPCODE, TRUE, FALSE)    \
 STARTFN (NAME);                                        \
-       mtc1    $4,$f0;                         \
-       mtc1    $5,$f2;                         \
-       OPCODE  $f2,$f0;                        \
+       MOVE_SF_BYTE0 (t);                      \
+       MOVE_SF_BYTE4 (t);                      \
+       OPCODE  ARG2,ARG1;                      \
        li      $2,TRUE;                        \
        bc1t    1f;                             \
        li      $2,FALSE;                       \
@@ -134,189 +269,118 @@ STARTFN (NAME);                                 \
        ENDFN (NAME)
 
 #ifdef L_m16eqsf2
-SFCMP(__mips16_eqsf2, c.eq.s, 0, 1)
+CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
 #endif
 #ifdef L_m16nesf2
-SFCMP(__mips16_nesf2, c.eq.s, 0, 1)
+CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
 #endif
 #ifdef L_m16gtsf2
-SFREVCMP(__mips16_gtsf2, c.lt.s, 1, 0)
+REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
 #endif
 #ifdef L_m16gesf2
-SFREVCMP(__mips16_gesf2, c.le.s, 0, -1)
+REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
 #endif
 #ifdef L_m16lesf2
-SFCMP(__mips16_lesf2, c.le.s, 0, 1)
+CMPSF (__mips16_lesf2, c.le.s, 0, 1)
 #endif
 #ifdef L_m16ltsf2
-SFCMP(__mips16_ltsf2, c.lt.s, -1, 0)
+CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
 #endif
 
-/* Single precision conversions.  */
+/* Single-precision conversions.  */
 
 #ifdef L_m16fltsisf
 STARTFN (__mips16_floatsisf)
-       .set    noreorder
-       mtc1    $4,$f0
-       nop
-       cvt.s.w $f0,$f0
-       mfc1    $2,$f0
-       j       $31
-       nop
-       .set    reorder
+       MOVE_SF_BYTE0 (t)
+       cvt.s.w RET,ARG1
+       MOVE_SF_RET (f, $31)
        ENDFN (__mips16_floatsisf)
 #endif
 
 #ifdef L_m16fix_truncsfsi
 STARTFN (__mips16_fix_truncsfsi)
-       .set    noreorder
-       mtc1    $4,$f0
-       nop
-       trunc.w.s $f0,$f0,$4
-       mfc1    $2,$f0
-       j       $31
-       nop
-       .set    reorder
+       MOVE_SF_BYTE0 (t)
+       trunc.w.s RET,ARG1,$4
+       MOVE_SI_RET (f, $31)
        ENDFN (__mips16_fix_truncsfsi)
 #endif
 
 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
 
-/* The double precision operations.  We need to use different code
-   based on the preprocessor symbol __mips64, because the way in which
-   double precision values will change.  Without __mips64, the value
-   is passed in two 32-bit registers.  With __mips64, the value is
-   passed in a single 64-bit register.  */
+/* Double-precision math.  */
 
-/* Load the first double precision operand.  */
+/* Define a function NAME that loads two double-precision values,
+   performs FPU operation OPCODE on them, and returns the double-
+   precision result.  */
 
-#if defined(__mips64)
-#define LDDBL1 dmtc1 $4,$f12
-#elif defined(__mipsfp64)
-#define LDDBL1 sw $4,0($29); sw $5,4($29); l.d $f12,0($29)
-#elif defined(__MIPSEB__)
-#define LDDBL1 mtc1 $4,$f13; mtc1 $5,$f12
-#else
-#define LDDBL1 mtc1 $4,$f12; mtc1 $5,$f13
-#endif
-
-/* Load the second double precision operand.  */
-
-#if defined(__mips64)
-/* XXX this should be $6 for Algo arg passing model */
-#define LDDBL2 dmtc1 $5,$f14
-#elif defined(__mipsfp64)
-#define LDDBL2 sw $6,8($29); sw $7,12($29); l.d $f14,8($29)
-#elif defined(__MIPSEB__)
-#define LDDBL2 mtc1 $6,$f15; mtc1 $7,$f14
-#else
-#define LDDBL2 mtc1 $6,$f14; mtc1 $7,$f15
-#endif
-
-/* Move the double precision return value to the right place.  */
-
-#if defined(__mips64)
-#define RETDBL dmfc1 $2,$f0
-#elif defined(__mipsfp64)
-#define RETDBL s.d $f0,0($29); lw $2,0($29); lw $3,4($29)
-#elif defined(__MIPSEB__)
-#define RETDBL mfc1 $2,$f1; mfc1 $3,$f0
-#else
-#define RETDBL mfc1 $2,$f0; mfc1 $3,$f1
-#endif
-
-/* Double precision math.  */
-
-/* This macro defines a function which loads two double precision
-   values, performs an operation, and returns the double precision
-   result.  */
-
-#define DFOP(NAME, OPCODE)     \
+#define OPDF3(NAME, OPCODE)    \
 STARTFN (NAME);                        \
-       .set    noreorder;      \
-       LDDBL1;                 \
-       LDDBL2;                 \
-       nop;                    \
-       OPCODE  $f0,$f12,$f14;  \
-       RETDBL;                 \
-       j       $31;            \
-       nop;                    \
-       .set    reorder;        \
+       MOVE_DF_BYTE0 (t);      \
+       MOVE_DF_BYTE8 (t);      \
+       OPCODE RET,ARG1,ARG2;   \
+       MOVE_DF_RET (f, $31);   \
        ENDFN (NAME)
 
 #ifdef L_m16adddf3
-DFOP(__mips16_adddf3, add.d)
+OPDF3 (__mips16_adddf3, add.d)
 #endif
 #ifdef L_m16subdf3
-DFOP(__mips16_subdf3, sub.d)
+OPDF3 (__mips16_subdf3, sub.d)
 #endif
 #ifdef L_m16muldf3
-DFOP(__mips16_muldf3, mul.d)
+OPDF3 (__mips16_muldf3, mul.d)
 #endif
 #ifdef L_m16divdf3
-DFOP(__mips16_divdf3, div.d)
+OPDF3 (__mips16_divdf3, div.d)
 #endif
 
-#define DFOP2(NAME, OPCODE)    \
+/* Define a function NAME that loads a double-precision value,
+   performs FPU operation OPCODE on it, and returns the double-
+   precision result.  */
+
+#define OPDF2(NAME, OPCODE)    \
 STARTFN (NAME);                        \
-       .set    noreorder;      \
-       LDDBL1;                 \
-       nop;                    \
-       OPCODE  $f0,$f12;       \
-       RETDBL;                 \
-       j       $31;            \
-       nop;                    \
-       .set    reorder;        \
+       MOVE_DF_BYTE0 (t);      \
+       OPCODE RET,ARG1;        \
+       MOVE_DF_RET (f, $31);   \
        ENDFN (NAME)
 
 #ifdef L_m16negdf2
-DFOP2(__mips16_negdf2, neg.d)
+OPDF2 (__mips16_negdf2, neg.d)
 #endif
 #ifdef L_m16absdf2
-DFOP2(__mips16_absdf2, abs.d)
+OPDF2 (__mips16_absdf2, abs.d)
 #endif
 
-
 /* Conversions between single and double precision.  */
 
 #ifdef L_m16extsfdf2
 STARTFN (__mips16_extendsfdf2)
-       .set    noreorder
-       mtc1    $4,$f12
-       nop
-       cvt.d.s $f0,$f12
-       RETDBL
-       j       $31
-       nop
-       .set    reorder
+       MOVE_SF_BYTE0 (t)
+       cvt.d.s RET,ARG1
+       MOVE_DF_RET (f, $31)
        ENDFN (__mips16_extendsfdf2)
 #endif
 
 #ifdef L_m16trdfsf2
 STARTFN (__mips16_truncdfsf2)
-       .set    noreorder
-       LDDBL1
-       nop
-       cvt.s.d $f0,$f12
-       mfc1    $2,$f0
-       j       $31
-       nop
-       .set    reorder
+       MOVE_DF_BYTE0 (t)
+       cvt.s.d RET,ARG1
+       MOVE_SF_RET (f, $31)
        ENDFN (__mips16_truncdfsf2)
 #endif
 
-/* Double precision comparisons.  */
+/* Double-precision comparisons.  */
 
-/* This macro defines a function which loads two double precision
-   values, performs a floating point comparison, and returns the
-   specified values according to whether the comparison is true or
-   false.  */
+/* Define a function NAME that loads two double-precision values,
+   performs floating point comparison OPCODE, and returns TRUE or
+   FALSE depending on the result.  */
 
-#define DFCMP(NAME, OPCODE, TRUE, FALSE)       \
+#define CMPDF(NAME, OPCODE, TRUE, FALSE)       \
 STARTFN (NAME);                                        \
-       LDDBL1;                                 \
-       LDDBL2;                                 \
-       OPCODE  $f12,$f14;                      \
+       MOVE_DF_BYTE0 (t);                      \
+       MOVE_DF_BYTE8 (t);                      \
+       OPCODE  ARG1,ARG2;                      \
        li      $2,TRUE;                        \
        bc1t    1f;                             \
        li      $2,FALSE;                       \
@@ -324,13 +388,13 @@ STARTFN (NAME);                                   \
        j       $31;                            \
        ENDFN (NAME)
 
-/* This macro is like DFCMP, but it reverses the comparison.  */
+/* Like CMPDF, but reverse the comparison operands.  */
 
-#define DFREVCMP(NAME, OPCODE, TRUE, FALSE)    \
+#define REVCMPDF(NAME, OPCODE, TRUE, FALSE)    \
 STARTFN (NAME);                                        \
-       LDDBL1;                                 \
-       LDDBL2;                                 \
-       OPCODE  $f14,$f12;                      \
+       MOVE_DF_BYTE0 (t);                      \
+       MOVE_DF_BYTE8 (t);                      \
+       OPCODE  ARG2,ARG1;                      \
        li      $2,TRUE;                        \
        bc1t    1f;                             \
        li      $2,FALSE;                       \
@@ -339,174 +403,125 @@ STARTFN (NAME);                                 \
        ENDFN (NAME)
 
 #ifdef L_m16eqdf2
-DFCMP(__mips16_eqdf2, c.eq.d, 0, 1)
+CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
 #endif
 #ifdef L_m16nedf2
-DFCMP(__mips16_nedf2, c.eq.d, 0, 1)
+CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
 #endif
 #ifdef L_m16gtdf2
-DFREVCMP(__mips16_gtdf2, c.lt.d, 1, 0)
+REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
 #endif
 #ifdef L_m16gedf2
-DFREVCMP(__mips16_gedf2, c.le.d, 0, -1)
+REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
 #endif
 #ifdef L_m16ledf2
-DFCMP(__mips16_ledf2, c.le.d, 0, 1)
+CMPDF (__mips16_ledf2, c.le.d, 0, 1)
 #endif
 #ifdef L_m16ltdf2
-DFCMP(__mips16_ltdf2, c.lt.d, -1, 0)
+CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
 #endif
 
-/* Double precision conversions.  */
+/* Double-precision conversions.  */
 
 #ifdef L_m16fltsidf
 STARTFN (__mips16_floatsidf)
-       .set    noreorder
-       mtc1    $4,$f12
-       nop
-       cvt.d.w $f0,$f12
-       RETDBL
-       j       $31
-       nop
-       .set    reorder
+       MOVE_SI_BYTE0 (t)
+       cvt.d.w RET,ARG1
+       MOVE_DF_RET (f, $31)
        ENDFN (__mips16_floatsidf)
 #endif
 
 #ifdef L_m16fix_truncdfsi
 STARTFN (__mips16_fix_truncdfsi)
-       .set    noreorder
-       LDDBL1
-       nop
-       trunc.w.d $f0,$f12,$4
-       mfc1    $2,$f0
-       j       $31
-       nop
-       .set    reorder
+       MOVE_DF_BYTE0 (t)
+       trunc.w.d RET,ARG1,$4
+       MOVE_SI_RET (f, $31)
        ENDFN (__mips16_fix_truncdfsi)
 #endif
 #endif /* !__mips_single_float */
 
-/* These functions are used to return floating point values from
-   mips16 functions.  In this case we can put mtc1 in a jump delay slot,
-   because we know that the next instruction will not refer to a floating
-   point register.  */
+/* Define a function NAME that moves a return value of mode MODE from
+   FPRs to GPRs.  */
+
+#define RET_FUNCTION(NAME, MODE)       \
+STARTFN (NAME);                                \
+       MOVE_##MODE##_RET (t, $31);     \
+       ENDFN (NAME)
 
 #ifdef L_m16retsf
-STARTFN (__mips16_ret_sf)
-       .set    noreorder
-       j       $31
-       mtc1    $2,$f0
-       .set    reorder
-       ENDFN (__mips16_ret_sf)
+RET_FUNCTION (__mips16_ret_sf, SF)
+#endif
+
+#ifdef L_m16retsc
+RET_FUNCTION (__mips16_ret_sc, SC)
 #endif
 
 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
 #ifdef L_m16retdf
-STARTFN (__mips16_ret_df)
-       .set    noreorder
-#if defined(__mips64)
-       j       $31
-       dmtc1   $2,$f0
-#elif defined(__mipsfp64)
-       sw      $2,0($29)
-       sw      $3,4($29)
-       l.d     $f0,0($29)
-#elif defined(__MIPSEB__)
-       mtc1    $2,$f1
-       j       $31
-       mtc1    $3,$f0
-#else
-       mtc1    $2,$f0
-       j       $31
-       mtc1    $3,$f1
+RET_FUNCTION (__mips16_ret_df, DF)
 #endif
-       .set    reorder
-       ENDFN (__mips16_ret_df)
+
+#ifdef L_m16retdc
+RET_FUNCTION (__mips16_ret_dc, DC)
 #endif
 #endif /* !__mips_single_float */
 
+/* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
+   code X.  X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
+   classify the first and second arguments as follows:
+
+       1: a single-precision argument
+       2: a double-precision argument
+       0: no argument, or not one of the above.  */
+
+#define STUB_ARGS_0                                            /* () */
+#define STUB_ARGS_1 MOVE_SF_BYTE0 (t)                          /* (sf) */
+#define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t)       /* (sf, sf) */
+#define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t)       /* (sf, df) */
+#define STUB_ARGS_2 MOVE_DF_BYTE0 (t)                          /* (df) */
+#define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t)       /* (df, sf) */
+#define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t)      /* (df, df) */
+
 /* These functions are used by 16-bit code when calling via a function
-   pointer.  They must copy the floating point arguments from the gp
-   regs into the fp regs.  The function to call will be in $2.  The
-   exact set of floating point arguments to copy is encoded in the
-   function name; the final number is an fp_code, as described in
-   mips.h in the comment about CUMULATIVE_ARGS.  */
+   pointer.  They must copy the floating point arguments from the GPRs
+   to FPRs and then call function $2.  */
+
+#define CALL_STUB_NO_RET(NAME, CODE)   \
+STARTFN (NAME);                                \
+       STUB_ARGS_##CODE;               \
+       jr      $2;                     \
+       ENDFN (NAME)
 
 #ifdef L_m16stub1
-/* (float) */
-STARTFN (__mips16_call_stub_1)
-       .set    noreorder
-       mtc1    $4,$f12
-       j       $2
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_1)
+CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
 #endif
 
 #ifdef L_m16stub5
-/* (float, float) */
-STARTFN (__mips16_call_stub_5)
-       .set    noreorder
-       mtc1    $4,$f12
-       mtc1    $5,$f14
-       j       $2
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_5)
+CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
 #endif
 
 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
 
 #ifdef L_m16stub2
-/* (double) */
-STARTFN (__mips16_call_stub_2)
-       .set    noreorder
-       LDDBL1
-       j       $2
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_2)
+CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
 #endif
 
 #ifdef L_m16stub6
-/* (double, float) */
-STARTFN (__mips16_call_stub_6)
-       .set    noreorder
-       LDDBL1
-       mtc1    $6,$f14
-       j       $2
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_6)
+CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
 #endif
 
 #ifdef L_m16stub9
-/* (float, double) */
-STARTFN (__mips16_call_stub_9)
-       .set    noreorder
-       mtc1    $4,$f12
-       LDDBL2
-       j       $2
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_9)
+CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
 #endif
 
 #ifdef L_m16stub10
-/* (double, double) */
-STARTFN (__mips16_call_stub_10)
-       .set    noreorder
-       LDDBL1
-       LDDBL2
-       j       $2
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_10)
+CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
 #endif
 #endif /* !__mips_single_float */
 
 /* Now we have the same set of functions, except that this time the
-   function being called returns an SFmode value.  The calling
+   function being called returns an SFmode, SCmode, DFmode or DCmode
+   value; we need to instantiate a set for each case.  The calling
    function will arrange to preserve $18, so these functions are free
    to use it to hold the return address.
 
@@ -517,223 +532,143 @@ STARTFN (__mips16_call_stub_10)
    being called is 16 bits, in which case the copy is unnecessary;
    however, it's faster to always do the copy.  */
 
+#define CALL_STUB_RET(NAME, CODE, MODE)        \
+STARTFN (NAME);                                \
+       move    $18,$31;                \
+       STUB_ARGS_##CODE;               \
+       jalr    $2;                     \
+       MOVE_##MODE##_RET (f, $18);     \
+       ENDFN (NAME)
+
+/* First, instantiate the single-float set.  */
+
 #ifdef L_m16stubsf0
-/* () */
-STARTFN (__mips16_call_stub_sf_0)
-       .set    noreorder
-       move    $18,$31
-       jal     $2
-       nop
-       mfc1    $2,$f0
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_sf_0)
+CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
 #endif
 
 #ifdef L_m16stubsf1
-/* (float) */
-STARTFN (__mips16_call_stub_sf_1)
-       .set    noreorder
-       mtc1    $4,$f12
-       move    $18,$31
-       jal     $2
-       nop
-       mfc1    $2,$f0
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_sf_1)
+CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
 #endif
 
 #ifdef L_m16stubsf5
-/* (float, float) */
-STARTFN (__mips16_call_stub_sf_5)
-       .set    noreorder
-       mtc1    $4,$f12
-       mtc1    $5,$f14
-       move    $18,$31
-       jal     $2
-       nop
-       mfc1    $2,$f0
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_sf_5)
+CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
 #endif
 
 #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
 #ifdef L_m16stubsf2
-/* (double) */
-STARTFN (__mips16_call_stub_sf_2)
-       .set    noreorder
-       LDDBL1
-       move    $18,$31
-       jal     $2
-       nop
-       mfc1    $2,$f0
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_sf_2)
+CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
 #endif
 
 #ifdef L_m16stubsf6
-/* (double, float) */
-STARTFN (__mips16_call_stub_sf_6)
-       .set    noreorder
-       LDDBL1
-       mtc1    $6,$f14
-       move    $18,$31
-       jal     $2
-       nop
-       mfc1    $2,$f0
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_sf_6)
+CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
 #endif
 
 #ifdef L_m16stubsf9
-/* (float, double) */
-STARTFN (__mips16_call_stub_sf_9)
-       .set    noreorder
-       mtc1    $4,$f12
-       LDDBL2
-       move    $18,$31
-       jal     $2
-       nop
-       mfc1    $2,$f0
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_sf_9)
+CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
 #endif
 
 #ifdef L_m16stubsf10
-/* (double, double) */
-STARTFN (__mips16_call_stub_sf_10)
-       .set    noreorder
-       LDDBL1
-       LDDBL2
-       move    $18,$31
-       jal     $2
-       nop
-       mfc1    $2,$f0
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_sf_10)
+CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
 #endif
+#endif /* !__mips_single_float */
+
 
 /* Now we have the same set of functions again, except that this time
    the function being called returns an DFmode value.  */
 
+#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
 #ifdef L_m16stubdf0
-/* () */
-STARTFN (__mips16_call_stub_df_0)
-       .set    noreorder
-       move    $18,$31
-       jal     $2
-       nop
-       RETDBL
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_df_0)
+CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
 #endif
 
 #ifdef L_m16stubdf1
-/* (float) */
-STARTFN (__mips16_call_stub_df_1)
-       .set    noreorder
-       mtc1    $4,$f12
-       move    $18,$31
-       jal     $2
-       nop
-       RETDBL
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_df_1)
+CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
 #endif
 
-#ifdef L_m16stubdf2
-/* (double) */
-STARTFN (__mips16_call_stub_df_2)
-       .set    noreorder
-       LDDBL1
-       move    $18,$31
-       jal     $2
-       nop
-       RETDBL
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_df_2)
+#ifdef L_m16stubdf5
+CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
 #endif
 
-#ifdef L_m16stubdf5
-/* (float, float) */
-STARTFN (__mips16_call_stub_df_5)
-       .set    noreorder
-       mtc1    $4,$f12
-       mtc1    $5,$f14
-       move    $18,$31
-       jal     $2
-       nop
-       RETDBL
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_df_5)
+#ifdef L_m16stubdf2
+CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
 #endif
 
 #ifdef L_m16stubdf6
-/* (double, float) */
-STARTFN (__mips16_call_stub_df_6)
-       .set    noreorder
-       LDDBL1
-       mtc1    $6,$f14
-       move    $18,$31
-       jal     $2
-       nop
-       RETDBL
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_df_6)
+CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
 #endif
 
 #ifdef L_m16stubdf9
-/* (float, double) */
-STARTFN (__mips16_call_stub_df_9)
-       .set    noreorder
-       mtc1    $4,$f12
-       LDDBL2
-       move    $18,$31
-       jal     $2
-       nop
-       RETDBL
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_df_9)
+CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
 #endif
 
 #ifdef L_m16stubdf10
-/* (double, double) */
-STARTFN (__mips16_call_stub_df_10)
-       .set    noreorder
-       LDDBL1
-       LDDBL2
-       move    $18,$31
-       jal     $2
-       nop
-       RETDBL
-       j       $18
-       nop
-       .set    reorder
-       ENDFN (__mips16_call_stub_df_10)
+CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
+#endif
+#endif /* !__mips_single_float */
+
+
+/* Ho hum.  Here we have the same set of functions again, this time
+   for when the function being called returns an SCmode value.  */
+
+#ifdef L_m16stubsc0
+CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
+#endif
+
+#ifdef L_m16stubsc1
+CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
+#endif
+
+#ifdef L_m16stubsc5
+CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
+#endif
+
+#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
+#ifdef L_m16stubsc2
+CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
+#endif
+
+#ifdef L_m16stubsc6
+CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
+#endif
+
+#ifdef L_m16stubsc9
+CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
+#endif
+
+#ifdef L_m16stubsc10
+CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
+#endif
+#endif /* !__mips_single_float */
+
+
+/* Finally, another set of functions for DCmode.  */
+
+#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
+#ifdef L_m16stubdc0
+CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
+#endif
+
+#ifdef L_m16stubdc1
+CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
+#endif
+
+#ifdef L_m16stubdc5
+CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
+#endif
+
+#ifdef L_m16stubdc2
+CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
+#endif
+
+#ifdef L_m16stubdc6
+CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
+#endif
+
+#ifdef L_m16stubdc9
+CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
+#endif
+
+#ifdef L_m16stubdc10
+CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
 #endif
 #endif /* !__mips_single_float */
index f2da07d1bcdff935c6ec71d29f7fbef924960336..e66520b77d4bbaeff90424ef4b353e0769420f84 100644 (file)
@@ -19,11 +19,16 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m16mulsf3 _m16divsf3 \
        _m16eqdf2 _m16nedf2 _m16gtdf2 _m16gedf2 _m16ledf2 _m16ltdf2 \
        _m16fltsidf _m16fix_truncdfsi \
        _m16retsf _m16retdf \
+       _m16retsc _m16retdc \
        _m16stub1 _m16stub2 _m16stub5 _m16stub6 _m16stub9 _m16stub10 \
        _m16stubsf0 _m16stubsf1 _m16stubsf2 _m16stubsf5 _m16stubsf6 \
        _m16stubsf9 _m16stubsf10 \
        _m16stubdf0 _m16stubdf1 _m16stubdf2 _m16stubdf5 _m16stubdf6 \
-       _m16stubdf9 _m16stubdf10
+       _m16stubdf9 _m16stubdf10 \
+       _m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \
+       _m16stubsc9 _m16stubsc10 \
+       _m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \
+       _m16stubdc9 _m16stubdc10
 
 # We must build libgcc2.a with -G 0, in case the user wants to link
 # without the $gp register.
index 6604fbe09b25eaef4f4260a508ee3ceedd079465..be1fc867540f09a02036dde49015834110e0a15b 100644 (file)
@@ -19,11 +19,16 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m16mulsf3 _m16divsf3 \
        _m16eqdf2 _m16nedf2 _m16gtdf2 _m16gedf2 _m16ledf2 _m16ltdf2 \
        _m16fltsidf _m16fix_truncdfsi \
        _m16retsf _m16retdf \
+       _m16retsc _m16retdc \
        _m16stub1 _m16stub2 _m16stub5 _m16stub6 _m16stub9 _m16stub10 \
        _m16stubsf0 _m16stubsf1 _m16stubsf2 _m16stubsf5 _m16stubsf6 \
        _m16stubsf9 _m16stubsf10 \
        _m16stubdf0 _m16stubdf1 _m16stubdf2 _m16stubdf5 _m16stubdf6 \
-       _m16stubdf9 _m16stubdf10
+       _m16stubdf9 _m16stubdf10 \
+       _m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \
+       _m16stubsc9 _m16stubsc10 \
+       _m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \
+       _m16stubdc9 _m16stubdc10
 
 # We must build libgcc2.a with -G 0, in case the user wants to link
 # without the $gp register.
index 3bc8c47279d651a8c2eb0dfaf7437c31a1e80a9c..12455985074bd42784e2bec2a368637d454ad3da 100644 (file)
@@ -7,11 +7,16 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m16mulsf3 _m16divsf3 \
        _m16eqdf2 _m16nedf2 _m16gtdf2 _m16gedf2 _m16ledf2 _m16ltdf2 \
        _m16fltsidf _m16fix_truncdfsi \
        _m16retsf _m16retdf \
+       _m16retsc _m16retdc \
        _m16stub1 _m16stub2 _m16stub5 _m16stub6 _m16stub9 _m16stub10 \
        _m16stubsf0 _m16stubsf1 _m16stubsf2 _m16stubsf5 _m16stubsf6 \
        _m16stubsf9 _m16stubsf10 \
        _m16stubdf0 _m16stubdf1 _m16stubdf2 _m16stubdf5 _m16stubdf6 \
-       _m16stubdf9 _m16stubdf10
+       _m16stubdf9 _m16stubdf10 \
+       _m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \
+       _m16stubsc9 _m16stubsc10 \
+       _m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \
+       _m16stubdc9 _m16stubdc10
 
 # We must build libgcc2.a with -G 0, in case the user wants to link
 # without the $gp register.
index fc9ecb2251ab75f067c9dea97576b2f97f47decd..988a41ba5610e6f9d580ad050c83c67906b51f85 100644 (file)
@@ -1,3 +1,12 @@
+2007-05-23  Sandra Loosemore  <sandra@codesourcery.com>
+           Nigel Stephens  <nigel@mips.com>
+           Richard Sandiford  <richard@codesourcery.com>
+
+       * gcc.target/mips/inter/mips16_stubs_1_main.c: New.
+       * gcc.target/mips/inter/mips16_stubs_1_x.c: New.
+       * gcc.target/mips/inter/mips16_stubs_1_y.c: New.
+       * gcc.target/mips/inter/mips16-inter.exp: New.
+
 2007-05-23  Kazu Hirata  <kazu@codesourcery.com>
 
        * gcc.dg/bf-spl1.c, gcc.dg/m68k-pic-1.c: Enable on fido-*-*.
diff --git a/gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp b/gcc/testsuite/gcc.target/mips/inter/mips16-inter.exp
new file mode 100644 (file)
index 0000000..dc28dad
--- /dev/null
@@ -0,0 +1,48 @@
+# Run compatibility tests in which the "alt" compiler tries to force
+# MIPS16 mode.
+
+# We can only guarantee MIPS16 runtime support for certain targets.
+if { ![istarget mipsisa*-*-elf*] && ![istarget mips64vr*-*-elf*] } {
+    return
+}
+
+# Save the old value of CFLAGS_FOR_TARGET, if any.
+global saved_CFLAGS_FOR_TARGET
+if { [info exists CFLAGS_FOR_TARGET] } {
+    set saved_CFLAGS_FOR_TARGET $CFLAGS_FOR_TARGET
+} else {
+    unset -nocomplain saved_CFLAGS_FOR_TARGET
+}
+
+# The "alt" compiler is the normal compiler with an extra "-mips16" argument.
+proc compat-use-alt-compiler { } {
+    global saved_CFLAGS_FOR_TARGET CFLAGS_FOR_TARGET
+
+    if { [info exists saved_CFLAGS_FOR_TARGET] } {
+       set CFLAGS_FOR_TARGET [concat $saved_CFLAGS_FOR_TARGET "-mips16"]
+    } else {
+       set CFLAGS_FOR_TARGET "-mips16"
+    }
+}
+
+# Make the compiler under test the default.
+proc compat-use-tst-compiler { } {
+    global saved_CFLAGS_FOR_TARGET CFLAGS_FOR_TARGET
+
+    if { [info exists saved_CFLAGS_FOR_TARGET] } {
+       set CFLAGS_FOR_TARGET $saved_CFLAGS_FOR_TARGET
+    } else {
+       unset -nocomplain CFLAGS_FOR_TARGET
+    }
+}
+
+load_lib gcc.exp
+load_lib compat.exp
+
+gcc_init
+foreach src [lsort [find $srcdir/$subdir mips16_*_main.c]] {
+    if { [runtest_file_p $runtests $src] } {
+       compat-execute $src "mips16_inter" 1
+    }
+}
+compat-use-tst-compiler
diff --git a/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c b/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_main.c
new file mode 100644 (file)
index 0000000..df18c76
--- /dev/null
@@ -0,0 +1,10 @@
+extern void init (void);
+extern void test (void);
+
+int
+main (void)
+{
+  init ();
+  test ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c b/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_x.c
new file mode 100644 (file)
index 0000000..076b399
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c b/gcc/testsuite/gcc.target/mips/inter/mips16_stubs_1_y.c
new file mode 100644 (file)
index 0000000..b7a4d7f
--- /dev/null
@@ -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;
+}