dojump.c (do_jump): Move below.
authorPaolo Bonzini <bonzini@gnu.org>
Thu, 11 Sep 2008 14:45:05 +0000 (14:45 +0000)
committerPaolo Bonzini <bonzini@gcc.gnu.org>
Thu, 11 Sep 2008 14:45:05 +0000 (14:45 +0000)
2008-09-11  Paolo Bonzini  <bonzini@gnu.org>

* dojump.c (do_jump) [BIT_AND_EXPR]: Move below.  Fall through to
TRUTH_AND_EXPR for boolean (1-bit precision) expressions.
(do_jump) [BIT_IOR_EXPR]: Compile as TRUTH_OR_EXPR.

* tree-flow.h (simplify_stmt_using_ranges): Accept a GSI, return a bool.
* tree-ssa-propagate.c (substitute_and_fold): Pass a GSI to
VRP's simplify_stmt_using_ranges.  Do simplify_stmt_using_ranges
before finalizing the changes.
* tree-vrp.c (extract_range_from_binary_expr): Add limited support
for BIT_IOR_EXPR.
(simplify_truth_ops_using_ranges): New.
(simplify_div_or_mod_using_ranges, simplify_abs_using_ranges,
simplify_cond_using_ranges, simplify_switch_using_ranges): Return
whether a simplification was made.
(simplify_stmt_using_ranges): Ditto, and accept a GSI.  For GS_ASSIGN,
use a switch statement and also call simplify_truth_ops_using_ranges.

testsuite:
2008-09-11  Paolo Bonzini  <bonzini@gnu.org>

* gcc.dg/tree-ssa/vrp47.c: New.
* gcc.target/i386/andor-2.c: New.

From-SVN: r140288

gcc/ChangeLog
gcc/dojump.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/vrp47.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/andor-2.c [new file with mode: 0644]
gcc/tree-flow.h
gcc/tree-ssa-propagate.c
gcc/tree-vrp.c

index 67d1649..2f4e784 100644 (file)
@@ -1,3 +1,22 @@
+2008-09-11  Paolo Bonzini  <bonzini@gnu.org>
+
+       * dojump.c (do_jump) [BIT_AND_EXPR]: Move below.  Fall through to
+       TRUTH_AND_EXPR for boolean (1-bit precision) expressions.
+       (do_jump) [BIT_IOR_EXPR]: Compile as TRUTH_OR_EXPR.
+
+       * tree-flow.h (simplify_stmt_using_ranges): Accept a GSI, return a bool.
+       * tree-ssa-propagate.c (substitute_and_fold): Pass a GSI to
+       VRP's simplify_stmt_using_ranges.  Do simplify_stmt_using_ranges
+       before finalizing the changes.
+       * tree-vrp.c (extract_range_from_binary_expr): Add limited support
+       for BIT_IOR_EXPR.
+       (simplify_truth_ops_using_ranges): New.
+       (simplify_div_or_mod_using_ranges, simplify_abs_using_ranges,
+       simplify_cond_using_ranges, simplify_switch_using_ranges): Return
+       whether a simplification was made.
+       (simplify_stmt_using_ranges): Ditto, and accept a GSI.  For GS_ASSIGN,
+       use a switch statement and also call simplify_truth_ops_using_ranges.
+
 2008-09-11  Jan Hubicka  <jh@suse.cz>
 
        * ggc-common.c (loc_array): Make static.
index 0ff5395..849f69f 100644 (file)
@@ -208,79 +208,6 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
       do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
       break;
 
-    case BIT_AND_EXPR:
-      /* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1.
-        See if the former is preferred for jump tests and restore it
-        if so.  */
-      if (integer_onep (TREE_OPERAND (exp, 1)))
-       {
-         tree exp0 = TREE_OPERAND (exp, 0);
-         rtx set_label, clr_label;
-
-         /* Strip narrowing integral type conversions.  */
-         while (CONVERT_EXPR_P (exp0)
-                && TREE_OPERAND (exp0, 0) != error_mark_node
-                && TYPE_PRECISION (TREE_TYPE (exp0))
-                   <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp0, 0))))
-           exp0 = TREE_OPERAND (exp0, 0);
-
-         /* "exp0 ^ 1" inverts the sense of the single bit test.  */
-         if (TREE_CODE (exp0) == BIT_XOR_EXPR
-             && integer_onep (TREE_OPERAND (exp0, 1)))
-           {
-             exp0 = TREE_OPERAND (exp0, 0);
-             clr_label = if_true_label;
-             set_label = if_false_label;
-           }
-         else
-           {
-             clr_label = if_false_label;
-             set_label = if_true_label;
-           }
-
-         if (TREE_CODE (exp0) == RSHIFT_EXPR)
-           {
-             tree arg = TREE_OPERAND (exp0, 0);
-             tree shift = TREE_OPERAND (exp0, 1);
-             tree argtype = TREE_TYPE (arg);
-             if (TREE_CODE (shift) == INTEGER_CST
-                 && compare_tree_int (shift, 0) >= 0
-                 && compare_tree_int (shift, HOST_BITS_PER_WIDE_INT) < 0
-                 && prefer_and_bit_test (TYPE_MODE (argtype),
-                                         TREE_INT_CST_LOW (shift)))
-               {
-                 HOST_WIDE_INT mask = (HOST_WIDE_INT) 1
-                                      << TREE_INT_CST_LOW (shift);
-                 do_jump (build2 (BIT_AND_EXPR, argtype, arg,
-                                  build_int_cst_type (argtype, mask)),
-                          clr_label, set_label);
-                 break;
-               }
-           }
-       }
-
-      /* If we are AND'ing with a small constant, do this comparison in the
-         smallest type that fits.  If the machine doesn't have comparisons
-         that small, it will be converted back to the wider comparison.
-         This helps if we are testing the sign bit of a narrower object.
-         combine can't do this for us because it can't know whether a
-         ZERO_EXTRACT or a compare in a smaller mode exists, but we do.  */
-
-      if (! SLOW_BYTE_ACCESS
-          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-          && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
-          && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
-          && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
-          && (type = lang_hooks.types.type_for_mode (mode, 1)) != 0
-          && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
-          && (optab_handler (cmp_optab, TYPE_MODE (type))->insn_code
-              != CODE_FOR_nothing))
-        {
-          do_jump (fold_convert (type, exp), if_false_label, if_true_label);
-          break;
-        }
-      goto normal;
-
     case TRUTH_NOT_EXPR:
       do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
       break;
@@ -504,8 +431,86 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
            do_jump (cmp0, 0, if_true_label);
            do_jump (cmp1, if_false_label, if_true_label);
           }
-      }
       break;
+    }
+
+    case BIT_AND_EXPR:
+      /* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1.
+        See if the former is preferred for jump tests and restore it
+        if so.  */
+      if (integer_onep (TREE_OPERAND (exp, 1)))
+       {
+         tree exp0 = TREE_OPERAND (exp, 0);
+         rtx set_label, clr_label;
+
+         /* Strip narrowing integral type conversions.  */
+         while (CONVERT_EXPR_P (exp0)
+                && TREE_OPERAND (exp0, 0) != error_mark_node
+                && TYPE_PRECISION (TREE_TYPE (exp0))
+                   <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp0, 0))))
+           exp0 = TREE_OPERAND (exp0, 0);
+
+         /* "exp0 ^ 1" inverts the sense of the single bit test.  */
+         if (TREE_CODE (exp0) == BIT_XOR_EXPR
+             && integer_onep (TREE_OPERAND (exp0, 1)))
+           {
+             exp0 = TREE_OPERAND (exp0, 0);
+             clr_label = if_true_label;
+             set_label = if_false_label;
+           }
+         else
+           {
+             clr_label = if_false_label;
+             set_label = if_true_label;
+           }
+
+         if (TREE_CODE (exp0) == RSHIFT_EXPR)
+           {
+             tree arg = TREE_OPERAND (exp0, 0);
+             tree shift = TREE_OPERAND (exp0, 1);
+             tree argtype = TREE_TYPE (arg);
+             if (TREE_CODE (shift) == INTEGER_CST
+                 && compare_tree_int (shift, 0) >= 0
+                 && compare_tree_int (shift, HOST_BITS_PER_WIDE_INT) < 0
+                 && prefer_and_bit_test (TYPE_MODE (argtype),
+                                         TREE_INT_CST_LOW (shift)))
+               {
+                 HOST_WIDE_INT mask = (HOST_WIDE_INT) 1
+                                      << TREE_INT_CST_LOW (shift);
+                 do_jump (build2 (BIT_AND_EXPR, argtype, arg,
+                                  build_int_cst_type (argtype, mask)),
+                          clr_label, set_label);
+                 break;
+               }
+           }
+       }
+
+      /* If we are AND'ing with a small constant, do this comparison in the
+         smallest type that fits.  If the machine doesn't have comparisons
+         that small, it will be converted back to the wider comparison.
+         This helps if we are testing the sign bit of a narrower object.
+         combine can't do this for us because it can't know whether a
+         ZERO_EXTRACT or a compare in a smaller mode exists, but we do.  */
+
+      if (! SLOW_BYTE_ACCESS
+          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
+          && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
+          && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
+          && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
+          && (type = lang_hooks.types.type_for_mode (mode, 1)) != 0
+          && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
+          && (optab_handler (cmp_optab, TYPE_MODE (type))->insn_code
+              != CODE_FOR_nothing))
+        {
+          do_jump (fold_convert (type, exp), if_false_label, if_true_label);
+          break;
+        }
+
+      if (TYPE_PRECISION (TREE_TYPE (exp)) > 1
+         || TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
+       goto normal;
+
+      /* Boolean comparisons can be compiled as TRUTH_AND_EXPR.  */
 
     case TRUTH_AND_EXPR:
       /* High branch cost, expand as the bitwise AND of the conditions.
@@ -530,6 +535,7 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
        }
       break;
 
+    case BIT_IOR_EXPR:
     case TRUTH_OR_EXPR:
       /* High branch cost, expand as the bitwise OR of the conditions.
         Do the same if the RHS has side effects, because we're effectively
index 85bb2a5..84ba775 100644 (file)
@@ -1,3 +1,8 @@
+2008-09-11  Paolo Bonzini  <bonzini@gnu.org>
+
+       * gcc.dg/tree-ssa/vrp47.c: New.
+       * gcc.target/i386/andor-2.c: New.
+
 2008-09-11  Ira Rosen  <irar@il.ibm.com>
 
        PR tree-optimization/37474
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
new file mode 100644 (file)
index 0000000..a1ee927
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom" } */
+
+int h(int x, int y)
+{
+  if ((x >= 0 && x <= 1) && (y >= 0 && y <= 1))
+    return x && y;
+  else
+    return -1;
+}
+
+int g(int x, int y)
+{
+  if ((x >= 0 && x <= 1) && (y >= 0 && y <= 1))
+    return x || y;
+  else
+    return -1;
+}
+
+int f(int x)
+{
+  if (x != 0 && x != 1)
+    return -2;
+
+  else
+    return !x;
+}
+
+/* Test that x and y are never compared to 0 -- they're always known to be
+   0 or 1.  */
+/* { dg-final { scan-tree-dump-times "\[xy\]\[^ \]* !=" 0 "vrp1" } } */
+
+/* This one needs more copy propagation that only happens in dom1.  */
+/* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "dom1" } } */
+/* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "vrp1" { xfail *-*-* } } } */
+
+/* These two are fully simplified by VRP.  */
+/* { dg-final { scan-tree-dump-times "x\[^ \]* \[|\] y" 1 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "x\[^ \]* \\^ 1" 1 "vrp1" } } */
+
+/* { dg-final { cleanup-tree-dump "vrp\[0-9\]" } } */
+/* { dg-final { cleanup-tree-dump "dom\[0-9\]" } } */
diff --git a/gcc/testsuite/gcc.target/i386/andor-2.c b/gcc/testsuite/gcc.target/i386/andor-2.c
new file mode 100644 (file)
index 0000000..88118aa
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=i686" } */
+
+int h(int x, int y)
+{
+  if ((x >= 0 && x <= 1) && (y >= 0 && y <= 1))
+    return x && y;
+  else
+    return -1;
+}
+
+int g(int x, int y)
+{
+  if ((x >= 0 && x <= 1) && (y >= 0 && y <= 1))
+    return x || y;
+  else
+    return -1;
+}
+
+int f(int x, int y)
+{
+  if (x != 0 && x != 1)
+    return -2;
+
+  else
+    return !x;
+}
+
+/* { dg-final { scan-assembler-not "setne" } } */
+/* { dg-final { scan-assembler-not "sete" } } */
index 99b993d..7f3c0dd 100644 (file)
@@ -913,7 +913,7 @@ tree fold_const_aggregate_ref (tree);
 
 /* In tree-vrp.c  */
 tree vrp_evaluate_conditional (enum tree_code, tree, tree, gimple);
-void simplify_stmt_using_ranges (gimple);
+bool simplify_stmt_using_ranges (gimple_stmt_iterator *);
 
 /* In tree-ssa-dom.c  */
 extern void dump_dominator_optimization_stats (FILE *);
index 4c246e6..86bc238 100644 (file)
@@ -1098,6 +1098,7 @@ substitute_and_fold (prop_value_t *prop_value, bool use_ranges_p)
        {
           bool did_replace;
          gimple stmt = gsi_stmt (i);
+         gimple old_stmt;
          enum gimple_code code = gimple_code (stmt);
 
          /* Ignore ASSERT_EXPRs.  They are used by VRP to generate
@@ -1162,12 +1163,24 @@ substitute_and_fold (prop_value_t *prop_value, bool use_ranges_p)
              && !did_replace)
            did_replace |= replace_uses_in (stmt, prop_value);
 
-         /* If we made a replacement, fold and cleanup the statement.  */
+         /* If we made a replacement, fold the statement.  */
+
+         old_stmt = stmt;
          if (did_replace)
-           {
-             gimple old_stmt = stmt;
+           fold_stmt (&i);
+
+         /* Some statements may be simplified using ranges.  For
+            example, division may be replaced by shifts, modulo
+            replaced with bitwise and, etc.   Do this after 
+            substituting constants, folding, etc so that we're
+            presented with a fully propagated, canonicalized
+            statement.  */
+         if (use_ranges_p)
+           did_replace |= simplify_stmt_using_ranges (&i);
 
-             fold_stmt (&i);
+         /* Now cleanup.  */
+         if (did_replace)
+           {
              stmt = gsi_stmt (i);
 
               /* If we cleaned up EH information from the statement,
@@ -1207,15 +1220,6 @@ substitute_and_fold (prop_value_t *prop_value, bool use_ranges_p)
                fprintf (dump_file, "Not folded\n");
            }
 
-         /* Some statements may be simplified using ranges.  For
-            example, division may be replaced by shifts, modulo
-            replaced with bitwise and, etc.   Do this after 
-            substituting constants, folding, etc so that we're
-            presented with a fully propagated, canonicalized
-            statement.  */
-         if (use_ranges_p)
-           simplify_stmt_using_ranges (stmt);
-
          gsi_prev (&i);
        }
     }
index 46aa69d..fffa224 100644 (file)
@@ -2055,6 +2055,7 @@ extract_range_from_binary_expr (value_range_t *vr,
       && code != MIN_EXPR
       && code != MAX_EXPR
       && code != BIT_AND_EXPR
+      && code != BIT_IOR_EXPR
       && code != TRUTH_AND_EXPR
       && code != TRUTH_OR_EXPR)
     {
@@ -2415,6 +2416,45 @@ extract_range_from_binary_expr (value_range_t *vr,
          return;
        }
     }
+  else if (code == BIT_IOR_EXPR)
+    {
+      if (vr0.type == VR_RANGE
+          && vr1.type == VR_RANGE
+         && TREE_CODE (vr0.min) == INTEGER_CST
+         && TREE_CODE (vr1.min) == INTEGER_CST
+         && TREE_CODE (vr0.max) == INTEGER_CST
+         && TREE_CODE (vr1.max) == INTEGER_CST
+         && tree_int_cst_sgn (vr0.min) >= 0
+         && tree_int_cst_sgn (vr1.min) >= 0)
+       {
+         double_int vr0_max = tree_to_double_int (vr0.max);
+         double_int vr1_max = tree_to_double_int (vr1.max);
+         double_int ior_max;
+
+         /* Set all bits to the right of the most significant one to 1.
+            For example, [0, 4] | [4, 4] = [4, 7]. */
+         ior_max.low = vr0_max.low | vr1_max.low;
+         ior_max.high = vr0_max.high | vr1_max.high;
+         if (ior_max.high != 0)
+           {
+             ior_max.low = ~0u;
+             ior_max.high |= ((HOST_WIDE_INT) 1
+                              << floor_log2 (ior_max.high)) - 1;
+           }
+         else
+           ior_max.low |= ((unsigned HOST_WIDE_INT) 1u
+                           << floor_log2 (ior_max.low)) - 1;
+
+         /* Both of these endpoints are conservative.  */
+          min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
+          max = double_int_to_tree (expr_type, ior_max);
+       }
+      else
+       {
+         set_value_range_to_varying (vr);
+         return;
+       }
+    }
   else
     gcc_unreachable ();
 
@@ -6251,11 +6291,137 @@ varying:
   return SSA_PROP_VARYING;
 }
 
+/* Simplify boolean operations if the source is known
+   to be already a boolean.  */
+static bool
+simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
+{
+  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
+  tree val = NULL;
+  tree op0, op1;
+  value_range_t *vr;
+  bool sop = false;
+  bool need_conversion;
+
+  op0 = gimple_assign_rhs1 (stmt);
+  vr = get_value_range (op0);
+  if (TYPE_PRECISION (TREE_TYPE (op0)) != 1)
+    {
+      val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
+      if (!val || !integer_onep (val))
+        return false;
+
+      val = compare_range_with_value (LE_EXPR, vr, integer_one_node, &sop);
+      if (!val || !integer_onep (val))
+        return false;
+    }
+
+  if (rhs_code == TRUTH_NOT_EXPR)
+    {
+      rhs_code = NE_EXPR;
+      op1 = integer_one_node;
+    }
+
+  else
+    {
+      op1 = gimple_assign_rhs2 (stmt);
+
+      /* Reduce number of cases to handle.  */
+      if (is_gimple_min_invariant (op1))
+       {
+          /* Exclude anything that should have been already folded.  */
+         gcc_assert (rhs_code == EQ_EXPR || rhs_code == NE_EXPR
+                     || rhs_code == TRUTH_XOR_EXPR);
+         gcc_assert (integer_zerop (op1) || integer_onep (op1));
+
+         /* Limit the number of cases we have to consider.  */
+         if (rhs_code == EQ_EXPR)
+           {
+             rhs_code = NE_EXPR;
+             op1 = fold_unary (TRUTH_NOT_EXPR, TREE_TYPE (op1), op1);
+           }
+       }
+      else
+       {
+         /* Punt on A == B as there is no BIT_XNOR_EXPR.  */
+         if (rhs_code == EQ_EXPR)
+           return false;
+
+         if (TYPE_PRECISION (TREE_TYPE (op1)) != 1)
+           {
+             vr = get_value_range (op1);
+             val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
+             if (!val || !integer_onep (val))
+               return false;
+
+             val = compare_range_with_value (LE_EXPR, vr, integer_one_node, &sop);
+             if (!val || !integer_onep (val))
+               return false;
+           }
+       }
+    }
+
+  if (sop && issue_strict_overflow_warning (WARN_STRICT_OVERFLOW_MISC))
+    {
+      location_t location;
+
+      if (!gimple_has_location (stmt))
+       location = input_location;
+      else
+       location = gimple_location (stmt);
+
+      if (rhs_code == TRUTH_AND_EXPR || rhs_code == TRUTH_OR_EXPR)
+        warning_at (location, OPT_Wstrict_overflow,
+                   _("assuming signed overflow does not occur when "
+                     "simplifying && or || to & or |"));
+      else
+        warning_at (location, OPT_Wstrict_overflow,
+                   _("assuming signed overflow does not occur when "
+                     "simplifying ==, != or ! to identity or ^"));
+    }
+
+  need_conversion =
+    !useless_type_conversion_p (TREE_TYPE (gimple_assign_lhs (stmt)),
+                               TREE_TYPE (op0));
+
+  switch (rhs_code)
+    {
+    case TRUTH_AND_EXPR:
+      rhs_code = BIT_AND_EXPR;
+      break;
+    case TRUTH_OR_EXPR:
+      rhs_code = BIT_IOR_EXPR;
+      break;
+    case TRUTH_XOR_EXPR:
+    case NE_EXPR:
+      if (integer_zerop (op1))
+       {
+         gimple_assign_set_rhs_with_ops (gsi,
+                                         need_conversion ? NOP_EXPR : SSA_NAME,
+                                         op0, NULL);
+         update_stmt (gsi_stmt (*gsi));
+         return true;
+       }
+
+      rhs_code = BIT_XOR_EXPR;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (need_conversion)
+    return false;
+
+  gimple_assign_set_rhs_with_ops (gsi, rhs_code, op0, op1);
+  update_stmt (gsi_stmt (*gsi));
+  return true;
+}
+
 /* Simplify a division or modulo operator to a right shift or
    bitwise and if the first operand is unsigned or is greater
    than zero and the second operand is an exact power of two.  */
 
-static void
+static bool
 simplify_div_or_mod_using_ranges (gimple stmt)
 {
   enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
@@ -6315,14 +6481,17 @@ simplify_div_or_mod_using_ranges (gimple stmt)
        }
 
       update_stmt (stmt);
+      return true;
     }
+
+  return false;
 }
 
 /* If the operand to an ABS_EXPR is >= 0, then eliminate the
    ABS_EXPR.  If the operand is <= 0, then simplify the
    ABS_EXPR into a NEGATE_EXPR.  */
 
-static void
+static bool
 simplify_abs_using_ranges (gimple stmt)
 {
   tree val = NULL;
@@ -6377,8 +6546,11 @@ simplify_abs_using_ranges (gimple stmt)
          else
            gimple_assign_set_rhs_code (stmt, SSA_NAME);
          update_stmt (stmt);
+         return true;
        }
     }
+
+  return false;
 }
 
 /* We are comparing trees OP0 and OP1 using COND_CODE.  OP0 has
@@ -6453,7 +6625,7 @@ test_for_singularity (enum tree_code cond_code, tree op0,
    test if the range information indicates only one value can satisfy
    the original conditional.  */
 
-static void
+static bool
 simplify_cond_using_ranges (gimple stmt)
 {
   tree op0 = gimple_cond_lhs (stmt);
@@ -6494,8 +6666,8 @@ simplify_cond_using_ranges (gimple stmt)
                  print_gimple_stmt (dump_file, stmt, 0, 0);
                  fprintf (dump_file, "\n");
                }
-             return;
 
+             return true;
            }
 
          /* Try again after inverting the condition.  We only deal
@@ -6524,17 +6696,19 @@ simplify_cond_using_ranges (gimple stmt)
                  print_gimple_stmt (dump_file, stmt, 0, 0);
                  fprintf (dump_file, "\n");
                }
-             return;
 
+             return true;
            }
        }
     }
+
+  return false;
 }
 
 /* Simplify a switch statement using the value range of the switch
    argument.  */
 
-static void
+static bool
 simplify_switch_using_ranges (gimple stmt)
 {
   tree op = gimple_switch_index (stmt);
@@ -6547,14 +6721,14 @@ simplify_switch_using_ranges (gimple stmt)
   switch_update su;
 
   if (TREE_CODE (op) != SSA_NAME)
-    return;
+    return false;
 
   vr = get_value_range (op);
 
   /* We can only handle integer ranges.  */
   if (vr->type != VR_RANGE
       || symbolic_range_p (vr))
-    return;
+    return false;
 
   /* Find case label for min/max of the value range.  */
   n = gimple_switch_num_labels (stmt);
@@ -6564,7 +6738,7 @@ simplify_switch_using_ranges (gimple stmt)
   if (i == 1
       && j == n - 1
       && take_default)
-    return;
+    return false;
 
   /* Build a new vector of taken case labels.  */
   vec2 = make_tree_vec (j - i + 1 + (int)take_default);
@@ -6605,35 +6779,62 @@ simplify_switch_using_ranges (gimple stmt)
   su.stmt = stmt;
   su.vec = vec2;
   VEC_safe_push (switch_update, heap, to_update_switch_stmts, &su);
+  return false;
 }
 
 /* Simplify STMT using ranges if possible.  */
 
-void
-simplify_stmt_using_ranges (gimple stmt)
+bool
+simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
 {
+  gimple stmt = gsi_stmt (*gsi);
   if (is_gimple_assign (stmt))
     {
       enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
 
+      switch (rhs_code)
+       {
+       case EQ_EXPR:
+       case NE_EXPR:
+       case TRUTH_NOT_EXPR:
+       case TRUTH_AND_EXPR:
+       case TRUTH_OR_EXPR:
+        case TRUTH_XOR_EXPR:
+          /* Transform EQ_EXPR, NE_EXPR, TRUTH_NOT_EXPR into BIT_XOR_EXPR
+            or identity if the RHS is zero or one, and the LHS are known
+            to be boolean values.  Transform all TRUTH_*_EXPR into
+             BIT_*_EXPR if both arguments are known to be boolean values.  */
+         if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
+           return simplify_truth_ops_using_ranges (gsi, stmt);
+         break;
+
       /* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR
         and BIT_AND_EXPR respectively if the first operand is greater
         than zero and the second operand is an exact power of two.  */
-      if ((rhs_code == TRUNC_DIV_EXPR || rhs_code == TRUNC_MOD_EXPR)
-         && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))
-         && integer_pow2p (gimple_assign_rhs2 (stmt)))
-       simplify_div_or_mod_using_ranges (stmt);
+       case TRUNC_DIV_EXPR:
+       case TRUNC_MOD_EXPR:
+         if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))
+             && integer_pow2p (gimple_assign_rhs2 (stmt)))
+           return simplify_div_or_mod_using_ranges (stmt);
+         break;
 
       /* Transform ABS (X) into X or -X as appropriate.  */
-      if (rhs_code == ABS_EXPR
-         && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
-         && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
-       simplify_abs_using_ranges (stmt);
+       case ABS_EXPR:
+         if (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+             && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
+           return simplify_abs_using_ranges (stmt);
+         break;
+
+       default:
+         break;
+       }
     }
   else if (gimple_code (stmt) == GIMPLE_COND)
-    simplify_cond_using_ranges (stmt);
+    return simplify_cond_using_ranges (stmt);
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
-    simplify_switch_using_ranges (stmt);
+    return simplify_switch_using_ranges (stmt);
+
+  return false;
 }
 
 /* Stack of dest,src equivalency pairs that need to be restored after