]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR middle-end/50865 (Invalid code generation for INT64_MIN % 1 on x86_64)
authorJakub Jelinek <jakub@redhat.com>
Sat, 9 Jan 2016 07:37:04 +0000 (08:37 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Sat, 9 Jan 2016 07:37:04 +0000 (08:37 +0100)
PR middle-end/50865
PR tree-optimization/69097
* fold-const.h (expr_not_equal_to): New prototype.
* fold-const.c: Include stringpool.h and tree-ssanames.h.
(expr_not_equal_to): New function.
* match.pd (X % -Y is the same as X % Y): Don't optimize
unless X is known not to be equal to minimum or Y is known
not to be equal to -1.
* tree-vrp.c (simplify_div_or_mod_using_ranges): Add GSI argument.
fold TRUNC_MOD_EXPR if the second argument is not a power of two.
(simplify_stmt_using_ranges): Adjust caller.
(vrp_finalize): Call set_value_range on SSA_NAMEs before calling
substitute_and_fold.

* gcc.c-torture/execute/pr50865.c: New test.
* gcc.c-torture/execute/pr69097-1.c: New test.
* gcc.c-torture/execute/pr69097-2.c: New test.
* gcc.dg/pr69097-1.c: New test.
* gcc.dg/pr69097-2.c: New test.

From-SVN: r232188

gcc/ChangeLog
gcc/fold-const.c
gcc/fold-const.h
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr50865.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/pr69097-1.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/pr69097-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr69097-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr69097-2.c [new file with mode: 0644]
gcc/tree-vrp.c

index 151cb89c7cbbd9ba4e6cdca8eaea3fb7c8d31f5b..015673c02e433e7bd4121bc2ebc0fb10402a9c22 100644 (file)
@@ -1,3 +1,19 @@
+2016-01-09  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/50865
+       PR tree-optimization/69097
+       * fold-const.h (expr_not_equal_to): New prototype.
+       * fold-const.c: Include stringpool.h and tree-ssanames.h.
+       (expr_not_equal_to): New function.
+       * match.pd (X % -Y is the same as X % Y): Don't optimize
+       unless X is known not to be equal to minimum or Y is known
+       not to be equal to -1.
+       * tree-vrp.c (simplify_div_or_mod_using_ranges): Add GSI argument.
+       fold TRUNC_MOD_EXPR if the second argument is not a power of two.
+       (simplify_stmt_using_ranges): Adjust caller.
+       (vrp_finalize): Call set_value_range on SSA_NAMEs before calling
+       substitute_and_fold.
+
 2016-01-09  Jan Hubicka  <hubicka@ucw.cz>
 
        * ipa-icf.c (sem_item_optimizer::merge_classes): Do not ICE on VAR_DECL
index 23d1be3ee4a1c70f67322b7fae6afdffde92b146..abd53606aa13b550908061e2c41665f99129e759 100644 (file)
@@ -74,6 +74,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-into-ssa.h"
 #include "md5.h"
 #include "case-cfn-macros.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -9101,6 +9103,45 @@ tree_expr_nonzero_p (tree t)
   return ret;
 }
 
+/* Return true if T is known not to be equal to an integer W.  */
+
+bool
+expr_not_equal_to (tree t, const wide_int &w)
+{
+  wide_int min, max, nz;
+  value_range_type rtype;
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_CST:
+      return wi::ne_p (t, w);
+
+    case SSA_NAME:
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+       return false;
+      rtype = get_range_info (t, &min, &max);
+      if (rtype == VR_RANGE)
+       {
+         if (wi::lt_p (max, w, TYPE_SIGN (TREE_TYPE (t))))
+           return true;
+         if (wi::lt_p (w, min, TYPE_SIGN (TREE_TYPE (t))))
+           return true;
+       }
+      else if (rtype == VR_ANTI_RANGE
+              && wi::le_p (min, w, TYPE_SIGN (TREE_TYPE (t)))
+              && wi::le_p (w, max, TYPE_SIGN (TREE_TYPE (t))))
+       return true;
+      /* If T has some known zero bits and W has any of those bits set,
+        then T is known not to be equal to W.  */
+      if (wi::ne_p (wi::zext (wi::bit_and_not (w, get_nonzero_bits (t)),
+                             TYPE_PRECISION (TREE_TYPE (t))), 0))
+       return true;
+      return false;
+
+    default:
+      return false;
+    }
+}
+
 /* Fold a binary expression of code CODE and type TYPE with operands
    OP0 and OP1.  LOC is the location of the resulting expression.
    Return the folded expression if folding is successful.  Otherwise,
index 885320c08e56632a17e8c67d175a7d90cb8ab6a3..02f42709c4e0eec08f06311a7f6ebd023775af53 100644 (file)
@@ -177,6 +177,7 @@ extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int,
                          tree, tree);
 extern tree sign_bit_p (tree, const_tree);
 extern tree exact_inverse (tree, tree);
+extern bool expr_not_equal_to (tree t, const wide_int &);
 extern tree const_unop (enum tree_code, tree, tree);
 extern tree const_binop (enum tree_code, tree, tree, tree);
 extern bool negate_mathfn_p (combined_fn);
index 3913073192c7f579b9b82cdaacdcbd41871deff2..64e718cc5c90519b87eaef554440ab307b261a10 100644 (file)
@@ -295,7 +295,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (trunc_mod @0 (convert? (negate @1)))
  (if (!TYPE_UNSIGNED (type)
       && !TYPE_OVERFLOW_TRAPS (type)
-      && tree_nop_conversion_p (type, TREE_TYPE (@1)))
+      && tree_nop_conversion_p (type, TREE_TYPE (@1))
+      /* Avoid this transformation if X might be INT_MIN or
+        Y might be -1, because we would then change valid
+        INT_MIN % -(-1) into invalid INT_MIN % -1.  */
+      && (expr_not_equal_to (@0, TYPE_MIN_VALUE (type))
+         || expr_not_equal_to (@1, wi::minus_one (TYPE_PRECISION
+                                                       (TREE_TYPE (@1))))))
   (trunc_mod @0 (convert @1))))
 
 /* X - (X / Y) * Y is the same as X % Y.  */
index cbcf1bd1b550295f3415b935ce54cde891408aec..107ea24f396eb7bd14c91bdfc24827414590faaf 100644 (file)
@@ -1,3 +1,13 @@
+2016-01-09  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/50865
+       PR tree-optimization/69097
+       * gcc.c-torture/execute/pr50865.c: New test.
+       * gcc.c-torture/execute/pr69097-1.c: New test.
+       * gcc.c-torture/execute/pr69097-2.c: New test.
+       * gcc.dg/pr69097-1.c: New test.
+       * gcc.dg/pr69097-2.c: New test.
+
 2016-01-09  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/69164
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr50865.c b/gcc/testsuite/gcc.c-torture/execute/pr50865.c
new file mode 100644 (file)
index 0000000..1f05802
--- /dev/null
@@ -0,0 +1,27 @@
+/* PR middle-end/50865 */
+
+#define INT64_MIN (-__LONG_LONG_MAX__ - 1)
+
+int
+main ()
+{
+  volatile long long l1 = 1;
+  volatile long long l2 = -1;
+  volatile long long l3 = -1;
+
+  if ((INT64_MIN % 1LL) != 0)
+    __builtin_abort ();
+  if ((INT64_MIN % l1) != 0)
+    __builtin_abort ();
+  if (l2 == -1)
+    {
+      if ((INT64_MIN % 1LL) != 0)
+       __builtin_abort ();
+    }
+  else if ((INT64_MIN % -l2) != 0)
+    __builtin_abort ();
+  if ((INT64_MIN % -l3) != 0)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr69097-1.c b/gcc/testsuite/gcc.c-torture/execute/pr69097-1.c
new file mode 100644 (file)
index 0000000..b2b107e
--- /dev/null
@@ -0,0 +1,14 @@
+/* PR tree-optimization/69097 */
+
+int a, b;
+unsigned int c;
+
+int
+main ()
+{
+  int d = b;
+  b = ~(~a + (~d | b));
+  a = ~(~c >> b);
+  c = a % b;
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr69097-2.c b/gcc/testsuite/gcc.c-torture/execute/pr69097-2.c
new file mode 100644 (file)
index 0000000..8fe991b
--- /dev/null
@@ -0,0 +1,30 @@
+/* PR tree-optimization/69097 */
+
+__attribute__((noinline, noclone)) int
+f1 (int x, int y)
+{
+  return x % y;
+}
+
+__attribute__((noinline, noclone)) int
+f2 (int x, int y)
+{
+  return x % -y;
+}
+
+__attribute__((noinline, noclone)) int
+f3 (int x, int y)
+{
+  int z = -y;
+  return x % z;
+}
+
+int
+main ()
+{
+  if (f1 (-__INT_MAX__ - 1, 1) != 0
+      || f2 (-__INT_MAX__ - 1, -1) != 0
+      || f3 (-__INT_MAX__ - 1, -1) != 0)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr69097-1.c b/gcc/testsuite/gcc.dg/pr69097-1.c
new file mode 100644 (file)
index 0000000..0c20764
--- /dev/null
@@ -0,0 +1,140 @@
+/* PR tree-optimization/69097 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* All the x % -y below should be optimized into x % y, as
+   it should never be INT_MIN % -(-1).  */
+/* { dg-final { scan-tree-dump-not "-y" "optimized" } } */
+
+int
+f1 (int x, int y)
+{
+  if (x == -__INT_MAX__ - 1)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f2 (int x, int y)
+{
+  if (x < -__INT_MAX__)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f3 (int x, int y)
+{
+  if (y == -1)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f4 (int x, int y)
+{
+  if (y < 0)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f5 (int x, int y)
+{
+  if (y >= -1)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f6 (int x, int y)
+{
+  if (y < 0 || y > 24)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f7 (int x, int y)
+{
+  if (y <= -17 || y >= -1)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f8 (int x, int y)
+{
+  if (y >= -13 && y <= 15)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f9 (int x, int y)
+{
+  return x % -(y & ~4);
+}
+
+int
+f10 (int x, int y)
+{
+  if (x != -__INT_MAX__ - 1)
+    return x % -y;
+  return 34;
+}
+
+int
+f11 (int x, int y)
+{
+  if (x >= -__INT_MAX__)
+    return x % -y;
+  return 34;
+}
+
+int
+f12 (int x, int y)
+{
+  if (y != -1)
+    return x % -y;
+  return 34;
+}
+
+int
+f13 (int x, int y)
+{
+  if (y >= 0)
+    return x % -y;
+  return 34;
+}
+
+int
+f14 (int x, int y)
+{
+  if (y < -1)
+    return x % -y;
+  return 34;
+}
+
+int
+f15 (int x, int y)
+{
+  if (y >= 0 && y <= 24)
+    return x % -y;
+  return 34;
+}
+
+int
+f16 (int x, int y)
+{
+  if (y > -17 && y < -1)
+    return x % -y;
+  return 34;
+}
+
+int
+f17 (int x, int y)
+{
+  if (y < -13 || y > 15)
+    return x % -y;
+  return 34;
+}
diff --git a/gcc/testsuite/gcc.dg/pr69097-2.c b/gcc/testsuite/gcc.dg/pr69097-2.c
new file mode 100644 (file)
index 0000000..bf7ac0e
--- /dev/null
@@ -0,0 +1,138 @@
+/* PR tree-optimization/69097 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "-y" 17 "optimized" } } */
+
+int
+f1 (int x, int y)
+{
+  if (x == -__INT_MAX__)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f2 (int x, int y)
+{
+  if (x >= -__INT_MAX__ + 1)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f3 (int x, int y)
+{
+  if (y == -2)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f4 (int x, int y)
+{
+  if (y < -1)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f5 (int x, int y)
+{
+  if (y >= 0)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f6 (int x, int y)
+{
+  if (y < -1 || y > 24)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f7 (int x, int y)
+{
+  if (y <= -17 || y >= 0)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f8 (int x, int y)
+{
+  if (y >= -13 && y <= -2)
+    __builtin_unreachable ();
+  return x % -y;
+}
+
+int
+f9 (int x, int y)
+{
+  return x % -y;
+}
+
+int
+f10 (int x, int y)
+{
+  if (x != -__INT_MAX__)
+    return x % -y;
+  return 34;
+}
+
+int
+f11 (int x, int y)
+{
+  if (x < -__INT_MAX__ + 2)
+    return x % -y;
+  return 34;
+}
+
+int
+f12 (int x, int y)
+{
+  if (y != -2)
+    return x % -y;
+  return 34;
+}
+
+int
+f13 (int x, int y)
+{
+  if (y >= -1)
+    return x % -y;
+  return 34;
+}
+
+int
+f14 (int x, int y)
+{
+  if (y < 0)
+    return x % -y;
+  return 34;
+}
+
+int
+f15 (int x, int y)
+{
+  if (y >= -1 && y <= 24)
+    return x % -y;
+  return 34;
+}
+
+int
+f16 (int x, int y)
+{
+  if (y > -17 && y < 0)
+    return x % -y;
+  return 34;
+}
+
+int
+f17 (int x, int y)
+{
+  if (y < -13 || y > -4)
+    return x % -y;
+  return 34;
+}
index 2cc33aab7277645fe760152cd61307b1803959a0..e6c11e01fd9eacd7cf1f5670e3100b9de4520042 100644 (file)
@@ -8942,7 +8942,7 @@ simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
    modulo.  */
 
 static bool
-simplify_div_or_mod_using_ranges (gimple *stmt)
+simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
 {
   enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
   tree val = NULL;
@@ -8971,12 +8971,19 @@ simplify_div_or_mod_using_ranges (gimple *stmt)
     }
 
   if (!integer_pow2p (op1))
-    return false;
-
-  if (TYPE_UNSIGNED (TREE_TYPE (op0)))
     {
-      val = integer_one_node;
+      /* X % -Y can be only optimized into X % Y either if
+        X is not INT_MIN, or Y is not -1.  Fold it now, as after
+        remove_range_assertions the range info might be not available
+        anymore.  */
+      if (rhs_code == TRUNC_MOD_EXPR
+         && fold_stmt (gsi, follow_single_use_edges))
+       return true;
+      return false;
     }
+
+  if (TYPE_UNSIGNED (TREE_TYPE (op0)))
+    val = integer_one_node;
   else
     {
       bool sop = false;
@@ -9890,7 +9897,7 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
        case TRUNC_MOD_EXPR:
          if (TREE_CODE (rhs1) == SSA_NAME
              && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
-           return simplify_div_or_mod_using_ranges (stmt);
+           return simplify_div_or_mod_using_ranges (gsi, stmt);
          break;
 
       /* Transform ABS (X) into X or -X as appropriate.  */
@@ -10200,16 +10207,6 @@ vrp_finalize (bool warn_array_bounds_p)
       fprintf (dump_file, "\n");
     }
 
-  substitute_and_fold (op_with_constant_singleton_value_range,
-                      vrp_fold_stmt, false);
-
-  if (warn_array_bounds && warn_array_bounds_p)
-    check_all_array_refs ();
-
-  /* We must identify jump threading opportunities before we release
-     the datastructures built by VRP.  */
-  identify_jump_threads ();
-
   /* Set value range to non pointer SSA_NAMEs.  */
   for (i  = 0; i < num_vr_values; i++)
     if (vr_value[i])
@@ -10230,6 +10227,16 @@ vrp_finalize (bool warn_array_bounds_p)
                        vr_value[i]->max);
       }
 
+  substitute_and_fold (op_with_constant_singleton_value_range,
+                      vrp_fold_stmt, false);
+
+  if (warn_array_bounds && warn_array_bounds_p)
+    check_all_array_refs ();
+
+  /* We must identify jump threading opportunities before we release
+     the datastructures built by VRP.  */
+  identify_jump_threads ();
+
   /* Free allocated memory.  */
   for (i = 0; i < num_vr_values; i++)
     if (vr_value[i])