sparc.c (sparc_emit_float_lib_cmp): New function.
authorJakub Jelinek <jakub@redhat.com>
Wed, 8 Dec 1999 08:00:51 +0000 (09:00 +0100)
committerDavid S. Miller <davem@gcc.gnu.org>
Wed, 8 Dec 1999 08:00:51 +0000 (00:00 -0800)
* config/sparc/sparc.c (sparc_emit_float_lib_cmp): New function.
* config/sparc/sparc-protos.h (sparc_emit_float_lib_cmp): Prototype.
* config/sparc/sparc.h (*_LIBCALL): Only use for _Q_*
routines, _Qp_* cannot be handled like that now.
(INIT_TARGET_OPTABS): Likewise.
* config/sparc/sparc.md (cmptf): Accept soft float ARCH64.
(seq, sne, sgt, sge, slt, sle, beq, bne, bgt, bge, blt, ble): Call
sparc_emit_float_lib_cmp if ARCH64 and soft float.
(extendsftf2, extenddftf2, trunctfsf2, trunctfdf2, floatsitf2,
floatditf2, fix_trunctfsi2, fix_trunctfdi2, addtf3, subtf3, multf3,
divtf3, sqrttf3): New expanders.
(extendsftf2_hq, extenddftf2_hq, trunctfsf2_hq, trunctfdf2_hq,
floatsitf2_hq, floatditf2_hq, fix_trunctfsi2_hq, fix_trunctfdi2_hq,
addtf3_hq, subtf3_hq, multf3_hq, divtf3_hq, sqrttf3_hq): Rename from
non-_hq patterns.

From-SVN: r30824

gcc/ChangeLog
gcc/config/sparc/sparc-protos.h
gcc/config/sparc/sparc.c
gcc/config/sparc/sparc.h
gcc/config/sparc/sparc.md

index c9d7794188936fa35e5806ce370b756c85ce8e55..da3a78be4d63220f4859841aa8628618cf7508a5 100644 (file)
        (clear_sf): Use const_double_operand.
        (clear_sfp, clear_dfp, clear_tf, clear_tfp): New patterns.
 
+       * config/sparc/sparc.c (sparc_emit_float_lib_cmp): New function.
+       * config/sparc/sparc-protos.h (sparc_emit_float_lib_cmp): Prototype.
+       * config/sparc/sparc.h (*_LIBCALL): Only use for _Q_*
+       routines, _Qp_* cannot be handled like that now.
+       (INIT_TARGET_OPTABS): Likewise.
+       * config/sparc/sparc.md (cmptf): Accept soft float ARCH64.
+       (seq, sne, sgt, sge, slt, sle, beq, bne, bgt, bge, blt, ble): Call
+       sparc_emit_float_lib_cmp if ARCH64 and soft float.
+       (extendsftf2, extenddftf2, trunctfsf2, trunctfdf2, floatsitf2,
+       floatditf2, fix_trunctfsi2, fix_trunctfdi2, addtf3, subtf3, multf3,
+       divtf3, sqrttf3): New expanders.
+       (extendsftf2_hq, extenddftf2_hq, trunctfsf2_hq, trunctfdf2_hq,
+       floatsitf2_hq, floatditf2_hq, fix_trunctfsi2_hq, fix_trunctfdi2_hq,
+       addtf3_hq, subtf3_hq, multf3_hq, divtf3_hq, sqrttf3_hq): Rename from
+       non-_hq patterns.
+
 Tue Dec  7 19:22:06 1999  Richard Henderson  <rth@cygnus.com>
 
        * loop.h (struct induction): Add multi_insn_incr.
index 2e173393e9da2d3d820cbf87a0d623efab92f261..c7616696fb561ac9785d8af6ef27782fb595f3ac 100644 (file)
@@ -79,6 +79,7 @@ extern void sparc_flat_save_restore PARAMS ((FILE *, const char *,
 #ifdef RTX_CODE
 /* Define the function that build the compare insn for scc and bcc.  */
 extern rtx gen_compare_reg PARAMS ((enum rtx_code code, rtx, rtx));
+extern void sparc_emit_float_lib_cmp PARAMS ((rtx, rtx, enum rtx_code));
 /* This function handles all v9 scc insns */
 extern int gen_v9_scc PARAMS ((enum rtx_code, rtx *));
 extern void sparc_initialize_trampoline PARAMS ((rtx, rtx, rtx));
index b2161ab04079d8e17f4f606d431030382ed21237..b2219cc5a1c89938b32cc96217e881afe2920e8d 100644 (file)
@@ -4689,6 +4689,77 @@ output_cbranch (op, label, reversed, annul, noop, insn)
   return string;
 }
 
+/* Emit a library call comparison between floating point X and Y.
+   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
+   TARGET_ARCH64 uses _Qp_* functions, which use pointers to TFmode
+   values as arguments instead of the TFmode registers themselves,
+   that's why we cannot call emit_float_lib_cmp.  */
+void
+sparc_emit_float_lib_cmp (x, y, comparison)
+     rtx x, y;
+     enum rtx_code comparison;
+{
+  const char *qpfunc;
+  rtx slot0, slot1, result;
+
+  switch (comparison)
+    {
+    case EQ:
+      qpfunc = "_Qp_feq";
+      break;
+
+    case NE:
+      qpfunc = "_Qp_fne";
+      break;
+
+    case GT:
+      qpfunc = "_Qp_fgt";
+      break;
+
+    case GE:
+      qpfunc = "_Qp_fge";
+      break;
+
+    case LT:
+      qpfunc = "_Qp_flt";
+      break;
+
+    case LE:
+      qpfunc = "_Qp_fle";
+      break;
+
+    default:
+      abort();
+      break;
+    }
+
+  if (GET_CODE (x) != MEM)
+    {
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      emit_insn (gen_rtx_SET (VOIDmode, slot0, x));
+    }
+
+  if (GET_CODE (y) != MEM)
+    {
+      slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      emit_insn (gen_rtx_SET (VOIDmode, slot1, y));
+    }
+
+  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, qpfunc), 1,
+                     DImode, 2,
+                     XEXP (slot0, 0), Pmode,
+                     XEXP (slot1, 0), Pmode);
+
+  /* Immediately move the result of the libcall into a pseudo
+     register so reload doesn't clobber the value if it needs
+     the return register for a spill reg.  */
+  result = gen_reg_rtx (DImode);
+  emit_move_insn (result, hard_libcall_value (DImode));
+
+  emit_cmp_insn (result, const0_rtx, comparison,
+                 NULL_RTX, DImode, 0, 0);
+}
+          
 /* Return the string to output a conditional branch to LABEL, testing
    register REG.  LABEL is the operand number of the label; REG is the
    operand number of the reg.  OP is the conditional expression.  The mode
index cfb80ce17768d7aa9555557dc7d581d29ada6058..c051c7848e2524f22c173d9358c2f9fc72448ada 100644 (file)
@@ -2680,26 +2680,25 @@ do {                                                                    \
 #define MULSI3_LIBCALL "*.umul"
 
 /* Define library calls for quad FP operations.  These are all part of the
-   SPARC ABI.
-   ??? ARCH64 still does not work as the _Qp_* routines take pointers.  */
-#define ADDTF3_LIBCALL (TARGET_ARCH64 ? "_Qp_add" : "_Q_add")
-#define SUBTF3_LIBCALL (TARGET_ARCH64 ? "_Qp_sub" : "_Q_sub")
-#define NEGTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_neg" : "_Q_neg")
-#define MULTF3_LIBCALL (TARGET_ARCH64 ? "_Qp_mul" : "_Q_mul")
-#define DIVTF3_LIBCALL (TARGET_ARCH64 ? "_Qp_div" : "_Q_div")
-#define FLOATSITF2_LIBCALL (TARGET_ARCH64 ? "_Qp_itoq" : "_Q_itoq")
-#define FIX_TRUNCTFSI2_LIBCALL (TARGET_ARCH64 ? "_Qp_qtoi" : "_Q_qtoi")
-#define FIXUNS_TRUNCTFSI2_LIBCALL (TARGET_ARCH64 ? "_Qp_qtoui" : "_Q_qtou")
-#define EXTENDSFTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_stoq" : "_Q_stoq")
-#define TRUNCTFSF2_LIBCALL (TARGET_ARCH64 ? "_Qp_qtos" :  "_Q_qtos")
-#define EXTENDDFTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_dtoq" : "_Q_dtoq")
-#define TRUNCTFDF2_LIBCALL (TARGET_ARCH64 ? "_Qp_qtod" : "_Q_qtod")
-#define EQTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_feq" : "_Q_feq")
-#define NETF2_LIBCALL (TARGET_ARCH64 ? "_Qp_fne" : "_Q_fne")
-#define GTTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_fgt" : "_Q_fgt")
-#define GETF2_LIBCALL (TARGET_ARCH64 ? "_Qp_fge" : "_Q_fge")
-#define LTTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_flt" : "_Q_flt")
-#define LETF2_LIBCALL (TARGET_ARCH64 ? "_Qp_fle" : "_Q_fle")
+   SPARC 32bit ABI.  */
+#define ADDTF3_LIBCALL "_Q_add"
+#define SUBTF3_LIBCALL "_Q_sub"
+#define NEGTF2_LIBCALL "_Q_neg"
+#define MULTF3_LIBCALL "_Q_mul"
+#define DIVTF3_LIBCALL "_Q_div"
+#define FLOATSITF2_LIBCALL "_Q_itoq"
+#define FIX_TRUNCTFSI2_LIBCALL "_Q_qtoi"
+#define FIXUNS_TRUNCTFSI2_LIBCALL "_Q_qtou"
+#define EXTENDSFTF2_LIBCALL "_Q_stoq"
+#define TRUNCTFSF2_LIBCALL "_Q_qtos"
+#define EXTENDDFTF2_LIBCALL "_Q_dtoq"
+#define TRUNCTFDF2_LIBCALL "_Q_qtod"
+#define EQTF2_LIBCALL "_Q_feq"
+#define NETF2_LIBCALL "_Q_fne"
+#define GTTF2_LIBCALL "_Q_fgt"
+#define GETF2_LIBCALL "_Q_fge"
+#define LTTF2_LIBCALL "_Q_flt"
+#define LETF2_LIBCALL "_Q_fle"
 
 /* We can define the TFmode sqrt optab only if TARGET_FPU.  This is because
    with soft-float, the SFmode and DFmode sqrt instructions will be absent,
@@ -2707,33 +2706,36 @@ do {                                                                    \
    for calls to the builtin function sqrt, but this fails.  */
 #define INIT_TARGET_OPTABS                                             \
   do {                                                                 \
-    add_optab->handlers[(int) TFmode].libfunc                          \
-      = init_one_libfunc (ADDTF3_LIBCALL);                             \
-    sub_optab->handlers[(int) TFmode].libfunc                          \
-      = init_one_libfunc (SUBTF3_LIBCALL);                             \
-    neg_optab->handlers[(int) TFmode].libfunc                          \
-      = init_one_libfunc (NEGTF2_LIBCALL);                             \
-    smul_optab->handlers[(int) TFmode].libfunc                         \
-      = init_one_libfunc (MULTF3_LIBCALL);                             \
-    flodiv_optab->handlers[(int) TFmode].libfunc                       \
-      = init_one_libfunc (DIVTF3_LIBCALL);                             \
-    eqtf2_libfunc = init_one_libfunc (EQTF2_LIBCALL);                  \
-    netf2_libfunc = init_one_libfunc (NETF2_LIBCALL);                  \
-    gttf2_libfunc = init_one_libfunc (GTTF2_LIBCALL);                  \
-    getf2_libfunc = init_one_libfunc (GETF2_LIBCALL);                  \
-    lttf2_libfunc = init_one_libfunc (LTTF2_LIBCALL);                  \
-    letf2_libfunc = init_one_libfunc (LETF2_LIBCALL);                  \
-    trunctfsf2_libfunc = init_one_libfunc (TRUNCTFSF2_LIBCALL);                \
-    trunctfdf2_libfunc = init_one_libfunc (TRUNCTFDF2_LIBCALL);                \
-    extendsftf2_libfunc = init_one_libfunc (EXTENDSFTF2_LIBCALL);      \
-    extenddftf2_libfunc = init_one_libfunc (EXTENDDFTF2_LIBCALL);      \
-    floatsitf_libfunc = init_one_libfunc (FLOATSITF2_LIBCALL);         \
-    fixtfsi_libfunc = init_one_libfunc (FIX_TRUNCTFSI2_LIBCALL);       \
-    fixunstfsi_libfunc                                                 \
-      = init_one_libfunc (FIXUNS_TRUNCTFSI2_LIBCALL);                  \
-    if (TARGET_FPU)                                                    \
-      sqrt_optab->handlers[(int) TFmode].libfunc                       \
-       = init_one_libfunc ("_Q_sqrt");                                 \
+    if (TARGET_ARCH32)                                                 \
+      {                                                                        \
+       add_optab->handlers[(int) TFmode].libfunc                       \
+         = init_one_libfunc (ADDTF3_LIBCALL);                          \
+       sub_optab->handlers[(int) TFmode].libfunc                       \
+         = init_one_libfunc (SUBTF3_LIBCALL);                          \
+       neg_optab->handlers[(int) TFmode].libfunc                       \
+         = init_one_libfunc (NEGTF2_LIBCALL);                          \
+       smul_optab->handlers[(int) TFmode].libfunc                      \
+         = init_one_libfunc (MULTF3_LIBCALL);                          \
+       flodiv_optab->handlers[(int) TFmode].libfunc                    \
+         = init_one_libfunc (DIVTF3_LIBCALL);                          \
+       eqtf2_libfunc = init_one_libfunc (EQTF2_LIBCALL);               \
+       netf2_libfunc = init_one_libfunc (NETF2_LIBCALL);               \
+       gttf2_libfunc = init_one_libfunc (GTTF2_LIBCALL);               \
+       getf2_libfunc = init_one_libfunc (GETF2_LIBCALL);               \
+       lttf2_libfunc = init_one_libfunc (LTTF2_LIBCALL);               \
+       letf2_libfunc = init_one_libfunc (LETF2_LIBCALL);               \
+       trunctfsf2_libfunc = init_one_libfunc (TRUNCTFSF2_LIBCALL);     \
+       trunctfdf2_libfunc = init_one_libfunc (TRUNCTFDF2_LIBCALL);     \
+       extendsftf2_libfunc = init_one_libfunc (EXTENDSFTF2_LIBCALL);   \
+       extenddftf2_libfunc = init_one_libfunc (EXTENDDFTF2_LIBCALL);   \
+       floatsitf_libfunc = init_one_libfunc (FLOATSITF2_LIBCALL);      \
+       fixtfsi_libfunc = init_one_libfunc (FIX_TRUNCTFSI2_LIBCALL);    \
+       fixunstfsi_libfunc                                              \
+         = init_one_libfunc (FIXUNS_TRUNCTFSI2_LIBCALL);               \
+       if (TARGET_FPU)                                                 \
+         sqrt_optab->handlers[(int) TFmode].libfunc                    \
+           = init_one_libfunc ("_Q_sqrt");                             \
+      }                                                                        \
     INIT_SUBTARGET_OPTABS;                                             \
   } while (0)
 
index cf995462edf4b127bf3fc44f1e154fdb70ae467a..25951f07eccd86a8c2133861bfd2e74f082d0938 100644 (file)
   [(set (reg:CCFP 96)
        (compare:CCFP (match_operand:TF 0 "register_operand" "")
                      (match_operand:TF 1 "register_operand" "")))]
-  "TARGET_FPU && TARGET_HARD_QUAD"
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
   "
 {
   sparc_compare_op0 = operands[0];
       emit_insn (pat);
       DONE;
     }
+  else if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, EQ);
+      emit_jump_insn (gen_sne (operands[0]));
+      DONE;
+    }
   else if (TARGET_V9)
     {
       if (gen_v9_scc (EQ, operands))
       emit_insn (pat);
       DONE;
     }
+  else if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, NE);
+      emit_jump_insn (gen_sne (operands[0]));
+      DONE;
+    }
   else if (TARGET_V9)
     {
       if (gen_v9_scc (NE, operands))
   "! TARGET_LIVE_G0"
   "
 {
-  if (TARGET_V9)
+  if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GT);
+      emit_jump_insn (gen_sne (operands[0]));
+      DONE;
+    }
+  else if (TARGET_V9)
     {
       if (gen_v9_scc (GT, operands))
        DONE;
   "! TARGET_LIVE_G0"
   "
 {
-  if (TARGET_V9)
+  if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LT);
+      emit_jump_insn (gen_sne (operands[0]));
+      DONE;
+    }
+  else if (TARGET_V9)
     {
       if (gen_v9_scc (LT, operands))
        DONE;
   "! TARGET_LIVE_G0"
   "
 {
-  if (TARGET_V9)
+  if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GE);
+      emit_jump_insn (gen_sne (operands[0]));
+      DONE;
+    }
+  else if (TARGET_V9)
     {
       if (gen_v9_scc (GE, operands))
        DONE;
   "! TARGET_LIVE_G0"
   "
 {
-  if (TARGET_V9)
+  if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LE);
+      emit_jump_insn (gen_sne (operands[0]));
+      DONE;
+    }
+  else if (TARGET_V9)
     {
       if (gen_v9_scc (LE, operands))
        DONE;
       emit_v9_brxx_insn (EQ, sparc_compare_op0, operands[0]);
       DONE;
     }
+  else if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, EQ);
+      emit_jump_insn (gen_bne (operands[0]));
+      DONE;
+    }
   operands[1] = gen_compare_reg (EQ, sparc_compare_op0, sparc_compare_op1);
 }")
 
       emit_v9_brxx_insn (NE, sparc_compare_op0, operands[0]);
       DONE;
     }
+  else if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, NE);
+      emit_jump_insn (gen_bne (operands[0]));
+      DONE;
+    }
   operands[1] = gen_compare_reg (NE, sparc_compare_op0, sparc_compare_op1);
 }")
 
       emit_v9_brxx_insn (GT, sparc_compare_op0, operands[0]);
       DONE;
     }
+  else if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GT);
+      emit_jump_insn (gen_bne (operands[0]));
+      DONE;
+    }
   operands[1] = gen_compare_reg (GT, sparc_compare_op0, sparc_compare_op1);
 }")
 
       emit_v9_brxx_insn (LT, sparc_compare_op0, operands[0]);
       DONE;
     }
+  else if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LT);
+      emit_jump_insn (gen_bne (operands[0]));
+      DONE;
+    }
   operands[1] = gen_compare_reg (LT, sparc_compare_op0, sparc_compare_op1);
 }")
 
       emit_v9_brxx_insn (GE, sparc_compare_op0, operands[0]);
       DONE;
     }
+  else if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GE);
+      emit_jump_insn (gen_bne (operands[0]));
+      DONE;
+    }
   operands[1] = gen_compare_reg (GE, sparc_compare_op0, sparc_compare_op1);
 }")
 
       emit_v9_brxx_insn (LE, sparc_compare_op0, operands[0]);
       DONE;
     }
+  else if (GET_MODE (sparc_compare_op0) == TFmode && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+    {
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LE);
+      emit_jump_insn (gen_bne (operands[0]));
+      DONE;
+    }
   operands[1] = gen_compare_reg (LE, sparc_compare_op0, sparc_compare_op1);
 }")
 
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "extendsftf2"
+(define_expand "extendsftf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+       (float_extend:TF
+        (match_operand:SF 1 "register_operand" "f")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      if (GET_CODE (operands[0]) != MEM)
+       slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      else
+       slot0 = operands[0];
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_stoq\"), 0,
+                        VOIDmode, 2,
+                        XEXP (slot0, 0), Pmode,
+                        operands[1], SFmode);
+
+      if (GET_CODE (operands[0]) != MEM)
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*extendsftf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
        (float_extend:TF
         (match_operand:SF 1 "register_operand" "f")))]
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "extenddftf2"
+(define_expand "extenddftf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+       (float_extend:TF
+        (match_operand:DF 1 "register_operand" "e")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      if (GET_CODE (operands[0]) != MEM)
+       slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      else
+       slot0 = operands[0];
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_dtoq\"), 0,
+                        VOIDmode, 2,
+                        XEXP (slot0, 0), Pmode,
+                        operands[1], DFmode);
+
+      if (GET_CODE (operands[0]) != MEM)
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*extenddftf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
        (float_extend:TF
         (match_operand:DF 1 "register_operand" "e")))]
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "trunctfsf2"
+(define_expand "trunctfsf2"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+       (float_truncate:SF
+        (match_operand:TF 1 "register_operand" "e")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      if (GET_CODE (operands[1]) != MEM)
+       {
+         slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+       }
+      else
+       slot0 = operands[1];
+
+      emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtos\"),
+                              operands[0], 0, SFmode, 1,
+                              XEXP (slot0, 0), Pmode);
+      DONE;
+    }
+}")
+
+(define_insn "*trunctfsf2_hq"
   [(set (match_operand:SF 0 "register_operand" "=f")
        (float_truncate:SF
         (match_operand:TF 1 "register_operand" "e")))]
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "trunctfdf2"
+(define_expand "trunctfdf2"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+       (float_truncate:DF
+        (match_operand:TF 1 "register_operand" "e")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      if (GET_CODE (operands[1]) != MEM)
+       {
+         slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+       }
+      else
+       slot0 = operands[1];
+
+      emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtod\"),
+                              operands[0], 0, DFmode, 1,
+                              XEXP (slot0, 0), Pmode);
+      DONE;
+    }
+}")
+
+(define_insn "*trunctfdf2_hq"
   [(set (match_operand:DF 0 "register_operand" "=e")
        (float_truncate:DF
         (match_operand:TF 1 "register_operand" "e")))]
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "floatsitf2"
+(define_expand "floatsitf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+       (float:TF (match_operand:SI 1 "register_operand" "f")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      if (GET_CODE (operands[1]) != MEM)
+       slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      else
+       slot0 = operands[1];
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_itoq\"), 0,
+                        VOIDmode, 2,
+                        XEXP (slot0, 0), Pmode,
+                        operands[1], SImode);
+
+      if (GET_CODE (operands[0]) != MEM)
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*floatsitf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
        (float:TF (match_operand:SI 1 "register_operand" "f")))]
   "TARGET_FPU && TARGET_HARD_QUAD"
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
+(define_expand "floatunssitf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+       (unsigned_float:TF (match_operand:SI 1 "register_operand" "e")))]
+  "TARGET_FPU && TARGET_ARCH64 && ! TARGET_HARD_QUAD"
+  "
+{
+  rtx slot0;
+
+  if (GET_CODE (operands[1]) != MEM)
+    slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+  else
+    slot0 = operands[1];
+
+  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_uitoq\"), 0,
+                    VOIDmode, 2,
+                    XEXP (slot0, 0), Pmode,
+                    operands[1], SImode);
+
+  if (GET_CODE (operands[0]) != MEM)
+    emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+  DONE;
+}")
+
 ;; Now the same for 64 bit sources.
 
 (define_insn "floatdisf2"
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "floatditf2"
+(define_expand "floatditf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+       (float:TF (match_operand:DI 1 "register_operand" "e")))]
+  "TARGET_FPU && TARGET_V9 && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      if (GET_CODE (operands[1]) != MEM)
+       slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      else
+       slot0 = operands[1];
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_xtoq\"), 0,
+                        VOIDmode, 2,
+                        XEXP (slot0, 0), Pmode,
+                        operands[1], DImode);
+
+      if (GET_CODE (operands[0]) != MEM)
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*floatditf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
        (float:TF (match_operand:DI 1 "register_operand" "e")))]
   "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD"
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
+(define_expand "floatunsditf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+       (unsigned_float:TF (match_operand:DI 1 "register_operand" "e")))]
+  "TARGET_FPU && TARGET_ARCH64 && ! TARGET_HARD_QUAD"
+  "
+{
+  rtx slot0;
+
+  if (GET_CODE (operands[1]) != MEM)
+    slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+  else
+    slot0 = operands[1];
+
+  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_uxtoq\"), 0,
+                    VOIDmode, 2,
+                    XEXP (slot0, 0), Pmode,
+                    operands[1], DImode);
+
+  if (GET_CODE (operands[0]) != MEM)
+    emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+  DONE;
+}")
+
 ;; Convert a float to an actual integer.
 ;; Truncation is performed as part of the conversion.
 
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "fix_trunctfsi2"
+(define_expand "fix_trunctfsi2"
+  [(set (match_operand:SI 0 "register_operand" "=f")
+       (fix:SI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      if (GET_CODE (operands[1]) != MEM)
+       {
+         slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+       }
+      else
+       slot0 = operands[1];
+
+      emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtoi\"),
+                              operands[0], 0, SImode, 1,
+                              XEXP (slot0, 0), Pmode);
+      DONE;
+    }
+}")
+
+(define_insn "*fix_trunctfsi2_hq"
   [(set (match_operand:SI 0 "register_operand" "=f")
        (fix:SI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
   "TARGET_FPU && TARGET_HARD_QUAD"
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
+(define_expand "fixuns_trunctfsi2"
+  [(set (match_operand:SI 0 "register_operand" "=f")
+       (unsigned_fix:SI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
+  "TARGET_FPU && TARGET_ARCH64 && ! TARGET_HARD_QUAD"
+  "
+{
+  rtx slot0;
+
+  if (GET_CODE (operands[1]) != MEM)
+    {
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+    }
+  else
+    slot0 = operands[1];
+
+  emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtoui\"),
+                          operands[0], 0, SImode, 1,
+                          XEXP (slot0, 0), Pmode);
+  DONE;
+}")
+
 ;; Now the same, for V9 targets
 
 (define_insn "fix_truncsfdi2"
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "fix_trunctfdi2"
+(define_expand "fix_trunctfdi2"
+  [(set (match_operand:DI 0 "register_operand" "=e")
+       (fix:SI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
+  "TARGET_V9 && TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      if (GET_CODE (operands[1]) != MEM)
+       {
+         slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+       }
+      else
+       slot0 = operands[1];
+
+      emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtox\"),
+                              operands[0], 0, DImode, 1,
+                              XEXP (slot0, 0), Pmode);
+      DONE;
+    }
+}")
+
+(define_insn "*fix_trunctfdi2_hq"
   [(set (match_operand:DI 0 "register_operand" "=e")
        (fix:DI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
   "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD"
   "fqtox\\t%1, %0"
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
+
+(define_expand "fixuns_trunctfdi2"
+  [(set (match_operand:DI 0 "register_operand" "=f")
+       (unsigned_fix:DI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
+  "TARGET_FPU && TARGET_ARCH64 && ! TARGET_HARD_QUAD"
+  "
+{
+  rtx slot0;
+
+  if (GET_CODE (operands[1]) != MEM)
+    {
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+    }
+  else
+    slot0 = operands[1];
+
+  emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtoux\"),
+                          operands[0], 0, DImode, 1,
+                          XEXP (slot0, 0), Pmode);
+  DONE;
+}")
+
 \f
 ;;- arithmetic instructions
 
 \f
 ;; Floating point arithmetic instructions.
 
-(define_insn "addtf3"
+(define_expand "addtf3"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+       (plus:TF (match_operand:TF 1 "general_operand" "")
+                (match_operand:TF 2 "general_operand" "")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1, slot2;
+
+      if (GET_CODE (operands[0]) != MEM)
+       slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      else
+       slot0 = operands[0];
+      if (GET_CODE (operands[1]) != MEM)
+       {
+         slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+       }
+      else
+       slot1 = operands[1];
+      if (GET_CODE (operands[2]) != MEM)
+       {
+         slot2 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot2, operands[2]));
+       }
+      else
+       slot2 = operands[2];
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_add\"), 0,
+                        VOIDmode, 3,
+                        XEXP (slot0, 0), Pmode,
+                        XEXP (slot1, 0), Pmode,
+                        XEXP (slot2, 0), Pmode);
+
+      if (GET_CODE (operands[0]) != MEM)
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*addtf3_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
        (plus:TF (match_operand:TF 1 "register_operand" "e")
                 (match_operand:TF 2 "register_operand" "e")))]
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "subtf3"
+(define_expand "subtf3"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+       (minus:TF (match_operand:TF 1 "general_operand" "")
+                 (match_operand:TF 2 "general_operand" "")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1, slot2;
+
+      if (GET_CODE (operands[0]) != MEM)
+       slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      else
+       slot0 = operands[0];
+      if (GET_CODE (operands[1]) != MEM)
+       {
+         slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+       }
+      else
+       slot1 = operands[1];
+      if (GET_CODE (operands[2]) != MEM)
+       {
+         slot2 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot2, operands[2]));
+       }
+      else
+       slot2 = operands[2];
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_sub\"), 0,
+                        VOIDmode, 3,
+                        XEXP (slot0, 0), Pmode,
+                        XEXP (slot1, 0), Pmode,
+                        XEXP (slot2, 0), Pmode);
+
+      if (GET_CODE (operands[0]) != MEM)
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*subtf3_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
        (minus:TF (match_operand:TF 1 "register_operand" "e")
                  (match_operand:TF 2 "register_operand" "e")))]
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "multf3"
+(define_expand "multf3"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+       (mult:TF (match_operand:TF 1 "general_operand" "")
+                (match_operand:TF 2 "general_operand" "")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1, slot2;
+
+      if (GET_CODE (operands[0]) != MEM)
+       slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      else
+       slot0 = operands[0];
+      if (GET_CODE (operands[1]) != MEM)
+       {
+         slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+       }
+      else
+       slot1 = operands[1];
+      if (GET_CODE (operands[2]) != MEM)
+       {
+         slot2 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot2, operands[2]));
+       }
+      else
+       slot2 = operands[2];
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_mul\"), 0,
+                        VOIDmode, 3,
+                        XEXP (slot0, 0), Pmode,
+                        XEXP (slot1, 0), Pmode,
+                        XEXP (slot2, 0), Pmode);
+
+      if (GET_CODE (operands[0]) != MEM)
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*multf3_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
        (mult:TF (match_operand:TF 1 "register_operand" "e")
                 (match_operand:TF 2 "register_operand" "e")))]
   [(set_attr "type" "fpmul")
    (set_attr "length" "1")])
 
+(define_expand "divtf3"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+       (div:TF (match_operand:TF 1 "general_operand" "")
+               (match_operand:TF 2 "general_operand" "")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1, slot2;
+
+      if (GET_CODE (operands[0]) != MEM)
+       slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      else
+       slot0 = operands[0];
+      if (GET_CODE (operands[1]) != MEM)
+       {
+         slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+       }
+      else
+       slot1 = operands[1];
+      if (GET_CODE (operands[2]) != MEM)
+       {
+         slot2 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot2, operands[2]));
+       }
+      else
+       slot2 = operands[2];
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_div\"), 0,
+                        VOIDmode, 3,
+                        XEXP (slot0, 0), Pmode,
+                        XEXP (slot1, 0), Pmode,
+                        XEXP (slot2, 0), Pmode);
+
+      if (GET_CODE (operands[0]) != MEM)
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
 ;; don't have timing for quad-prec. divide.
-(define_insn "divtf3"
+(define_insn "*divtf3_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
        (div:TF (match_operand:TF 1 "register_operand" "e")
                (match_operand:TF 2 "register_operand" "e")))]
   [(set_attr "type" "fpmove")
    (set_attr "length" "1")])
 
-(define_insn "sqrttf2"
+(define_expand "sqrttf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+       (sqrt:TF (match_operand:TF 1 "register_operand" "e")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1;
+
+      if (GET_CODE (operands[0]) != MEM)
+       slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      else
+       slot0 = operands[0];
+      if (GET_CODE (operands[1]) != MEM)
+       {
+         slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+       }
+      else
+       slot1 = operands[1];
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_sqrt\"), 0,
+                        VOIDmode, 2,
+                        XEXP (slot0, 0), Pmode,
+                        XEXP (slot1, 0), Pmode);
+
+      if (GET_CODE (operands[0]) != MEM)
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*sqrttf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
        (sqrt:TF (match_operand:TF 1 "register_operand" "e")))]
   "TARGET_FPU && TARGET_HARD_QUAD"