tree-ssa-dom.c (edge_info::record_simple_equiv): Call derive_equivalences.
authorJeff Law <law@redhat.com>
Tue, 29 Aug 2017 05:03:36 +0000 (23:03 -0600)
committerJeff Law <law@gcc.gnu.org>
Tue, 29 Aug 2017 05:03:36 +0000 (23:03 -0600)
* tree-ssa-dom.c (edge_info::record_simple_equiv): Call
derive_equivalences.
(derive_equivalences_from_bit_ior, record_temporary_equivalences):
Code moved into....
(edge_info::derive_equivalences): New private member function

* gcc.dg/torture/pr57214.c: Fix type of loop counter.
* gcc.dg/tree-ssa/ssa-sink-16.c: Disable DOM.
* gcc.dg/tree-ssa/ssa-dom-thread-11.c: New test.
* gcc.dg/tree-ssa/ssa-dom-thread-12.c: New test.
* gcc.dg/tree-ssa/ssa-dom-thread-13.c: New test.
* gcc.dg/tree-ssa/ssa-dom-thread-14.c: New test.
* gcc.dg/tree-ssa/ssa-dom-thread-15.c: New test.
* gcc.dg/tree-ssa/ssa-dom-thread-16.c: New test.
* gcc.dg/tree-ssa/ssa-dom-thread-17.c: New test.

From-SVN: r251397

12 files changed:
gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/pr57214.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
gcc/tree-ssa-dom.c

index 258d4242f301523a5fff7fb57011d7c4477017ca..9a60a80b7466b635e77ae4c881f21c14e7e63748 100644 (file)
@@ -1,5 +1,11 @@
 2017-08-28  Jeff Law  <law@redhat.com>
 
+       * tree-ssa-dom.c (edge_info::record_simple_equiv): Call
+       derive_equivalences.
+       (derive_equivalences_from_bit_ior, record_temporary_equivalences):
+       Code moved into....
+       (edge_info::derive_equivalences): New private member function
+
        * tree-ssa-dom.c (class edge_info): Changed from a struct
        to a class.  Add ctor/dtor, methods and data members.
        (edge_info::edge_info): Renamed from allocate_edge_info.
index cfe90904f6d649e00b3c521243bb3cdc65ec16ae..0ffc4f9a70fb2d516e88e2bf9ac207ffc6ba370c 100644 (file)
@@ -1,3 +1,15 @@
+2017-08-28  Jeff Law  <law@redhat.com>
+
+       * gcc.dg/torture/pr57214.c: Fix type of loop counter.
+       * gcc.dg/tree-ssa/ssa-sink-16.c: Disable DOM.
+       * gcc.dg/tree-ssa/ssa-dom-thread-11.c: New test.
+       * gcc.dg/tree-ssa/ssa-dom-thread-12.c: New test.
+       * gcc.dg/tree-ssa/ssa-dom-thread-13.c: New test.
+       * gcc.dg/tree-ssa/ssa-dom-thread-14.c: New test.
+       * gcc.dg/tree-ssa/ssa-dom-thread-15.c: New test.
+       * gcc.dg/tree-ssa/ssa-dom-thread-16.c: New test.
+       * gcc.dg/tree-ssa/ssa-dom-thread-17.c: New test.
+
 2017-08-28  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/81770
index d51067d95d8fae03a32862c9ca9b2179eda2e283..c697f84514ea95ec6dbf8434840788323c7f4e89 100644 (file)
@@ -15,7 +15,7 @@ bar (_Bool b)
       b = 1;
       baz ();
       x = 0;
-      int i;
+      unsigned int i;
       while (buf[i] && i)
        i++;
       foo ();
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c
new file mode 100644 (file)
index 0000000..f42d64b
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile { target { ! logical_op_short_circuit  } } } */
+/* { dg-options "-O2 -fdump-tree-dom2-details" } */
+
+static int *bb_ticks;
+extern void frob (void);
+void
+mark_target_live_regs (int b, int block, int bb_tick)
+{
+  if (b == block && b != -1 && bb_tick == bb_ticks[b])
+      return;
+  if (b != -1)
+    frob ();
+}
+
+/* When the first two conditionals in the first IF are true, but
+   the third conditional is false, then there's a jump threading
+   opportunity to bypass the second IF statement.  */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c
new file mode 100644 (file)
index 0000000..63bd12a
--- /dev/null
@@ -0,0 +1,36 @@
+/* { dg-do compile } */ 
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+typedef long unsigned int size_t;
+union tree_node;
+typedef union tree_node *tree;
+typedef union gimple_statement_d *gimple;
+typedef const union gimple_statement_d *const_gimple;
+union gimple_statement_d
+{
+  unsigned num_ops;
+  tree exp;
+};
+
+unsigned int x;
+static inline tree
+gimple_op (const_gimple gs, unsigned i)
+{
+  if (!(i < gs->num_ops))
+    abort ();
+  return gs->exp;
+}
+
+unsigned char
+scan_function (gimple stmt)
+{
+  unsigned i;
+  for (i = 0; i < stmt->num_ops - 3 ; i++)
+    gimple_call_arg (stmt, i);
+  gimple_op (stmt, 1);
+}
+
+/* The test which bypasses the loop is simplified prior to DOM to check
+   that stmt->num_ops - 3 != 0.  When that test is false, we can derive
+   a value for stmt->num_ops.  That in turn allows us to thread the jump
+   for the conditional at the start of the call to gimple_op.  */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c
new file mode 100644 (file)
index 0000000..209c40d
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do compile } */ 
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+
+union tree_node;
+typedef union tree_node *tree;
+extern unsigned char tree_contains_struct[0xdead][64];
+struct tree_base
+{
+  int code:16;
+};
+struct tree_typed
+{
+  tree type;
+};
+struct tree_type_common
+{
+  tree main_variant;
+};
+extern tree build_target_option_node (void);
+union tree_node
+{
+  struct tree_base base;
+  struct tree_typed typed;
+  struct tree_type_common type_common;
+};
+tree
+convert (tree type, tree expr)
+{
+  tree e = expr;
+  int code = (type)->base.code;
+  const char *invalid_conv_diag;
+  tree ret;
+  if (tree_contains_struct[expr->base.code][(42)] != 1)
+    abort ();
+  if (type->type_common.main_variant == expr->typed.type->type_common.main_variant
+      && (expr->typed.type->base.code != 123
+         || e->base.code == 456))
+    return arf ();
+  if (expr->typed.type->base.code == 42)
+    error ("void value not ignored as it ought to be");
+}
+
+/* When the *->base.code tests in the second IF statement are false, we
+   know that expr->typed.base->base.code has the value 123.  That allows
+   us to thread the test for the final IF statement on that path.  */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c
new file mode 100644 (file)
index 0000000..2d97f86
--- /dev/null
@@ -0,0 +1,40 @@
+/* { dg-do compile { target { ! logical_op_short_circuit  } } } */
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+
+enum optab_methods
+{
+  OPTAB_DIRECT,
+  OPTAB_LIB,
+  OPTAB_WIDEN,
+  OPTAB_LIB_WIDEN,
+  OPTAB_MUST_WIDEN
+};
+struct optab_d { };
+typedef struct optab_d *optab;
+void
+expand_shift_1 (int code, int unsignedp, int rotate,
+               optab lshift_optab, optab rshift_arith_optab)
+{
+  int left = (code == 42 || code == 0xde);
+  int attempt;
+  enum optab_methods methods;
+  if (attempt == 0)
+    methods = OPTAB_DIRECT;
+  else if (attempt == 1)
+    methods = OPTAB_WIDEN;
+  if ((!unsignedp || (!left && methods == OPTAB_WIDEN)))
+    {
+      enum optab_methods methods1 = methods;
+      if (unsignedp)
+       methods1 = OPTAB_MUST_WIDEN;
+      expand_binop (left ? lshift_optab : rshift_arith_optab,
+                          unsignedp, methods1);
+    }
+}
+
+/* When UNSIGNEDP is true, LEFT is false and METHOD == OPTAB_WIDEN
+   we will enter the TRUE arm of the conditional and we can thread
+   the test to compute the first first argument of the expand_binop
+   call if we look backwards through the boolean logicals.  */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c
new file mode 100644 (file)
index 0000000..df6a9b3
--- /dev/null
@@ -0,0 +1,67 @@
+/* { dg-do compile } */ 
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+struct rtx_def;
+typedef struct rtx_def *rtx;
+struct machine_frame_state
+{
+  rtx cfa_reg;
+  long sp_offset;
+};
+struct machine_function {
+  struct machine_frame_state fs;
+};
+enum global_rtl_index
+{
+  GR_PC,
+  GR_CC0,
+  GR_RETURN,
+  GR_SIMPLE_RETURN,
+  GR_STACK_POINTER,
+  GR_FRAME_POINTER,
+  GR_HARD_FRAME_POINTER,
+  GR_ARG_POINTER,
+  GR_VIRTUAL_INCOMING_ARGS,
+  GR_VIRTUAL_STACK_ARGS,
+  GR_VIRTUAL_STACK_DYNAMIC,
+  GR_VIRTUAL_OUTGOING_ARGS,
+  GR_VIRTUAL_CFA,
+  GR_VIRTUAL_PREFERRED_STACK_BOUNDARY,
+  GR_MAX
+};
+struct target_rtl {
+  rtx x_global_rtl[GR_MAX];
+};
+extern struct target_rtl default_target_rtl;
+struct function {
+  struct machine_function * machine;
+};
+extern struct function *cfun;
+struct ix86_frame
+{
+  long stack_pointer_offset;
+};
+void
+ix86_expand_prologue (void)
+{
+  struct machine_function *m = (cfun + 0)->machine;
+  struct ix86_frame frame;
+  long allocate;
+  allocate = frame.stack_pointer_offset - m->fs.sp_offset;
+  if (allocate == 0)
+    ;
+  else if (!ix86_target_stack_probe ()) 
+    {
+      pro_epilogue_adjust_stack ((((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]), (((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]),
+            gen_rtx_CONST_INT ((-allocate)), -1,
+            m->fs.cfa_reg == (((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]));
+    }
+  ((void)(!(m->fs.sp_offset == frame.stack_pointer_offset) ? fancy_abort ("../../gcc-4.7.3/gcc/config/i386/i386.c", 10435, __FUNCTION__), 0 : 0));
+}
+
+/* In the case where ALLOCATE is zero, we know that sp_offset and
+   stack_poitner_offset within their respective structures are the
+   same.  That allows us to thread the jump from the true arm of the
+   first IF conditional around the test controlling the call to
+   fancy_abort.  */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c
new file mode 100644 (file)
index 0000000..e2e0d20
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile { target { ! logical_op_short_circuit  } } } */
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+unsigned char
+validate_subreg (unsigned int offset, unsigned int isize, unsigned int osize, int zz, int qq)
+{
+if (osize >= (((zz & (1L << 2)) != 0) ? 8 : 4) && isize >= osize)
+    ;
+  else if (qq == 99)
+ return 0;
+  if (osize > isize)
+    return offset == 0;
+  return 1;
+}
+/* When we test isize >= osize in the first IF conditional and it is
+   false and qq != 99, then we can thread the osize > isize test of
+   the second conditional.  */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c
new file mode 100644 (file)
index 0000000..2c5c5a6
--- /dev/null
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dom2 -w" } */
+
+struct rtx_def;
+typedef struct rtx_def *rtx;
+struct reload
+{
+  rtx in;
+  rtx reg_rtx;
+};
+extern struct reload rld[(2 * 30 * (2 + 1))];
+static rtx find_dummy_reload (rtx);
+extern int frob ();
+extern int arf ();
+int
+push_reload (rtx in, rtx out
+)
+{
+  int i;
+  if (out != 0 && in != out)
+    {
+      rld[i].reg_rtx = find_dummy_reload (out);
+      if (rld[i].reg_rtx == out)
+        rld[i].in = out;
+    }
+}
+rtx
+find_dummy_reload (rtx real_out)
+{
+   unsigned int nwords = frob ();
+   unsigned int regno = frob ();
+   unsigned int i;
+   for (i = 0; i < nwords; i++)
+     if (arf ())
+       break;
+   if (i == nwords)
+     return real_out;
+  return 0;
+}
+
+/* In the case where the call to find_dummy_reload returns 0,
+   the final test in push_reload will never be true and it will
+   be eliminated.  */
+/* { dg-final { scan-tree-dump-not "out_\[^\n\r]+ == 0" "dom2"} } */
index 1b94c336806a057bc57a63390309fa11c78a26ff..610c8d60ebeec421ab1e884b9b747551c8848127 100644 (file)
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
-/* Note PRE rotates the loop and blocks the sinking opportunity.  */
-/* { dg-options "-O2 -fno-tree-pre -fdump-tree-sink -fdump-tree-optimized" } */
+/* Note PRE and DOM jump threading rotate the loop and blocks the sinking opportunity.  */
+/* { dg-options "-O2 -fno-tree-pre -fno-tree-dominator-opts -fdump-tree-sink -fdump-tree-optimized" } */
 
 int f(int n)
 {
index 403485b3c553bb00b20a06155b313d6ce86b9f93..d91766e902e4846383ab7e843a13ba5adc64e969 100644 (file)
@@ -136,19 +136,240 @@ edge_info::edge_info (edge e)
 }
 
 /* Destructor just needs to release the vectors.  */
+
 edge_info::~edge_info (void)
 {
   this->cond_equivalences.release ();
   this->simple_equivalences.release ();
 }
 
-/* Record that LHS is known to be equal to RHS at runtime when the
-   edge associated with THIS is traversed.  */
+/* NAME is known to have the value VALUE, which must be a constant.
+
+   Walk through its use-def chain to see if there are other equivalences
+   we might be able to derive.
+
+   RECURSION_LIMIT controls how far back we recurse through the use-def
+   chains.  */
+
+void
+edge_info::derive_equivalences (tree name, tree value, int recursion_limit)
+{
+  if (TREE_CODE (name) != SSA_NAME || TREE_CODE (value) != INTEGER_CST)
+    return;
+
+  /* This records the equivalence for the toplevel object.  Do
+     this before checking the recursion limit.  */
+  simple_equivalences.safe_push (equiv_pair (name, value));
+
+  /* Limit how far up the use-def chains we are willing to walk.  */
+  if (recursion_limit == 0)
+    return;
+
+  /* We can walk up the use-def chains to potentially find more
+     equivalences.  */
+  gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+  if (is_gimple_assign (def_stmt))
+    {
+      /* We know the result of DEF_STMT was zero.  See if that allows
+        us to deduce anything about the SSA_NAMEs used on the RHS.  */
+      enum tree_code code = gimple_assign_rhs_code (def_stmt);
+      switch (code)
+       {
+       case BIT_IOR_EXPR:
+         if (integer_zerop (value))
+           {
+             tree rhs1 = gimple_assign_rhs1 (def_stmt);
+             tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+             value = build_zero_cst (TREE_TYPE (rhs1));
+             derive_equivalences (rhs1, value, recursion_limit - 1);
+             value = build_zero_cst (TREE_TYPE (rhs2));
+             derive_equivalences (rhs2, value, recursion_limit - 1);
+           }
+         break;
+
+      /* We know the result of DEF_STMT was one.  See if that allows
+        us to deduce anything about the SSA_NAMEs used on the RHS.  */
+       case BIT_AND_EXPR:
+         if (!integer_zerop (value))
+           {
+             tree rhs1 = gimple_assign_rhs1 (def_stmt);
+             tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+             /* If either operand has a boolean range, then we
+                know its value must be one, otherwise we just know it
+                is nonzero.  The former is clearly useful, I haven't
+                seen cases where the latter is helpful yet.  */
+             if (TREE_CODE (rhs1) == SSA_NAME)
+               {
+                 if (ssa_name_has_boolean_range (rhs1))
+                   {
+                     value = build_one_cst (TREE_TYPE (rhs1));
+                     derive_equivalences (rhs1, value, recursion_limit - 1);
+                   }
+               }
+             if (TREE_CODE (rhs2) == SSA_NAME)
+               {
+                 if (ssa_name_has_boolean_range (rhs2))
+                   {
+                     value = build_one_cst (TREE_TYPE (rhs2));
+                     derive_equivalences (rhs2, value, recursion_limit - 1);
+                   }
+               }
+           }
+         break;
+
+       /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
+          set via a widening type conversion, then we may be able to record
+          additional equivalences.  */
+       case NOP_EXPR:
+       case CONVERT_EXPR:
+         {
+           tree rhs = gimple_assign_rhs1 (def_stmt);
+           tree rhs_type = TREE_TYPE (rhs);
+           if (INTEGRAL_TYPE_P (rhs_type)
+               && (TYPE_PRECISION (TREE_TYPE (name))
+                   >= TYPE_PRECISION (rhs_type))
+               && int_fits_type_p (value, rhs_type))
+             derive_equivalences (rhs,
+                                  fold_convert (rhs_type, value),
+                                  recursion_limit - 1);
+           break;
+         }
+
+       /* We can invert the operation of these codes trivially if
+          one of the RHS operands is a constant to produce a known
+          value for the other RHS operand.  */
+       case POINTER_PLUS_EXPR:
+       case PLUS_EXPR:
+         {
+           tree rhs1 = gimple_assign_rhs1 (def_stmt);
+           tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+           /* If either argument is a constant, then we can compute
+              a constant value for the nonconstant argument.  */
+           if (TREE_CODE (rhs1) == INTEGER_CST
+               && TREE_CODE (rhs2) == SSA_NAME)
+             derive_equivalences (rhs2,
+                                  fold_binary (MINUS_EXPR, TREE_TYPE (rhs1),
+                                               value, rhs1),
+                                  recursion_limit - 1);
+           else if (TREE_CODE (rhs2) == INTEGER_CST
+                    && TREE_CODE (rhs1) == SSA_NAME)
+             derive_equivalences (rhs1,
+                                  fold_binary (MINUS_EXPR, TREE_TYPE (rhs1),
+                                               value, rhs2),
+                                  recursion_limit - 1);
+           break;
+         }
+
+       /* If one of the operands is a constant, then we can compute
+          the value of the other operand.  If both operands are
+          SSA_NAMEs, then they must be equal if the result is zero.  */
+       case MINUS_EXPR:
+         {
+           tree rhs1 = gimple_assign_rhs1 (def_stmt);
+           tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+           /* If either argument is a constant, then we can compute
+              a constant value for the nonconstant argument.  */
+           if (TREE_CODE (rhs1) == INTEGER_CST
+               && TREE_CODE (rhs2) == SSA_NAME)
+             derive_equivalences (rhs2,
+                                  fold_binary (MINUS_EXPR, TREE_TYPE (rhs1),
+                                               rhs1, value),
+                                  recursion_limit - 1);
+           else if (TREE_CODE (rhs2) == INTEGER_CST
+                    && TREE_CODE (rhs1) == SSA_NAME)
+             derive_equivalences (rhs1,
+                                  fold_binary (PLUS_EXPR, TREE_TYPE (rhs1),
+                                               value, rhs2),
+                                  recursion_limit - 1);
+           else if (integer_zerop (value))
+             {
+               tree cond = build2 (EQ_EXPR, boolean_type_node,
+                                   gimple_assign_rhs1 (def_stmt),
+                                   gimple_assign_rhs2 (def_stmt));
+               tree inverted = invert_truthvalue (cond);
+               record_conditions (&this->cond_equivalences, cond, inverted);
+             }
+           break;
+         }
+
+
+       case EQ_EXPR:
+       case NE_EXPR:
+         {
+           if ((code == EQ_EXPR && integer_onep (value))
+               || (code == NE_EXPR && integer_zerop (value)))
+             {
+               tree rhs1 = gimple_assign_rhs1 (def_stmt);
+               tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+               /* If either argument is a constant, then record the
+                  other argument as being the same as that constant.
+
+                  If neither operand is a constant, then we have a
+                  conditional name == name equivalence.  */
+               if (TREE_CODE (rhs1) == INTEGER_CST)
+                 derive_equivalences (rhs2, rhs1, recursion_limit - 1);
+               else if (TREE_CODE (rhs2) == INTEGER_CST)
+                 derive_equivalences (rhs1, rhs2, recursion_limit - 1);
+             }
+           else
+             {
+               tree cond = build2 (code, boolean_type_node,
+                                   gimple_assign_rhs1 (def_stmt),
+                                   gimple_assign_rhs2 (def_stmt));
+               tree inverted = invert_truthvalue (cond);
+               if (integer_zerop (value))
+                 std::swap (cond, inverted);
+               record_conditions (&this->cond_equivalences, cond, inverted);
+             }
+           break;
+         }
+
+       /* For BIT_NOT and NEGATE, we can just apply the operation to the
+          VALUE to get the new equivalence.  It will always be a constant
+          so we can recurse.  */
+       case BIT_NOT_EXPR:
+       case NEGATE_EXPR:
+         {
+           tree rhs = gimple_assign_rhs1 (def_stmt);
+           tree res = fold_build1 (code, TREE_TYPE (rhs), value);
+           derive_equivalences (rhs, res, recursion_limit - 1);
+           break;
+         }
+
+       default:
+         {
+           if (TREE_CODE_CLASS (code) == tcc_comparison)
+             {
+               tree cond = build2 (code, boolean_type_node,
+                                   gimple_assign_rhs1 (def_stmt),
+                                   gimple_assign_rhs2 (def_stmt));
+               tree inverted = invert_truthvalue (cond);
+               if (integer_zerop (value))
+                 std::swap (cond, inverted);
+               record_conditions (&this->cond_equivalences, cond, inverted);
+               break;
+             }
+           break;
+         }
+       }
+    }
+}
 
 void
 edge_info::record_simple_equiv (tree lhs, tree rhs)
 {
-  simple_equivalences.safe_push (equiv_pair (lhs, rhs));
+  /* If the RHS is a constant, then we may be able to derive
+     further equivalences.  Else just record the name = name
+     equivalence.  */
+  if (TREE_CODE (rhs) == INTEGER_CST)
+    derive_equivalences (lhs, rhs, 4);
+  else
+    simple_equivalences.safe_push (equiv_pair (lhs, rhs));
 }
 
 /* Free the edge_info data attached to E, if it exists.  */
@@ -702,42 +923,6 @@ back_propagate_equivalences (tree lhs, edge e,
     BITMAP_FREE (domby);
 }
 
-/* Record NAME has the value zero and if NAME was set from a BIT_IOR_EXPR
-   recurse into both operands recording their values as zero too. 
-   RECURSION_DEPTH controls how far back we recurse through the operands
-   of the BIT_IOR_EXPR.  */
-
-static void
-derive_equivalences_from_bit_ior (tree name,
-                                 const_and_copies *const_and_copies,
-                                 int recursion_limit)
-{
-  if (recursion_limit == 0)
-    return;
-
-  if (TREE_CODE (name) == SSA_NAME)
-    {
-      tree value = build_zero_cst (TREE_TYPE (name));
-
-      /* This records the equivalence for the toplevel object.  */
-      record_equality (name, value, const_and_copies);
-
-      /* And we can recurse into each operand to potentially find more
-        equivalences.  */
-      gimple *def_stmt = SSA_NAME_DEF_STMT (name);
-      if (is_gimple_assign (def_stmt)
-         && gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR)
-       {
-         derive_equivalences_from_bit_ior (gimple_assign_rhs1 (def_stmt),
-                                           const_and_copies,
-                                           recursion_limit - 1);
-         derive_equivalences_from_bit_ior (gimple_assign_rhs2 (def_stmt),
-                                           const_and_copies,
-                                           recursion_limit - 1);
-       }
-    }
-}
-
 /* Record into CONST_AND_COPIES and AVAIL_EXPRS_STACK any equivalences implied
    by traversing edge E (which are cached in E->aux).
 
@@ -758,28 +943,7 @@ record_temporary_equivalences (edge e,
       /* If we have 0 = COND or 1 = COND equivalences, record them
         into our expression hash tables.  */
       for (i = 0; edge_info->cond_equivalences.iterate (i, &eq); ++i)
-       {
-         avail_exprs_stack->record_cond (eq);
-
-         /* If the condition is testing that X == 0 is true or X != 0 is false
-            and X is set from a BIT_IOR_EXPR, then we can record equivalences
-            for the operands of the BIT_IOR_EXPR (and recurse on those).  */
-         tree op0 = eq->cond.ops.binary.opnd0;
-         tree op1 = eq->cond.ops.binary.opnd1;
-         if (TREE_CODE (op0) == SSA_NAME && integer_zerop (op1))
-           {
-             enum tree_code code = eq->cond.ops.binary.op;
-             if ((code == EQ_EXPR && eq->value == boolean_true_node)
-                 || (code == NE_EXPR && eq->value == boolean_false_node))
-               derive_equivalences_from_bit_ior (op0, const_and_copies, 4);
-
-             /* TODO: We could handle BIT_AND_EXPR in a similar fashion
-                recording that the operands have a nonzero value.  */
-
-             /* TODO: We can handle more cases here, particularly when OP0 is
-                known to have a boolean range.  */
-           }
-       }
+       avail_exprs_stack->record_cond (eq);
 
       edge_info::equiv_pair *seq;
       for (i = 0; edge_info->simple_equivalences.iterate (i, &seq); ++i)
@@ -806,42 +970,13 @@ record_temporary_equivalences (edge e,
              int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights);
 
              if (rhs_cost > lhs_cost)
-               record_equality (rhs, lhs, const_and_copies);
+               record_equality (rhs, lhs, const_and_copies);
              else if (rhs_cost < lhs_cost)
-               record_equality (lhs, rhs, const_and_copies);
+               record_equality (lhs, rhs, const_and_copies);
            }
          else
            record_equality (lhs, rhs, const_and_copies);
 
-         /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
-            set via a widening type conversion, then we may be able to record
-            additional equivalences.  */
-         if (TREE_CODE (rhs) == INTEGER_CST)
-           {
-             gimple *defstmt = SSA_NAME_DEF_STMT (lhs);
-
-             if (defstmt
-                 && is_gimple_assign (defstmt)
-                 && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (defstmt)))
-               {
-                 tree old_rhs = gimple_assign_rhs1 (defstmt);
-
-                 /* If the conversion widens the original value and
-                    the constant is in the range of the type of OLD_RHS,
-                    then convert the constant and record the equivalence.
-
-                    Note that int_fits_type_p does not check the precision
-                    if the upper and lower bounds are OK.  */
-                 if (INTEGRAL_TYPE_P (TREE_TYPE (old_rhs))
-                     && (TYPE_PRECISION (TREE_TYPE (lhs))
-                         > TYPE_PRECISION (TREE_TYPE (old_rhs)))
-                     && int_fits_type_p (rhs, TREE_TYPE (old_rhs)))
-                   {
-                     tree newval = fold_convert (TREE_TYPE (old_rhs), rhs);
-                     record_equality (old_rhs, newval, const_and_copies);
-                   }
-               }
-           }
 
          /* Any equivalence found for LHS may result in additional
             equivalences for other uses of LHS that we have already