re PR tree-optimization/81346 (Missed constant propagation into comparison)
authorJakub Jelinek <jakub@redhat.com>
Wed, 19 Jul 2017 12:31:59 +0000 (14:31 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 19 Jul 2017 12:31:59 +0000 (14:31 +0200)
PR tree-optimization/81346
* fold-const.h (fold_div_compare, range_check_type): Declare.
* fold-const.c (range_check_type): New function.
(build_range_check): Use range_check_type.
(fold_div_compare): No longer static, rewritten into
a match.pd helper function.
(fold_comparison): Don't call fold_div_compare here.
* match.pd (X / C1 op C2): New optimization using fold_div_compare
as helper function.

* gcc.dg/tree-ssa/pr81346-1.c: New test.
* gcc.dg/tree-ssa/pr81346-2.c: New test.
* gcc.dg/tree-ssa/pr81346-3.c: New test.
* gcc.dg/tree-ssa/pr81346-4.c: New test.
* gcc.target/i386/umod-3.c: Hide comparison against 1 from the
compiler to avoid X / C1 op C2 optimization to trigger.

From-SVN: r250338

gcc/ChangeLog
gcc/fold-const.c
gcc/fold-const.h
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr81346-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr81346-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr81346-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr81346-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/umod-3.c

index be964c6ab9edd5e596ffc10c3e43d5745db27bbd..e6e7f9d01b1664f37a612f6a70bb69bba7b25875 100644 (file)
@@ -1,3 +1,15 @@
+2017-07-19  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/81346
+       * fold-const.h (fold_div_compare, range_check_type): Declare.
+       * fold-const.c (range_check_type): New function.
+       (build_range_check): Use range_check_type.
+       (fold_div_compare): No longer static, rewritten into
+       a match.pd helper function.
+       (fold_comparison): Don't call fold_div_compare here.
+       * match.pd (X / C1 op C2): New optimization using fold_div_compare
+       as helper function.
+
 2017-07-19  Nathan Sidwell  <nathan@acm.org>
 
        * tree.h (TYPE_MINVAL, TYPE_MAXVAL): Rename to ...
index 1bcbbb58154b94093dccb384357900f7214f21ee..d702de2f97f07621e53eb853b1143d14a2d36714 100644 (file)
@@ -132,7 +132,6 @@ static tree fold_binary_op_with_conditional_arg (location_t,
                                                 enum tree_code, tree,
                                                 tree, tree,
                                                 tree, tree, int);
-static tree fold_div_compare (location_t, enum tree_code, tree, tree, tree);
 static tree fold_negate_const (tree, tree);
 static tree fold_not_const (const_tree, tree);
 static tree fold_relational_const (enum tree_code, tree, tree, tree);
@@ -4787,6 +4786,39 @@ maskable_range_p (const_tree low, const_tree high, tree type, tree *mask,
   return true;
 }
 \f
+/* Helper routine for build_range_check and match.pd.  Return the type to
+   perform the check or NULL if it shouldn't be optimized.  */
+
+tree
+range_check_type (tree etype)
+{
+  /* First make sure that arithmetics in this type is valid, then make sure
+     that it wraps around.  */
+  if (TREE_CODE (etype) == ENUMERAL_TYPE || TREE_CODE (etype) == BOOLEAN_TYPE)
+    etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype),
+                                           TYPE_UNSIGNED (etype));
+
+  if (TREE_CODE (etype) == INTEGER_TYPE && !TYPE_OVERFLOW_WRAPS (etype))
+    {
+      tree utype, minv, maxv;
+
+      /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN
+        for the type in question, as we rely on this here.  */
+      utype = unsigned_type_for (etype);
+      maxv = fold_convert (utype, TYPE_MAX_VALUE (etype));
+      maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1,
+                         build_int_cst (TREE_TYPE (maxv), 1), 1);
+      minv = fold_convert (utype, TYPE_MIN_VALUE (etype));
+
+      if (integer_zerop (range_binop (NE_EXPR, integer_type_node,
+                                     minv, 1, maxv, 1)))
+       etype = utype;
+      else
+       return NULL_TREE;
+    }
+  return etype;
+}
+
 /* Given a range, LOW, HIGH, and IN_P, an expression, EXP, and a result
    type, TYPE, return an expression to test if EXP is in (or out of, depending
    on IN_P) the range.  Return 0 if the test couldn't be created.  */
@@ -4869,31 +4901,10 @@ build_range_check (location_t loc, tree type, tree exp, int in_p,
     }
 
   /* Optimize (c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low).
-     This requires wrap-around arithmetics for the type of the expression.
-     First make sure that arithmetics in this type is valid, then make sure
-     that it wraps around.  */
-  if (TREE_CODE (etype) == ENUMERAL_TYPE || TREE_CODE (etype) == BOOLEAN_TYPE)
-    etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype),
-                                           TYPE_UNSIGNED (etype));
-
-  if (TREE_CODE (etype) == INTEGER_TYPE && !TYPE_OVERFLOW_WRAPS (etype))
-    {
-      tree utype, minv, maxv;
-
-      /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN
-        for the type in question, as we rely on this here.  */
-      utype = unsigned_type_for (etype);
-      maxv = fold_convert_loc (loc, utype, TYPE_MAX_VALUE (etype));
-      maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1,
-                         build_int_cst (TREE_TYPE (maxv), 1), 1);
-      minv = fold_convert_loc (loc, utype, TYPE_MIN_VALUE (etype));
-
-      if (integer_zerop (range_binop (NE_EXPR, integer_type_node,
-                                     minv, 1, maxv, 1)))
-       etype = utype;
-      else
-       return 0;
-    }
+     This requires wrap-around arithmetics for the type of the expression.  */
+  etype = range_check_type (etype);
+  if (etype == NULL_TREE)
+    return NULL_TREE;
 
   high = fold_convert_loc (loc, etype, high);
   low = fold_convert_loc (loc, etype, low);
@@ -6548,65 +6559,55 @@ fold_real_zero_addition_p (const_tree type, const_tree addend, int negate)
   return negate && !HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (type));
 }
 
-/* Subroutine of fold() that optimizes comparisons of a division by
+/* Subroutine of match.pd that optimizes comparisons of a division by
    a nonzero integer constant against an integer constant, i.e.
    X/C1 op C2.
 
    CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR,
-   GE_EXPR or LE_EXPR.  TYPE is the type of the result and ARG0 and ARG1
-   are the operands of the comparison.  ARG1 must be a TREE_REAL_CST.
-
-   The function returns the constant folded tree if a simplification
-   can be made, and NULL_TREE otherwise.  */
+   GE_EXPR or LE_EXPR.  ARG01 and ARG1 must be a INTEGER_CST.  */
 
-static tree
-fold_div_compare (location_t loc,
-                 enum tree_code code, tree type, tree arg0, tree arg1)
+enum tree_code
+fold_div_compare (enum tree_code code, tree c1, tree c2, tree *lo,
+                 tree *hi, bool *neg_overflow)
 {
-  tree prod, tmp, hi, lo;
-  tree arg00 = TREE_OPERAND (arg0, 0);
-  tree arg01 = TREE_OPERAND (arg0, 1);
-  signop sign = TYPE_SIGN (TREE_TYPE (arg0));
-  bool neg_overflow = false;
+  tree prod, tmp, type = TREE_TYPE (c1);
+  signop sign = TYPE_SIGN (type);
   bool overflow;
 
   /* We have to do this the hard way to detect unsigned overflow.
-     prod = int_const_binop (MULT_EXPR, arg01, arg1);  */
-  wide_int val = wi::mul (arg01, arg1, sign, &overflow);
-  prod = force_fit_type (TREE_TYPE (arg00), val, -1, overflow);
-  neg_overflow = false;
+     prod = int_const_binop (MULT_EXPR, c1, c2);  */
+  wide_int val = wi::mul (c1, c2, sign, &overflow);
+  prod = force_fit_type (type, val, -1, overflow);
+  *neg_overflow = false;
 
   if (sign == UNSIGNED)
     {
-      tmp = int_const_binop (MINUS_EXPR, arg01,
-                             build_int_cst (TREE_TYPE (arg01), 1));
-      lo = prod;
+      tmp = int_const_binop (MINUS_EXPR, c1, build_int_cst (type, 1));
+      *lo = prod;
 
-      /* Likewise hi = int_const_binop (PLUS_EXPR, prod, tmp).  */
+      /* Likewise *hi = int_const_binop (PLUS_EXPR, prod, tmp).  */
       val = wi::add (prod, tmp, sign, &overflow);
-      hi = force_fit_type (TREE_TYPE (arg00), val,
-                          -1, overflow | TREE_OVERFLOW (prod));
+      *hi = force_fit_type (type, val, -1, overflow | TREE_OVERFLOW (prod));
     }
-  else if (tree_int_cst_sgn (arg01) >= 0)
+  else if (tree_int_cst_sgn (c1) >= 0)
     {
-      tmp = int_const_binop (MINUS_EXPR, arg01,
-                            build_int_cst (TREE_TYPE (arg01), 1));
-      switch (tree_int_cst_sgn (arg1))
+      tmp = int_const_binop (MINUS_EXPR, c1, build_int_cst (type, 1));
+      switch (tree_int_cst_sgn (c2))
        {
        case -1:
-         neg_overflow = true;
-         lo = int_const_binop (MINUS_EXPR, prod, tmp);
-         hi = prod;
+         *neg_overflow = true;
+         *lo = int_const_binop (MINUS_EXPR, prod, tmp);
+         *hi = prod;
          break;
 
-       case  0:
-         lo = fold_negate_const (tmp, TREE_TYPE (arg0));
-         hi = tmp;
+       case 0:
+         *lo = fold_negate_const (tmp, type);
+         *hi = tmp;
          break;
 
-       case  1:
-          hi = int_const_binop (PLUS_EXPR, prod, tmp);
-         lo = prod;
+       case 1:
+         *hi = int_const_binop (PLUS_EXPR, prod, tmp);
+         *lo = prod;
          break;
 
        default:
@@ -6618,24 +6619,23 @@ fold_div_compare (location_t loc,
       /* A negative divisor reverses the relational operators.  */
       code = swap_tree_comparison (code);
 
-      tmp = int_const_binop (PLUS_EXPR, arg01,
-                            build_int_cst (TREE_TYPE (arg01), 1));
-      switch (tree_int_cst_sgn (arg1))
+      tmp = int_const_binop (PLUS_EXPR, c1, build_int_cst (type, 1));
+      switch (tree_int_cst_sgn (c2))
        {
        case -1:
-         hi = int_const_binop (MINUS_EXPR, prod, tmp);
-         lo = prod;
+         *hi = int_const_binop (MINUS_EXPR, prod, tmp);
+         *lo = prod;
          break;
 
-       case  0:
-         hi = fold_negate_const (tmp, TREE_TYPE (arg0));
-         lo = tmp;
+       case 0:
+         *hi = fold_negate_const (tmp, type);
+         *lo = tmp;
          break;
 
-       case  1:
-         neg_overflow = true;
-         lo = int_const_binop (PLUS_EXPR, prod, tmp);
-         hi = prod;
+       case 1:
+         *neg_overflow = true;
+         *lo = int_const_binop (PLUS_EXPR, prod, tmp);
+         *hi = prod;
          break;
 
        default:
@@ -6643,63 +6643,17 @@ fold_div_compare (location_t loc,
        }
     }
 
-  switch (code)
-    {
-    case EQ_EXPR:
-      if (TREE_OVERFLOW (lo) && TREE_OVERFLOW (hi))
-       return omit_one_operand_loc (loc, type, integer_zero_node, arg00);
-      if (TREE_OVERFLOW (hi))
-       return fold_build2_loc (loc, GE_EXPR, type, arg00, lo);
-      if (TREE_OVERFLOW (lo))
-       return fold_build2_loc (loc, LE_EXPR, type, arg00, hi);
-      return build_range_check (loc, type, arg00, 1, lo, hi);
+  if (code != EQ_EXPR && code != NE_EXPR)
+    return code;
 
-    case NE_EXPR:
-      if (TREE_OVERFLOW (lo) && TREE_OVERFLOW (hi))
-       return omit_one_operand_loc (loc, type, integer_one_node, arg00);
-      if (TREE_OVERFLOW (hi))
-       return fold_build2_loc (loc, LT_EXPR, type, arg00, lo);
-      if (TREE_OVERFLOW (lo))
-       return fold_build2_loc (loc, GT_EXPR, type, arg00, hi);
-      return build_range_check (loc, type, arg00, 0, lo, hi);
+  if (TREE_OVERFLOW (*lo)
+      || operand_equal_p (*lo, TYPE_MIN_VALUE (type), 0))
+    *lo = NULL_TREE;
+  if (TREE_OVERFLOW (*hi)
+      || operand_equal_p (*hi, TYPE_MAX_VALUE (type), 0))
+    *hi = NULL_TREE;
 
-    case LT_EXPR:
-      if (TREE_OVERFLOW (lo))
-       {
-         tmp = neg_overflow ? integer_zero_node : integer_one_node;
-         return omit_one_operand_loc (loc, type, tmp, arg00);
-       }
-      return fold_build2_loc (loc, LT_EXPR, type, arg00, lo);
-
-    case LE_EXPR:
-      if (TREE_OVERFLOW (hi))
-       {
-         tmp = neg_overflow ? integer_zero_node : integer_one_node;
-         return omit_one_operand_loc (loc, type, tmp, arg00);
-       }
-      return fold_build2_loc (loc, LE_EXPR, type, arg00, hi);
-
-    case GT_EXPR:
-      if (TREE_OVERFLOW (hi))
-       {
-         tmp = neg_overflow ? integer_one_node : integer_zero_node;
-         return omit_one_operand_loc (loc, type, tmp, arg00);
-       }
-      return fold_build2_loc (loc, GT_EXPR, type, arg00, hi);
-
-    case GE_EXPR:
-      if (TREE_OVERFLOW (lo))
-       {
-         tmp = neg_overflow ? integer_one_node : integer_zero_node;
-         return omit_one_operand_loc (loc, type, tmp, arg00);
-       }
-      return fold_build2_loc (loc, GE_EXPR, type, arg00, lo);
-
-    default:
-      break;
-    }
-
-  return NULL_TREE;
+  return code;
 }
 
 
@@ -8793,20 +8747,6 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
        }
     }
 
-  /* We can fold X/C1 op C2 where C1 and C2 are integer constants
-     into a single range test.  */
-  if (TREE_CODE (arg0) == TRUNC_DIV_EXPR
-      && TREE_CODE (arg1) == INTEGER_CST
-      && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-      && !integer_zerop (TREE_OPERAND (arg0, 1))
-      && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
-      && !TREE_OVERFLOW (arg1))
-    {
-      tem = fold_div_compare (loc, code, type, arg0, arg1);
-      if (tem != NULL_TREE)
-       return tem;
-    }
-
   return NULL_TREE;
 }
 
index 7abf4d1bc06b4e3eb9d5f427fd8e4dc1de12ab2d..780e5c781b78deea4431ccea2fbe692f99ba9b6e 100644 (file)
@@ -88,6 +88,8 @@ extern void fold_undefer_overflow_warnings (bool, const gimple *, int);
 extern void fold_undefer_and_ignore_overflow_warnings (void);
 extern bool fold_deferring_overflow_warnings_p (void);
 extern void fold_overflow_warning (const char*, enum warn_strict_overflow_code);
+extern enum tree_code fold_div_compare (enum tree_code, tree, tree,
+                                       tree *, tree *, bool *);
 extern int operand_equal_p (const_tree, const_tree, unsigned int);
 extern int multiple_of_p (tree, const_tree, const_tree);
 #define omit_one_operand(T1,T2,T3)\
@@ -175,6 +177,7 @@ extern bool tree_expr_nonnegative_warnv_p (tree, bool *, int = 0);
 extern tree make_range (tree, int *, tree *, tree *, bool *);
 extern tree make_range_step (location_t, enum tree_code, tree, tree, tree,
                             tree *, tree *, int *, bool *);
+extern tree range_check_type (tree);
 extern tree build_range_check (location_t, tree, tree, int, tree, tree);
 extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int,
                          tree, tree);
index 979085aba5ae67faff3d6613275ab271632f3de5..fe270934c03fe3519fbffefc79577569ec810d2c 100644 (file)
@@ -1132,6 +1132,60 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (if (wi::gt_p(@2, 0, TYPE_SIGN (TREE_TYPE (@2))))
    (cmp @0 @1))))
 
+/* X / C1 op C2 into a simple range test.  */
+(for cmp (simple_comparison)
+ (simplify
+  (cmp (trunc_div:s @0 INTEGER_CST@1) INTEGER_CST@2)
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && integer_nonzerop (@1)
+       && !TREE_OVERFLOW (@1)
+       && !TREE_OVERFLOW (@2))
+   (with { tree lo, hi; bool neg_overflow;
+          enum tree_code code = fold_div_compare (cmp, @1, @2, &lo, &hi,
+                                                  &neg_overflow); }
+    (switch
+     (if (code == LT_EXPR || code == GE_EXPR)
+       (if (TREE_OVERFLOW (lo))
+       { build_int_cst (type, (code == LT_EXPR) ^ neg_overflow); }
+       (if (code == LT_EXPR)
+        (lt @0 { lo; })
+        (ge @0 { lo; }))))
+     (if (code == LE_EXPR || code == GT_EXPR)
+       (if (TREE_OVERFLOW (hi))
+       { build_int_cst (type, (code == LE_EXPR) ^ neg_overflow); }
+       (if (code == LE_EXPR)
+        (le @0 { hi; })
+        (gt @0 { hi; }))))
+     (if (!lo && !hi)
+      { build_int_cst (type, code == NE_EXPR); })
+     (if (code == EQ_EXPR && !hi)
+      (ge @0 { lo; }))
+     (if (code == EQ_EXPR && !lo)
+      (le @0 { hi; }))
+     (if (code == NE_EXPR && !hi)
+      (lt @0 { lo; }))
+     (if (code == NE_EXPR && !lo)
+      (gt @0 { hi; }))
+     (if (GENERIC)
+      { build_range_check (UNKNOWN_LOCATION, type, @0, code == EQ_EXPR,
+                          lo, hi); })
+     (with
+      {
+       tree etype = range_check_type (TREE_TYPE (@0));
+       if (etype)
+         {
+           if (! TYPE_UNSIGNED (etype))
+             etype = unsigned_type_for (etype);
+           hi = fold_convert (etype, hi);
+           lo = fold_convert (etype, lo);
+           hi = const_binop (MINUS_EXPR, etype, hi, lo);
+         }
+      }
+      (if (etype && hi && !TREE_OVERFLOW (hi))
+       (if (code == EQ_EXPR)
+       (le (minus (convert:etype @0) { lo; }) { hi; })
+       (gt (minus (convert:etype @0) { lo; }) { hi; })))))))))
+
 /* X + Z < Y + Z is the same as X < Y when there is no overflow.  */
 (for op (lt le ge gt)
  (simplify
index a688b31bbcc1f9cc9e194782785a877beb6660a6..cad1ade6ea8b360c20765ba3fd0b266ef1f4a079 100644 (file)
@@ -1,3 +1,13 @@
+2017-07-19  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/81346
+       * gcc.dg/tree-ssa/pr81346-1.c: New test.
+       * gcc.dg/tree-ssa/pr81346-2.c: New test.
+       * gcc.dg/tree-ssa/pr81346-3.c: New test.
+       * gcc.dg/tree-ssa/pr81346-4.c: New test.
+       * gcc.target/i386/umod-3.c: Hide comparison against 1 from the
+       compiler to avoid X / C1 op C2 optimization to trigger.
+
 2017-07-19  Martin Liska  <mliska@suse.cz>
 
        PR sanitizer/63361
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81346-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-1.c
new file mode 100644 (file)
index 0000000..c766d6f
--- /dev/null
@@ -0,0 +1,37 @@
+/* PR tree-optimization/81346 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "return 1;" 32 "optimized" } } */
+
+int f00 (int x) { return x / 49152 > -49152; }
+int f01 (int x) { int a = 49152, b = -49152; return x / a > b; }
+int f02 (int x) { return x / 49152 >= -49152; }
+int f03 (int x) { int a = 49152, b = -49152; return x / a >= b; }
+int f04 (int x) { return x / 49152 < 49152; }
+int f05 (int x) { int a = 49152, b = 49152; return x / a < b; }
+int f06 (int x) { return x / 49152 <= 49152; }
+int f07 (int x) { int a = 49152, b = 49152; return x / a <= b; }
+int f08 (int x) { return x / 46340 >= -46341; }
+int f09 (int x) { int a = 46340, b = -46341; return x / a >= b; }
+int f10 (int x) { return x / 46340 <= 46341; }
+int f11 (int x) { int a = 46340, b = 46341; return x / a <= b; }
+int f12 (int x) { return x / 49152 != -49152; }
+int f13 (int x) { int a = 49152, b = -49152; return x / a != b; }
+int f14 (int x) { return x / 49152 != 49152; }
+int f15 (int x) { int a = 49152, b = 49152; return x / a != b; }
+int f16 (int x) { return x / -49152 > -49152; }
+int f17 (int x) { int a = -49152, b = -49152; return x / a > b; }
+int f18 (int x) { return x / -49152 >= -49152; }
+int f19 (int x) { int a = -49152, b = -49152; return x / a >= b; }
+int f20 (int x) { return x / -49152 < 49152; }
+int f21 (int x) { int a = -49152, b = 49152; return x / a < b; }
+int f22 (int x) { return x / -49152 <= 49152; }
+int f23 (int x) { int a = -49152, b = 49152; return x / a <= b; }
+int f24 (int x) { return x / -46340 >= -46341; }
+int f25 (int x) { int a = -46340, b = -46341; return x / a >= b; }
+int f26 (int x) { return x / -46340 <= 46341; }
+int f27 (int x) { int a = -46340, b = 46341; return x / a <= b; }
+int f28 (int x) { return x / -49152 != 49152; }
+int f29 (int x) { int a = -49152, b = 49152; return x / a != b; }
+int f30 (int x) { return x / -49152 != -49152; }
+int f31 (int x) { int a = -49152, b = -49152; return x / a != b; }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81346-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-2.c
new file mode 100644 (file)
index 0000000..87bad39
--- /dev/null
@@ -0,0 +1,37 @@
+/* PR tree-optimization/81346 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "return 0;" 32 "optimized" } } */
+
+int f00 (int x) { return x / 49152 > 49152; }
+int f01 (int x) { int a = 49152, b = 49152; return x / a > b; }
+int f02 (int x) { return x / 49152 >= 49152; }
+int f03 (int x) { int a = 49152, b = 49152; return x / a >= b; }
+int f04 (int x) { return x / 49152 < -49152; }
+int f05 (int x) { int a = 49152, b = -49152; return x / a < b; }
+int f06 (int x) { return x / 49152 <= -49152; }
+int f07 (int x) { int a = 49152, b = -49152; return x / a <= b; }
+int f08 (int x) { return x / 46340 > 46341; }
+int f09 (int x) { int a = 46340, b = 46341; return x / a > b; }
+int f10 (int x) { return x / 46340 < -46341; }
+int f11 (int x) { int a = 46340, b = -46341; return x / a < b; }
+int f12 (int x) { return x / 49152 == -49152; }
+int f13 (int x) { int a = 49152, b = -49152; return x / a == b; }
+int f14 (int x) { return x / 49152 == 49152; }
+int f15 (int x) { int a = 49152, b = 49152; return x / a == b; }
+int f16 (int x) { return x / -49152 > 49152; }
+int f17 (int x) { int a = -49152, b = 49152; return x / a > b; }
+int f18 (int x) { return x / -49152 >= 49152; }
+int f19 (int x) { int a = -49152, b = 49152; return x / a >= b; }
+int f20 (int x) { return x / -49152 < -49152; }
+int f21 (int x) { int a = -49152, b = -49152; return x / a < b; }
+int f22 (int x) { return x / -49152 <= -49152; }
+int f23 (int x) { int a = -49152, b = -49152; return x / a <= b; }
+int f24 (int x) { return x / -46340 > 46341; }
+int f25 (int x) { int a = -46340, b = 46341; return x / a > b; }
+int f26 (int x) { return x / -46340 < -46341; }
+int f27 (int x) { int a = -46340, b = -46341; return x / a < b; }
+int f28 (int x) { return x / -49152 == 49152; }
+int f29 (int x) { int a = -49152, b = 49152; return x / a == b; }
+int f30 (int x) { return x / -49152 == -49152; }
+int f31 (int x) { int a = -49152, b = -49152; return x / a == b; }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81346-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-3.c
new file mode 100644 (file)
index 0000000..bef64a8
--- /dev/null
@@ -0,0 +1,109 @@
+/* PR tree-optimization/81346 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-not " / " "optimized" } } */
+
+__attribute__((noinline, noclone)) int f00 (int x) { return x / 46340 > -46341; }
+__attribute__((noinline, noclone)) int f01 (int x) { int a = 46340, b = -46341; return x / a > b; }
+__attribute__((noinline, noclone)) int f02 (int x) { return x / 46340 >= 46341; }
+__attribute__((noinline, noclone)) int f03 (int x) { int a = 46340, b = 46341; return x / a >= b; }
+__attribute__((noinline, noclone)) int f04 (int x) { return x / 46340 < 46341; }
+__attribute__((noinline, noclone)) int f05 (int x) { int a = 46340, b = 46341; return x / a < b; }
+__attribute__((noinline, noclone)) int f06 (int x) { return x / 46340 <= -46341; }
+__attribute__((noinline, noclone)) int f07 (int x) { int a = 46340, b = -46341; return x / a <= b; }
+__attribute__((noinline, noclone)) int f08 (int x) { return x / 46340 == -46341; }
+__attribute__((noinline, noclone)) int f09 (int x) { int a = 46340, b = -46341; return x / a == b; }
+__attribute__((noinline, noclone)) int f10 (int x) { return x / 46340 == 46341; }
+__attribute__((noinline, noclone)) int f11 (int x) { int a = 46340, b = 46341; return x / a == b; }
+__attribute__((noinline, noclone)) int f12 (int x) { return x / 46340 != -46341; }
+__attribute__((noinline, noclone)) int f13 (int x) { int a = 46340, b = -46341; return x / a != b; }
+__attribute__((noinline, noclone)) int f14 (int x) { return x / 46340 != 46341; }
+__attribute__((noinline, noclone)) int f15 (int x) { int a = 46340, b = 46341; return x / a != b; }
+__attribute__((noinline, noclone)) int f16 (int x) { return x / 15 > -15; }
+__attribute__((noinline, noclone)) int f17 (int x) { int a = 15, b = -15; return x / a > b; }
+__attribute__((noinline, noclone)) int f18 (int x) { return x / 15 > 15; }
+__attribute__((noinline, noclone)) int f19 (int x) { int a = 15, b = 15; return x / a > b; }
+__attribute__((noinline, noclone)) int f20 (int x) { return x / 15 >= -15; }
+__attribute__((noinline, noclone)) int f21 (int x) { int a = 15, b = -15; return x / a >= b; }
+__attribute__((noinline, noclone)) int f22 (int x) { return x / 15 >= 15; }
+__attribute__((noinline, noclone)) int f23 (int x) { int a = 15, b = 15; return x / a >= b; }
+__attribute__((noinline, noclone)) int f24 (int x) { return x / 15 < -15; }
+__attribute__((noinline, noclone)) int f25 (int x) { int a = 15, b = -15; return x / a < b; }
+__attribute__((noinline, noclone)) int f26 (int x) { return x / 15 < 15; }
+__attribute__((noinline, noclone)) int f27 (int x) { int a = 15, b = 15; return x / a < b; }
+__attribute__((noinline, noclone)) int f28 (int x) { return x / 15 <= -15; }
+__attribute__((noinline, noclone)) int f29 (int x) { int a = 15, b = -15; return x / a <= b; }
+__attribute__((noinline, noclone)) int f30 (int x) { return x / 15 <= 15; }
+__attribute__((noinline, noclone)) int f31 (int x) { int a = 15, b = 15; return x / a <= b; }
+__attribute__((noinline, noclone)) int f32 (int x) { return x / 15 == -15; }
+__attribute__((noinline, noclone)) int f33 (int x) { int a = 15, b = -15; return x / a == b; }
+__attribute__((noinline, noclone)) int f34 (int x) { return x / 15 == 15; }
+__attribute__((noinline, noclone)) int f35 (int x) { int a = 15, b = 15; return x / a == b; }
+__attribute__((noinline, noclone)) int f36 (int x) { return x / 15 != -15; }
+__attribute__((noinline, noclone)) int f37 (int x) { int a = 15, b = -15; return x / a != b; }
+__attribute__((noinline, noclone)) int f38 (int x) { return x / 15 != 15; }
+__attribute__((noinline, noclone)) int f39 (int x) { int a = 15, b = 15; return x / a != b; }
+__attribute__((noinline, noclone)) int f40 (int x) { return x / -46340 > -46341; }
+__attribute__((noinline, noclone)) int f41 (int x) { int a = -46340, b = -46341; return x / a > b; }
+__attribute__((noinline, noclone)) int f42 (int x) { return x / -46340 >= 46341; }
+__attribute__((noinline, noclone)) int f43 (int x) { int a = -46340, b = 46341; return x / a >= b; }
+__attribute__((noinline, noclone)) int f44 (int x) { return x / -46340 < 46341; }
+__attribute__((noinline, noclone)) int f45 (int x) { int a = -46340, b = 46341; return x / a < b; }
+__attribute__((noinline, noclone)) int f46 (int x) { return x / -46340 <= -46341; }
+__attribute__((noinline, noclone)) int f47 (int x) { int a = -46340, b = -46341; return x / a <= b; }
+__attribute__((noinline, noclone)) int f48 (int x) { return x / -46340 == 46341; }
+__attribute__((noinline, noclone)) int f49 (int x) { int a = -46340, b = 46341; return x / a == b; }
+__attribute__((noinline, noclone)) int f50 (int x) { return x / -46340 == -46341; }
+__attribute__((noinline, noclone)) int f51 (int x) { int a = -46340, b = -46341; return x / a == b; }
+__attribute__((noinline, noclone)) int f52 (int x) { return x / -46340 != 46341; }
+__attribute__((noinline, noclone)) int f53 (int x) { int a = -46340, b = 46341; return x / a != b; }
+__attribute__((noinline, noclone)) int f54 (int x) { return x / -46340 != -46341; }
+__attribute__((noinline, noclone)) int f55 (int x) { int a = -46340, b = -46341; return x / a != b; }
+__attribute__((noinline, noclone)) int f56 (int x) { return x / -15 > 15; }
+__attribute__((noinline, noclone)) int f57 (int x) { int a = -15, b = 15; return x / a > b; }
+__attribute__((noinline, noclone)) int f58 (int x) { return x / -15 > -15; }
+__attribute__((noinline, noclone)) int f59 (int x) { int a = -15, b = -15; return x / a > b; }
+__attribute__((noinline, noclone)) int f60 (int x) { return x / -15 >= 15; }
+__attribute__((noinline, noclone)) int f61 (int x) { int a = -15, b = 15; return x / a >= b; }
+__attribute__((noinline, noclone)) int f62 (int x) { return x / -15 >= -15; }
+__attribute__((noinline, noclone)) int f63 (int x) { int a = -15, b = -15; return x / a >= b; }
+__attribute__((noinline, noclone)) int f64 (int x) { return x / -15 < 15; }
+__attribute__((noinline, noclone)) int f65 (int x) { int a = -15, b = 15; return x / a < b; }
+__attribute__((noinline, noclone)) int f66 (int x) { return x / -15 < -15; }
+__attribute__((noinline, noclone)) int f67 (int x) { int a = -15, b = -15; return x / a < b; }
+__attribute__((noinline, noclone)) int f68 (int x) { return x / -15 <= 15; }
+__attribute__((noinline, noclone)) int f69 (int x) { int a = -15, b = 15; return x / a <= b; }
+__attribute__((noinline, noclone)) int f70 (int x) { return x / -15 <= -15; }
+__attribute__((noinline, noclone)) int f71 (int x) { int a = -15, b = -15; return x / a <= b; }
+__attribute__((noinline, noclone)) int f72 (int x) { return x / -15 == 15; }
+__attribute__((noinline, noclone)) int f73 (int x) { int a = -15, b = 15; return x / a == b; }
+__attribute__((noinline, noclone)) int f74 (int x) { return x / -15 == -15; }
+__attribute__((noinline, noclone)) int f75 (int x) { int a = -15, b = -15; return x / a == b; }
+__attribute__((noinline, noclone)) int f76 (int x) { return x / -15 != 15; }
+__attribute__((noinline, noclone)) int f77 (int x) { int a = -15, b = 15; return x / a != b; }
+__attribute__((noinline, noclone)) int f78 (int x) { return x / -15 != -15; }
+__attribute__((noinline, noclone)) int f79 (int x) { int a = -15, b = -15; return x / a != b; }
+__attribute__((noinline, noclone)) int f80 (int x) { return x / -15 > 0; }
+__attribute__((noinline, noclone)) int f81 (int x) { int a = -15, b = 0; return x / a > b; }
+__attribute__((noinline, noclone)) int f82 (int x) { return x / 15 > 0; }
+__attribute__((noinline, noclone)) int f83 (int x) { int a = 15, b = 0; return x / a > b; }
+__attribute__((noinline, noclone)) int f84 (int x) { return x / -15 >= 0; }
+__attribute__((noinline, noclone)) int f85 (int x) { int a = -15, b = 0; return x / a >= b; }
+__attribute__((noinline, noclone)) int f86 (int x) { return x / 15 >= 0; }
+__attribute__((noinline, noclone)) int f87 (int x) { int a = 15, b = 0; return x / a >= b; }
+__attribute__((noinline, noclone)) int f88 (int x) { return x / -15 < 0; }
+__attribute__((noinline, noclone)) int f89 (int x) { int a = -15, b = 0; return x / a < b; }
+__attribute__((noinline, noclone)) int f90 (int x) { return x / 15 < 0; }
+__attribute__((noinline, noclone)) int f91 (int x) { int a = 15, b = 0; return x / a < b; }
+__attribute__((noinline, noclone)) int f92 (int x) { return x / -15 <= 0; }
+__attribute__((noinline, noclone)) int f93 (int x) { int a = -15, b = 0; return x / a <= b; }
+__attribute__((noinline, noclone)) int f94 (int x) { return x / 15 <= 0; }
+__attribute__((noinline, noclone)) int f95 (int x) { int a = 15, b = 0; return x / a <= b; }
+__attribute__((noinline, noclone)) int f96 (int x) { return x / -15 == 0; }
+__attribute__((noinline, noclone)) int f97 (int x) { int a = -15, b = 0; return x / a == b; }
+__attribute__((noinline, noclone)) int f98 (int x) { return x / 15 == 0; }
+__attribute__((noinline, noclone)) int f99 (int x) { int a = 15, b = 0; return x / a == b; }
+__attribute__((noinline, noclone)) int f100 (int x) { return x / -15 != 0; }
+__attribute__((noinline, noclone)) int f101 (int x) { int a = -15, b = 0; return x / a != b; }
+__attribute__((noinline, noclone)) int f102 (int x) { return x / 15 != 0; }
+__attribute__((noinline, noclone)) int f103 (int x) { int a = 15, b = 0; return x / a != b; }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81346-4.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-4.c
new file mode 100644 (file)
index 0000000..f93ad46
--- /dev/null
@@ -0,0 +1,79 @@
+/* PR tree-optimization/81346 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include "pr81346-3.c"
+
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-__INT_MAX__ - 1)
+
+extern void abort (void);
+
+int
+main ()
+{
+  if (__CHAR_BIT__ != 8 || __SIZEOF_INT__ != 4)
+    return 0;
+#define TEST(fn1, fn2, v1, v2) \
+  do { \
+    int w1 = v1; int w2 = v2; \
+    int in = 1; if (w1 > w2) { in = w1; w1 = w2; w2 = in; in = 0; } \
+    if (w1 != INT_MIN) { if (fn1 (w1 - 1) != !in || fn2 (w1 - 1) != !in) abort (); } \
+    if (fn1 (w1) != in || fn2 (w1) != in) abort (); \
+    if (fn1 (w2) != in || fn2 (w2) != in) abort (); \
+    if (w2 != INT_MAX) { if (fn1 (w2 + 1) != !in || fn2 (w2 + 1) != !in) abort (); } \
+  } while (0)
+TEST (f00, f01, -2147441939, INT_MAX);
+TEST (f02, f03, 2147441940, INT_MAX);
+TEST (f04, f05, INT_MIN, 2147441939);
+TEST (f06, f07, INT_MIN, -2147441940);
+TEST (f08, f09, INT_MIN, -2147441940);
+TEST (f10, f11, 2147441940, INT_MAX);
+TEST (f12, f13, -2147441939, INT_MAX);
+TEST (f14, f15, INT_MIN, 2147441939);
+TEST (f16, f17, -224, INT_MAX);
+TEST (f18, f19, 240, INT_MAX);
+TEST (f20, f21, -239, INT_MAX);
+TEST (f22, f23, 225, INT_MAX);
+TEST (f24, f25, INT_MIN, -240);
+TEST (f26, f27, INT_MIN, 224);
+TEST (f28, f29, INT_MIN, -225);
+TEST (f30, f31, INT_MIN, 239);
+TEST (f32, f33, -239, -225);
+TEST (f34, f35, 225, 239);
+TEST (f36, f37, -225, -239);
+TEST (f38, f39, 239, 225);
+TEST (f40, f41, INT_MIN, 2147441939);
+TEST (f42, f43, INT_MIN, -2147441940);
+TEST (f44, f45, -2147441939, INT_MAX);
+TEST (f46, f47, 2147441940, INT_MAX);
+TEST (f48, f49, INT_MIN, -2147441940);
+TEST (f50, f51, 2147441940, INT_MAX);
+TEST (f52, f53, -2147441939, INT_MAX);
+TEST (f54, f55, INT_MIN, 2147441939);
+TEST (f56, f57, INT_MIN, -240);
+TEST (f58, f59, INT_MIN, 224);
+TEST (f60, f61, INT_MIN, -225);
+TEST (f62, f63, INT_MIN, 239);
+TEST (f64, f65, -224, INT_MAX);
+TEST (f66, f67, 240, INT_MAX);
+TEST (f68, f69, -239, INT_MAX);
+TEST (f70, f71, 225, INT_MAX);
+TEST (f72, f73, -239, -225);
+TEST (f74, f75, 225, 239);
+TEST (f76, f77, -225, -239);
+TEST (f78, f79, 239, 225);
+TEST (f80, f81, INT_MIN, -15);
+TEST (f82, f83, 15, INT_MAX);
+TEST (f84, f85, INT_MIN, 14);
+TEST (f86, f87, -14, INT_MAX);
+TEST (f88, f89, 15, INT_MAX);
+TEST (f90, f91, INT_MIN, -15);
+TEST (f92, f93, -14, INT_MAX);
+TEST (f94, f95, INT_MIN, 14);
+TEST (f96, f97, -14, 14);
+TEST (f98, f99, -14, 14);
+TEST (f100, f101, 14, -14);
+TEST (f102, f103, 14, -14);
+  return 0;
+}
index e1fb988263a6363288506c659c9bb03a8336664c..609ab5207128830b936596c579f98afe7c6a7de5 100644 (file)
@@ -9,9 +9,11 @@ int
 main ()
 {
   unsigned char cy;
-  
-  cy = cx / 6; if (cy != 1) exit (1);
-  cy = cx % 6; if (cy != 1) exit (1);
+  unsigned char cz = 1;
+  asm ("" : "+q" (cz));
+
+  cy = cx / 6; if (cy != cz) exit (1);
+  cy = cx % 6; if (cy != cz) exit (1);
 
   exit(0);
 }