aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAlan Modra <amodra@bigpond.net.au>2002-09-18 23:27:29 +0000
committerAlan Modra <amodra@gcc.gnu.org>2002-09-19 08:57:29 +0930
commit678b77333a389968633c420123f579414c0f1911 (patch)
treefb8b6f627c043a74d86eb9f7b254aaabcfe12012 /gcc
parentc402b6bfbdeb1e95750bff205e441e597f1c47a6 (diff)
downloadgcc-678b77333a389968633c420123f579414c0f1911.zip
gcc-678b77333a389968633c420123f579414c0f1911.tar.gz
gcc-678b77333a389968633c420123f579414c0f1911.tar.bz2
rs6000.md: (floatdisf2): Rename to floatdisf2_internal1.
* config/rs6000/rs6000.md: (floatdisf2): Rename to floatdisf2_internal1. (floatdisf2): New define_expand. (floatdisf2_internal2): Likewise. From-SVN: r57288
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/config/rs6000/rs6000.md52
2 files changed, 55 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fec1110..80846d7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 270d82e..8bfec08 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -5890,13 +5890,30 @@
"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)
@@ -5904,6 +5921,33 @@
(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);
+}")
;; Define the DImode operations that can be done in a small number
;; of instructions. The & constraints are to prevent the register