From 14d6281388bad11de8c328be7ea825b184fc7efe Mon Sep 17 00:00:00 2001
From: Jeff Law <law@redhat.com>
Date: Mon, 28 Aug 2017 23:03:36 -0600
Subject: [PATCH] tree-ssa-dom.c (edge_info::record_simple_equiv): Call
 derive_equivalences.

	* 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
---
 gcc/ChangeLog                                 |   6 +
 gcc/testsuite/ChangeLog                       |  12 +
 gcc/testsuite/gcc.dg/torture/pr57214.c        |   2 +-
 .../gcc.dg/tree-ssa/ssa-dom-thread-11.c       |  18 +
 .../gcc.dg/tree-ssa/ssa-dom-thread-12.c       |  36 ++
 .../gcc.dg/tree-ssa/ssa-dom-thread-13.c       |  46 +++
 .../gcc.dg/tree-ssa/ssa-dom-thread-14.c       |  40 +++
 .../gcc.dg/tree-ssa/ssa-dom-thread-15.c       |  67 ++++
 .../gcc.dg/tree-ssa/ssa-dom-thread-16.c       |  17 +
 .../gcc.dg/tree-ssa/ssa-dom-thread-17.c       |  44 +++
 gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c   |   4 +-
 gcc/tree-ssa-dom.c                            | 319 +++++++++++++-----
 12 files changed, 516 insertions(+), 95 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 258d4242f301..9a60a80b7466 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index cfe90904f6d6..0ffc4f9a70fb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/gcc.dg/torture/pr57214.c b/gcc/testsuite/gcc.dg/torture/pr57214.c
index d51067d95d8f..c697f84514ea 100644
--- a/gcc/testsuite/gcc.dg/torture/pr57214.c
+++ b/gcc/testsuite/gcc.dg/torture/pr57214.c
@@ -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
index 000000000000..f42d64bed710
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c
@@ -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
index 000000000000..63bd12a06a41
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c
@@ -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
index 000000000000..209c40d4c95b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c
@@ -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
index 000000000000..2d97f86fa28e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c
@@ -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
index 000000000000..df6a9b32eb1b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c
@@ -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
index 000000000000..e2e0d20fb9fb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c
@@ -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
index 000000000000..2c5c5a6cf941
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c
@@ -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"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
index 1b94c336806a..610c8d60ebee 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
@@ -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)
 {
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index 403485b3c553..d91766e902e4 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -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
-- 
GitLab