rs6000.md: (floatdisf2): Rename to floatdisf2_internal1.
authorAlan Modra <amodra@bigpond.net.au>
Wed, 18 Sep 2002 23:27:29 +0000 (23:27 +0000)
committerAlan Modra <amodra@gcc.gnu.org>
Wed, 18 Sep 2002 23:27:29 +0000 (08:57 +0930)
* config/rs6000/rs6000.md: (floatdisf2): Rename to
floatdisf2_internal1.
(floatdisf2): New define_expand.
(floatdisf2_internal2): Likewise.

From-SVN: r57288

gcc/ChangeLog
gcc/config/rs6000/rs6000.md

index fec111098991b4f2219145b2df44d4a62b811ca7..80846d701075247e2c2e8ee7bcb8d8c6dcc28210 100644 (file)
@@ -1,3 +1,10 @@
+2002-09-19  Alan Modra  <amodra@bigpond.net.au>
+
+       * config/rs6000/rs6000.md: (floatdisf2): Rename to
+       floatdisf2_internal1.
+       (floatdisf2): New define_expand.
+       (floatdisf2_internal2): Likewise.
+
 2002-09-18  Richard Henderson  <rth@redhat.com>
 
        * real.c (sticky_rshift_significand): Collect sticky as 
index 270d82eb26a2bc31f53c6fb0894568492e0c4838..8bfec08c4d5ff5df397539fa24b3e2c59c7649b0 100644 (file)
   "fctidz %0,%1"
   [(set_attr "type" "fp")])
 
-;; This only is safe if rounding mode set appropriately.
-(define_insn_and_split "floatdisf2"
+(define_expand "floatdisf2"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "")
+        (float:SF (match_operand:DI 1 "gpc_reg_operand" "")))]
+  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "
+{
+  if (!flag_unsafe_math_optimizations)
+    {
+      rtx label = gen_label_rtx ();
+      emit_insn (gen_floatdisf2_internal2 (operands[1], label));
+      emit_label (label);
+    }
+  emit_insn (gen_floatdisf2_internal1 (operands[0], operands[1]));
+  DONE;
+}")
+
+;; This is not IEEE compliant if rounding mode is "round to nearest".
+;; If the DI->DF conversion is inexact, then it's possible to suffer
+;; from double rounding.
+(define_insn_and_split "floatdisf2_internal1"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
         (float:SF (match_operand:DI 1 "gpc_reg_operand" "*f")))
    (clobber (match_scratch:DF 2 "=f"))]
-  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
-   && flag_unsafe_math_optimizations"
+  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
   "#"
   "&& reload_completed"
   [(set (match_dup 2)
    (set (match_dup 0)
         (float_truncate:SF (match_dup 2)))]
   "")
+
+;; Twiddles bits to avoid double rounding.
+;; Bits that might be trucated when converting to DFmode are replaced
+;; by a bit that won't be lost at that stage, but is below the SFmode
+;; rounding position.
+(define_expand "floatdisf2_internal2"
+  [(set (match_dup 2) (and:DI (match_operand:DI 0 "" "") (const_int 2047)))
+   (set (match_dup 4) (compare:CC (match_dup 2) (const_int 0)))
+   (set (match_dup 3) (ashiftrt:DI (match_dup 0) (const_int 53)))
+   (set (match_dup 3) (plus:DI (match_dup 3) (const_int 1)))
+   (set (pc) (if_then_else (eq (match_dup 4) (const_int 0))
+                          (label_ref (match_operand:DI 1 "" ""))
+                          (pc)))
+   (set (match_dup 5) (compare:CCUNS (match_dup 3) (const_int 2)))
+   (set (pc) (if_then_else (ltu (match_dup 5) (const_int 0))
+                          (label_ref (match_dup 1))
+                          (pc)))
+   (set (match_dup 0) (xor:DI (match_dup 0) (match_dup 2)))
+   (set (match_dup 0) (ior:DI (match_dup 0) (const_int 2048)))]
+  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "
+{
+  operands[2] = gen_reg_rtx (DImode);
+  operands[3] = gen_reg_rtx (DImode);
+  operands[4] = gen_reg_rtx (CCmode);
+  operands[5] = gen_reg_rtx (CCUNSmode);
+}")
 \f
 ;; Define the DImode operations that can be done in a small number
 ;; of instructions.  The & constraints are to prevent the register