]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR rtl-optimization/576 (gcc performs invalid optimization with float operations...
authorRoger Sayle <roger@eyesopen.com>
Fri, 21 Jan 2005 17:54:26 +0000 (17:54 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Fri, 21 Jan 2005 17:54:26 +0000 (17:54 +0000)
PR rtl-optimization/576
* real.c (real_arithmetic): Change return type from void to bool
to return an indication that the result may be inexact.
* real.h (real_arithmeric): Update prototype.
* fold-const.c (const_binop):  Don't constant fold floating
point expressions when the user specifies -frounding-math and
the result may depend upon the run-time rounding mode.
(fold_convert_const_real_from_real): Clean-up.
(fold_initializer): Ignore flag_rounding_math for initializers.
* simplify-rtx.c (simplify_binary_operation): Likewise, don't
constant fold FP operations with flag_rounding_math if the
result may depend upon the run-time rounding mode.

From-SVN: r94020

gcc/ChangeLog
gcc/fold-const.c
gcc/real.c
gcc/real.h
gcc/simplify-rtx.c

index 2525350e7f0e1efe002a4a7a4d118f9b88232a05..7c07cc430f8becbe0bd7f2be6bfe9558d1d935e9 100644 (file)
@@ -1,3 +1,18 @@
+2005-01-21  Roger Sayle  <roger@eyesopen.com>
+
+       PR rtl-optimization/576
+       * real.c (real_arithmetic): Change return type from void to bool
+       to return an indication that the result may be inexact.
+       * real.h (real_arithmeric): Update prototype.
+       * fold-const.c (const_binop):  Don't constant fold floating
+       point expressions when the user specifies -frounding-math and
+       the result may depend upon the run-time rounding mode.
+       (fold_convert_const_real_from_real): Clean-up.
+       (fold_initializer): Ignore flag_rounding_math for initializers.
+       * simplify-rtx.c (simplify_binary_operation): Likewise, don't
+       constant fold FP operations with flag_rounding_math if the
+       result may depend upon the run-time rounding mode.
+
 2005-01-21  Tom Tromey  <tromey@redhat.com>
 
        * c-cppbuiltin.c (define__GNUC__): Correct assertion.
index cdefe7611fb2f1408209b990dde8c6a3d4425b7c..cb822ed2ec536bf9ec9b65a2952d55de28c41164 100644 (file)
@@ -1482,6 +1482,8 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
       REAL_VALUE_TYPE d1;
       REAL_VALUE_TYPE d2;
       REAL_VALUE_TYPE value;
+      REAL_VALUE_TYPE result;
+      bool inexact;
       tree t, type;
 
       d1 = TREE_REAL_CST (arg1);
@@ -1510,9 +1512,18 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
       else if (REAL_VALUE_ISNAN (d2))
        return arg2;
 
-      REAL_ARITHMETIC (value, code, d1, d2);
+      inexact = real_arithmetic (&value, code, &d1, &d2);
+      real_convert (&result, mode, &value);
 
-      t = build_real (type, real_value_truncate (mode, value));
+      /* Don't constant fold this floating point operation if the
+        result may dependent upon the run-time rounding mode and
+        flag_rounding_math is set.  */
+      
+      if (flag_rounding_math
+         && (inexact || !real_identical (&result, &value)))
+       return NULL_TREE;
+
+      t = build_real (type, result);
 
       TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2);
       TREE_CONSTANT_OVERFLOW (t)
@@ -1808,20 +1819,11 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, tree arg1)
 static tree
 fold_convert_const_real_from_real (tree type, tree arg1)
 {
+  REAL_VALUE_TYPE value;
   tree t;
 
-  if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)))
-    {
-      /* We make a copy of ARG1 so that we don't modify an
-        existing constant tree.  */
-      t = copy_node (arg1);
-      TREE_TYPE (t) = type;
-      return t;
-    }
-
-  t = build_real (type,
-                 real_value_truncate (TYPE_MODE (type),
-                                      TREE_REAL_CST (arg1)));
+  real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1));
+  t = build_real (type, value);
 
   TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1);
   TREE_CONSTANT_OVERFLOW (t)
@@ -9506,17 +9508,20 @@ fold_initializer (tree expr)
 {
   int saved_signaling_nans = flag_signaling_nans;
   int saved_trapping_math = flag_trapping_math;
+  int saved_rounding_math = flag_rounding_math;
   int saved_trapv = flag_trapv;
   tree result;
 
   flag_signaling_nans = 0;
   flag_trapping_math = 0;
+  flag_rounding_math = 0;
   flag_trapv = 0;
 
   result = fold (expr);
 
   flag_signaling_nans = saved_signaling_nans;
   flag_trapping_math = saved_trapping_math;
+  flag_rounding_math = saved_rounding_math;
   flag_trapv = saved_trapv;
 
   return result;
index 5871d1e037c4c35b9925a8ccd54320d7230a51e0..a748b87b33a82fa2317aacaeb6587c2fd74f0ba9 100644 (file)
@@ -972,9 +972,10 @@ do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
 }
 
 /* Perform the binary or unary operation described by CODE.
-   For a unary operation, leave OP1 NULL.  */
+   For a unary operation, leave OP1 NULL.  This function returns
+   true if the result may be inexact due to loss of precision.  */
 
-void
+bool
 real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
                 const REAL_VALUE_TYPE *op1)
 {
@@ -983,20 +984,16 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
   switch (code)
     {
     case PLUS_EXPR:
-      do_add (r, op0, op1, 0);
-      break;
+      return do_add (r, op0, op1, 0);
 
     case MINUS_EXPR:
-      do_add (r, op0, op1, 1);
-      break;
+      return do_add (r, op0, op1, 1);
 
     case MULT_EXPR:
-      do_multiply (r, op0, op1);
-      break;
+      return do_multiply (r, op0, op1);
 
     case RDIV_EXPR:
-      do_divide (r, op0, op1);
-      break;
+      return do_divide (r, op0, op1);
 
     case MIN_EXPR:
       if (op1->cl == rvc_nan)
@@ -1033,6 +1030,7 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
     default:
       gcc_unreachable ();
     }
+  return false;
 }
 
 /* Legacy.  Similar, but return the result directly.  */
index c477be11b62e971fc35ed98778b1c8443dfe6b3b..b7cf3bb2f04205f70c39c0eb3958b5577da6fa20 100644 (file)
@@ -160,7 +160,7 @@ extern const struct real_format *
 /* Declare functions in real.c.  */
 
 /* Binary or unary arithmetic on tree_code.  */
-extern void real_arithmetic (REAL_VALUE_TYPE *, int, const REAL_VALUE_TYPE *,
+extern bool real_arithmetic (REAL_VALUE_TYPE *, int, const REAL_VALUE_TYPE *,
                             const REAL_VALUE_TYPE *);
 
 /* Compare reals by tree_code.  */
index 91df355b9ac7bb4959f789bbb5e2e5940cb48323..92567fe3c41b79d4bda8df41990916b5d746dc52 100644 (file)
@@ -1288,12 +1288,13 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
        }
       else
        {
-         REAL_VALUE_TYPE f0, f1, value;
+         REAL_VALUE_TYPE f0, f1, value, result;
+         bool inexact;
 
          REAL_VALUE_FROM_CONST_DOUBLE (f0, trueop0);
          REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1);
-         f0 = real_value_truncate (mode, f0);
-         f1 = real_value_truncate (mode, f1);
+         real_convert (&f0, mode, &f0);
+         real_convert (&f1, mode, &f1);
 
          if (HONOR_SNANS (mode)
              && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
@@ -1339,10 +1340,18 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
            /* Inf * 0 = NaN plus exception.  */
            return 0;
 
-         REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
+         inexact = real_arithmetic (&value, rtx_to_tree_code (code),
+                                    &f0, &f1);
+         real_convert (&result, mode, &value);
 
-         value = real_value_truncate (mode, value);
-         return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
+         /* Don't constant fold this floating point operation if the
+            result may dependent upon the run-time rounding mode and
+            flag_rounding_math is set.  */
+         if (flag_rounding_math
+             && (inexact || !real_identical (&result, &value)))
+           return NULL_RTX;
+
+         return CONST_DOUBLE_FROM_REAL_VALUE (result, mode);
        }
     }