]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/39228 (387 optimised __builtin_isinf() gives incorrect result)
authorUros Bizjak <ubizjak@gmail.com>
Thu, 19 Feb 2009 12:44:40 +0000 (13:44 +0100)
committerUros Bizjak <uros@gcc.gnu.org>
Thu, 19 Feb 2009 12:44:40 +0000 (13:44 +0100)
PR target/39228
* config/i386/i386.md (isinfxf2): Split from isinf<mode>2.
(UNSPEC_FXAM_MEM): New unspec.
(fxam<mode>2_i387_with_temp): New insn and split pattern.
(isinf<mode>2): Use MODEF mode iterator.  Force operand[1] through
memory using fxam<mode>2_i387_with_temp to remove excess precision.

testsuite/ChangeLog:

PR target/39228
* gcc.c-torture/execute/pr39228.c: New test.

From-SVN: r144295

gcc/ChangeLog
gcc/config/i386/i386.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr39228.c [new file with mode: 0644]

index 58c89f0248f9da2ce9d4b60e8d522b3a3efe393f..eac440672e9ac49b81873a547eca23dd66cbff91 100644 (file)
@@ -1,3 +1,12 @@
+2009-02-19  Uros Bizjak  <ubizjak@gmail.com>
+
+       PR target/39228
+       * config/i386/i386.md (isinfxf2): Split from isinf<mode>2.
+       (UNSPEC_FXAM_MEM): New unspec.
+       (fxam<mode>2_i387_with_temp): New insn and split pattern.
+       (isinf<mode>2): Use MODEF mode iterator.  Force operand[1] through
+       memory using fxam<mode>2_i387_with_temp to remove excess precision.
+
 2009-02-17  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/soft-fp/double.h: Update from glibc CVS.
index 2487eb92392b131ec63b85a266dd73284e17615d..6e588ebb8694eafe0eeeb905b4273538825a44b9 100644 (file)
    (UNSPEC_FPREM1_U            91)
 
    (UNSPEC_C2_FLAG             95)
+   (UNSPEC_FXAM_MEM            96)
 
    ; SSP patterns
    (UNSPEC_SP_SET              100)
    (set_attr "unit" "i387")
    (set_attr "mode" "<MODE>")])
 
+(define_insn_and_split "fxam<mode>2_i387_with_temp"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (unspec:HI
+         [(match_operand:MODEF 1 "memory_operand" "")]
+         UNSPEC_FXAM_MEM))]
+  "TARGET_USE_FANCY_MATH_387
+   && !(reload_completed || reload_in_progress)"
+  "#"
+  "&& 1"
+  [(set (match_dup 2)(match_dup 1))
+   (set (match_dup 0)
+       (unspec:HI [(match_dup 2)] UNSPEC_FXAM))]
+{
+  operands[2] = gen_reg_rtx (<MODE>mode);
+
+  MEM_VOLATILE_P (operands[1]) = 1;
+}
+  [(set_attr "type" "multi")
+   (set_attr "unit" "i387")
+   (set_attr "mode" "<MODE>")])
+
+(define_expand "isinfxf2"
+  [(use (match_operand:SI 0 "register_operand" ""))
+   (use (match_operand:XF 1 "register_operand" ""))]
+  "TARGET_USE_FANCY_MATH_387
+   && TARGET_C99_FUNCTIONS"
+{
+  rtx mask = GEN_INT (0x45);
+  rtx val = GEN_INT (0x05);
+
+  rtx cond;
+
+  rtx scratch = gen_reg_rtx (HImode);
+  rtx res = gen_reg_rtx (QImode);
+
+  emit_insn (gen_fxamxf2_i387 (scratch, operands[1]));
+
+  emit_insn (gen_andqi_ext_0 (scratch, scratch, mask));
+  emit_insn (gen_cmpqi_ext_3 (scratch, val));
+  cond = gen_rtx_fmt_ee (EQ, QImode,
+                        gen_rtx_REG (CCmode, FLAGS_REG),
+                        const0_rtx);
+  emit_insn (gen_rtx_SET (VOIDmode, res, cond));
+  emit_insn (gen_zero_extendqisi2 (operands[0], res));
+  DONE;
+})
+
 (define_expand "isinf<mode>2"
   [(use (match_operand:SI 0 "register_operand" ""))
-   (use (match_operand:X87MODEF 1 "register_operand" ""))]
+   (use (match_operand:MODEF 1 "nonimmediate_operand" ""))]
   "TARGET_USE_FANCY_MATH_387
    && TARGET_C99_FUNCTIONS
    && !(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
   rtx scratch = gen_reg_rtx (HImode);
   rtx res = gen_reg_rtx (QImode);
 
-  emit_insn (gen_fxam<mode>2_i387 (scratch, operands[1]));
+  /* Remove excess precision by forcing value through memory. */
+  if (memory_operand (operands[1], VOIDmode))
+    emit_insn (gen_fxam<mode>2_i387_with_temp (scratch, operands[1]));
+  else
+    {
+      int slot = virtuals_instantiated ? SLOT_TEMP : SLOT_VIRTUAL;
+      rtx temp = assign_386_stack_local (<MODE>mode, slot);
+
+      emit_move_insn (temp, operands[1]);
+      emit_insn (gen_fxam<mode>2_i387_with_temp (scratch, temp));
+    }
+
   emit_insn (gen_andqi_ext_0 (scratch, scratch, mask));
   emit_insn (gen_cmpqi_ext_3 (scratch, val));
   cond = gen_rtx_fmt_ee (EQ, QImode,
index 2a9ceeba4605268e3eeebb526148142bdeaec6db..9d0809dd2a19e4cc15c64c5a15f157ab6f6486bf 100644 (file)
@@ -1,3 +1,8 @@
+2009-02-19  Uros Bizjak  <ubizjak@gmail.com>
+
+       PR target/39228
+       * gcc.c-torture/execute/pr39228.c: New test.
+
 2009-02-19  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran/38852
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr39228.c b/gcc/testsuite/gcc.c-torture/execute/pr39228.c
new file mode 100644 (file)
index 0000000..06d8efd
--- /dev/null
@@ -0,0 +1,36 @@
+extern void abort (void);
+
+static int __attribute__((always_inline)) testf (float b)
+{
+  float c = 1.01f * b;
+
+  return __builtin_isinff (c);
+}
+
+static int __attribute__((always_inline)) test (double b)
+{
+  double c = 1.01 * b;
+
+  return __builtin_isinf (c);
+}
+
+static int __attribute__((always_inline)) testl (long double b)
+{
+  long double c = 1.01L * b;
+
+  return __builtin_isinfl (c);
+}
+
+int main()
+{
+  if (testf (__FLT_MAX__) < 1)
+    abort ();
+
+  if (test (__DBL_MAX__) < 1)
+    abort ();
+
+  if (testl (__LDBL_MAX__) < 1)
+    abort ();
+
+  return 0;
+}