]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
i386.c (ix86_expand_rint): Fix issues with signed zeros.
authorRichard Guenther <rguenther@suse.de>
Wed, 1 Nov 2006 11:38:06 +0000 (11:38 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Wed, 1 Nov 2006 11:38:06 +0000 (11:38 +0000)
2006-11-01  Richard Guenther  <rguenther@suse.de>

* config/i386/i386.c (ix86_expand_rint): Fix issues with
signed zeros.
(ix86_expand_floorceildf_32): Likewise.
(ix86_expand_floorceil): Likewise.
(ix86_expand_trunc): Likewise.

* testsuite/gcc.target/i386/fpprec-1.c: New testcase.

From-SVN: r118373

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/fpprec-1.c [new file with mode: 0644]

index e39026c77cb42d66fe2589c44cc435dd4bd8156e..322bb4b852baf186323946850e1d0fe8a98c13b6 100644 (file)
@@ -1,3 +1,11 @@
+2006-11-01  Richard Guenther  <rguenther@suse.de>
+
+       * config/i386/i386.c (ix86_expand_rint): Fix issues with
+       signed zeros.
+       (ix86_expand_floorceildf_32): Likewise.
+       (ix86_expand_floorceil): Likewise.
+       (ix86_expand_trunc): Likewise.
+
 2006-10-31  Andrew Pinski  <pinskia@gmail.com>
 
        * doc/invoke.texi (-fkeep-inline-functions): Change "GNU C"
index a7919dc8d2bc1b318ea5a631835fa400e4ec6be2..d2e19a0c293f6dec1759a2207461811d23f46593 100644 (file)
@@ -19423,10 +19423,11 @@ void
 ix86_expand_rint (rtx operand0, rtx operand1)
 {
   /* C code for the stuff we're doing below:
-        if (!isless (fabs (operand1), 2**52))
+       xa = fabs (operand1);
+        if (!isless (xa, 2**52))
          return operand1;
-        tmp = copysign (2**52, operand1);
-        return operand1 + tmp - tmp;
+        xa = xa + 2**52 - 2**52;
+        return copysign (xa, operand1);
    */
   enum machine_mode mode = GET_MODE (operand0);
   rtx res, xa, label, TWO52, mask;
@@ -19441,10 +19442,10 @@ ix86_expand_rint (rtx operand0, rtx operand1)
   TWO52 = ix86_gen_TWO52 (mode);
   label = ix86_expand_sse_compare_and_jump (UNLE, TWO52, xa, false);
 
-  ix86_sse_copysign_to_positive (TWO52, TWO52, res, mask);
+  expand_simple_binop (mode, PLUS, xa, TWO52, xa, 0, OPTAB_DIRECT);
+  expand_simple_binop (mode, MINUS, xa, TWO52, xa, 0, OPTAB_DIRECT);
 
-  expand_simple_binop (mode, PLUS, res, TWO52, res, 0, OPTAB_DIRECT);
-  expand_simple_binop (mode, MINUS, res, TWO52, res, 0, OPTAB_DIRECT);
+  ix86_sse_copysign_to_positive (res, xa, res, mask);
 
   emit_label (label);
   LABEL_NUSES (label) = 1;
@@ -19468,7 +19469,7 @@ ix86_expand_floorceildf_32 (rtx operand0, rtx operand1, bool do_floor)
           x2 -= 1;
      Compensate.  Ceil:
         if (x2 < x)
-          x2 += 1;
+          x2 -= -1;
         return x2;
    */
   enum machine_mode mode = GET_MODE (operand0);
@@ -19494,14 +19495,17 @@ ix86_expand_floorceildf_32 (rtx operand0, rtx operand1, bool do_floor)
   /* xa = copysign (xa, operand1) */
   ix86_sse_copysign_to_positive (xa, xa, res, mask);
 
-  /* generate 1.0 */
-  one = force_reg (mode, const_double_from_real_value (dconst1, mode));
+  /* generate 1.0 or -1.0 */
+  one = force_reg (mode,
+                  const_double_from_real_value (do_floor
+                                                ? dconst1 : dconstm1, mode));
 
   /* Compensate: xa = xa - (xa > operand1 ? 1 : 0) */
   tmp = ix86_expand_sse_compare_mask (UNGT, xa, res, !do_floor);
   emit_insn (gen_rtx_SET (VOIDmode, tmp,
                           gen_rtx_AND (mode, one, tmp)));
-  expand_simple_binop (mode, do_floor ? MINUS : PLUS,
+  /* We always need to subtract here to preserve signed zero.  */
+  expand_simple_binop (mode, MINUS,
                        xa, tmp, res, 0, OPTAB_DIRECT);
 
   emit_label (label);
@@ -19526,10 +19530,12 @@ ix86_expand_floorceil (rtx operand0, rtx operand1, bool do_floor)
      Compensate.  Ceil:
        if (x2 < x)
          x2 += 1;
+       if (HONOR_SIGNED_ZEROS (mode))
+         return copysign (x2, x);
        return x2;
    */
   enum machine_mode mode = GET_MODE (operand0);
-  rtx xa, xi, TWO52, tmp, label, one, res;
+  rtx xa, xi, TWO52, tmp, label, one, res, mask;
 
   TWO52 = ix86_gen_TWO52 (mode);
 
@@ -19539,7 +19545,7 @@ ix86_expand_floorceil (rtx operand0, rtx operand1, bool do_floor)
   emit_move_insn (res, operand1);
 
   /* xa = abs (operand1) */
-  xa = ix86_expand_sse_fabs (res, NULL);
+  xa = ix86_expand_sse_fabs (res, &mask);
 
   /* if (!isless (xa, TWO52)) goto label; */
   label = ix86_expand_sse_compare_and_jump (UNLE, TWO52, xa, false);
@@ -19559,6 +19565,9 @@ ix86_expand_floorceil (rtx operand0, rtx operand1, bool do_floor)
   expand_simple_binop (mode, do_floor ? MINUS : PLUS,
                        xa, tmp, res, 0, OPTAB_DIRECT);
 
+  if (HONOR_SIGNED_ZEROS (mode))
+    ix86_sse_copysign_to_positive (res, res, force_reg (mode, operand1), mask);
+
   emit_label (label);
   LABEL_NUSES (label) = 1;
 
@@ -19650,10 +19659,13 @@ ix86_expand_trunc (rtx operand0, rtx operand1)
         double xa = fabs (x), x2;
         if (!isless (xa, TWO52))
           return x;
-        return (double)(long)x;
+        x2 = (double)(long)x;
+       if (HONOR_SIGNED_ZEROS (mode))
+         return copysign (x2, x);
+       return x2;
    */
   enum machine_mode mode = GET_MODE (operand0);
-  rtx xa, xi, TWO52, label, res;
+  rtx xa, xi, TWO52, label, res, mask;
 
   TWO52 = ix86_gen_TWO52 (mode);
 
@@ -19663,7 +19675,7 @@ ix86_expand_trunc (rtx operand0, rtx operand1)
   emit_move_insn (res, operand1);
 
   /* xa = abs (operand1) */
-  xa = ix86_expand_sse_fabs (res, NULL);
+  xa = ix86_expand_sse_fabs (res, &mask);
 
   /* if (!isless (xa, TWO52)) goto label; */
   label = ix86_expand_sse_compare_and_jump (UNLE, TWO52, xa, false);
@@ -19673,6 +19685,9 @@ ix86_expand_trunc (rtx operand0, rtx operand1)
   expand_fix (xi, res, 0);
   expand_float (res, xi, 0);
 
+  if (HONOR_SIGNED_ZEROS (mode))
+    ix86_sse_copysign_to_positive (res, res, force_reg (mode, operand1), mask);
+
   emit_label (label);
   LABEL_NUSES (label) = 1;
 
index c63a1d972911ec69919279dc9fe6832e17621b7a..4ca24be242c14337eb696010090bbc79b8f0bdc7 100644 (file)
@@ -1,3 +1,7 @@
+2006-11-01  Richard Guenther  <rguenther@suse.de>
+
+       * testsuite/gcc.target/i386/fpprec-1.c: New testcase.
+
 2006-11-01  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * gcc.dg/torture/builtin-attr-1.c: Don't test gamma/lgamma.
diff --git a/gcc/testsuite/gcc.target/i386/fpprec-1.c b/gcc/testsuite/gcc.target/i386/fpprec-1.c
new file mode 100644 (file)
index 0000000..ff600b2
--- /dev/null
@@ -0,0 +1,90 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-math-errno -fno-trapping-math -msse2 -mfpmath=sse" } */
+
+#include "../../gcc.dg/i386-cpuid.h"
+
+extern void abort(void);
+extern int printf(const char *format, ...);
+
+double x[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(),
+       -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023,  /* +-DBL_MAX */
+       -0x1p-52, 0x1p-52,                                  /* +-DBL_EPSILON */
+       /* nextafter/before 0.5, 1.0 and 1.5 */
+       0x1.0000000000001p-1, 0x1.fffffffffffffp-2,
+       0x1.0000000000001p+0, 0x1.fffffffffffffp-1,
+       0x1.8000000000001p+0, 0x1.7ffffffffffffp+0,
+       -0.0, 0.0, -0.5, 0.5, -1.0, 1.0, -1.5, 1.5, -2.0, 2.0,
+       -2.5, 2.5 };
+#define NUM (sizeof(x)/sizeof(double))
+
+double expect_round[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(),
+       -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023,
+       -0.0, 0.0,
+       1.0, 0.0, 1.0, 1.0, 2.0, 1.0,
+       -0.0, 0.0, -1.0, 1.0, -1.0, 1.0, -2.0, 2.0, -2.0, 2.0,
+       -3.0, 3.0 };
+
+double expect_rint[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(),
+        -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023,
+        -0.0, 0.0,
+        1.0, 0.0, 1.0, 1.0, 2.0, 1.0,
+        -0.0, 0.0, -0.0, 0.0, -1.0, 1.0, -2.0, 2.0, -2.0, 2.0,
+        -2.0, 2.0 };
+
+double expect_floor[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(),
+        -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023,
+        -1.0, 0.0,
+        0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
+        -0.0, 0.0, -1.0, 0.0, -1.0, 1.0, -2.0, 1.0, -2.0, 2.0,
+        -3.0, 2.0 };
+
+double expect_ceil[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(),
+        -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023,
+        -0.0, 1.0,
+        1.0, 1.0, 2.0, 1.0, 2.0, 2.0,
+        -0.0, 0.0, -0.0, 1.0, -1.0, 1.0, -1.0, 2.0, -2.0, 2.0,
+        -2.0, 3.0 };
+
+double expect_trunc[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(),
+        -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023,
+        -0.0, 0.0,
+        0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
+        -0.0, 0.0, -0.0, 0.0, -1.0, 1.0, -1.0, 1.0, -2.0, 2.0,
+        -2.0, 2.0 };
+
+
+#define CHECK(fn) \
+void check_ ## fn (void) \
+{ \
+  int i; \
+  for (i = 0; i < NUM; ++i) \
+    { \
+      double res = __builtin_ ## fn (x[i]); \
+      if (__builtin_memcmp (&res, &expect_ ## fn [i], sizeof(double)) != 0) \
+        printf( # fn " [%i]: %.18e %.18e\n", i, expect_ ## fn [i], res), abort (); \
+    } \
+}
+
+CHECK(round)
+CHECK(rint)
+CHECK(floor)
+CHECK(ceil)
+CHECK(trunc)
+
+int main()
+{
+  unsigned long cpu_facilities;
+
+  cpu_facilities = i386_cpuid ();
+
+  if ((cpu_facilities & bit_SSE2) != bit_SSE2)
+    /* If host has no SSE2 support, pass.  */
+    return 0;
+
+  check_round ();
+  check_rint ();
+  check_floor ();
+  check_ceil ();
+  check_trunc ();
+  return 0;
+}