From 95535d44db4e714821b1ec03490405410a63e80b Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 30 Jul 2019 11:11:26 -0400
Subject: [PATCH 41/96] FIXME: introduce
 region_model::add_any_constraints_from_ssa_def_stmt

---
 gcc/analyzer/region-model.cc | 178 +++++++++++++++++++++++++------------------
 gcc/analyzer/region-model.h  |   5 ++
 2 files changed, 107 insertions(+), 76 deletions(-)

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 239a112..9681660 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -3669,92 +3669,118 @@ region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
   /* Store the constraint.  */
   m_constraints->add_constraint (lhs_sid, op, rhs_sid);
 
-  /* Handle optimized && and || conditionals.
-     If we have an SSA_NAME for a boolean compared against 0,
-     look at anything implied by the def stmt.  */
-  if (TREE_CODE (lhs) == SSA_NAME
-      && rhs == boolean_false_node)
+  add_any_constraints_from_ssa_def_stmt (lhs, op, rhs, ctxt);
+
+  /* Notify the context, if any.  This exists so that the state machines
+     in a program_state can be notified about the condition, and so can
+     set sm-state for e.g. unchecked->checked, both for cfg-edges, and
+     when synthesizing constraints as above.  */
+  if (ctxt)
+    ctxt->on_condition (lhs, op, rhs);
+
+  return true;
+}
+
+/* Subroutine of region_model::add_constraint for handling optimized
+   && and || conditionals.
+
+   If we have an SSA_NAME for a boolean compared against 0,
+   look at anything implied by the def stmt and call add_constraint
+   for it (which could recurse).
+
+   For example, if we have
+      _1 = p_6 == 0B;
+      _2 = p_8 == 0B
+      _3 = _1 | _2
+    and add the constraint
+      (_3 == 0),
+    then the def stmt for _3 implies that _1 and _2 are both false,
+    and hence we can add the constraints:
+      p_6 != 0B
+      p_8 != 0B.  */
+
+void
+region_model::add_any_constraints_from_ssa_def_stmt (tree lhs,
+						     enum tree_code op,
+						     tree rhs,
+						     region_model_context *ctxt)
+{
+  if (TREE_CODE (lhs) != SSA_NAME)
+    return;
+
+  if (rhs != boolean_false_node)
+    return;
+
+  gimple *def_stmt = SSA_NAME_DEF_STMT (lhs);
+  if (gassign *assign = dyn_cast<gassign *> (def_stmt))
     {
-      gimple *def_stmt = SSA_NAME_DEF_STMT (lhs);
-      if (gassign *assign = dyn_cast<gassign *> (def_stmt))
+      enum tree_code rhs_code = gimple_assign_rhs_code (assign);
+      /* If we have "LHS != false", i.e. LHS is true... */
+      if (op == NE_EXPR)
 	{
-	  enum tree_code rhs_code = gimple_assign_rhs_code (assign);
-	  /* If we have "LHS != false", i.e. LHS is true... */
-	  if (op == NE_EXPR)
+	  switch (rhs_code)
 	    {
-	      switch (rhs_code)
-		{
-		default:
-		  break;
-		case BIT_AND_EXPR:
-		  {
-		    /* ...and "LHS == (rhs1 & rhs2) i.e. "(rhs1 & rhs2)" is true
-		       then both rhs1 and rhs2 must be true.  */
-		    tree rhs1 = gimple_assign_rhs1 (assign);
-		    tree rhs2 = gimple_assign_rhs2 (assign);
-		    add_constraint (rhs1, NE_EXPR, boolean_false_node, ctxt);
-		    add_constraint (rhs2, NE_EXPR, boolean_false_node, ctxt);
-		  }
-		  break;
+	    default:
+	      break;
+	    case BIT_AND_EXPR:
+	      {
+		/* ...and "LHS == (rhs1 & rhs2) i.e. "(rhs1 & rhs2)" is true
+		   then both rhs1 and rhs2 must be true.  */
+		tree rhs1 = gimple_assign_rhs1 (assign);
+		tree rhs2 = gimple_assign_rhs2 (assign);
+		add_constraint (rhs1, NE_EXPR, boolean_false_node, ctxt);
+		add_constraint (rhs2, NE_EXPR, boolean_false_node, ctxt);
+	      }
+	      break;
 
-		case EQ_EXPR:
-		case NE_EXPR:
-		  {
-		    /* ...and "LHS == (rhs1 OP rhs2)"
-		       then rhs1 OP rhs2 must be true.  */
-		    tree rhs1 = gimple_assign_rhs1 (assign);
-		    tree rhs2 = gimple_assign_rhs2 (assign);
-		    add_constraint (rhs1, rhs_code, rhs2, ctxt);
-		  }
-		  break;
-		}
+	    case EQ_EXPR:
+	    case NE_EXPR:
+	      {
+		/* ...and "LHS == (rhs1 OP rhs2)"
+		   then rhs1 OP rhs2 must be true.  */
+		tree rhs1 = gimple_assign_rhs1 (assign);
+		tree rhs2 = gimple_assign_rhs2 (assign);
+		add_constraint (rhs1, rhs_code, rhs2, ctxt);
+	      }
+	      break;
 	    }
+	}
 
-	  /* If we have "LHS == false", i.e. LHS is false... */
-	  if (op == EQ_EXPR)
+      /* If we have "LHS == false", i.e. LHS is false... */
+      if (op == EQ_EXPR)
+	{
+	  switch (rhs_code)
 	    {
-	      switch (rhs_code)
-		{
-		default:
-		  break;
-		case BIT_IOR_EXPR:
-		  {
-		    /* ...and "LHS == (rhs1 | rhs2)
-		       i.e. "(rhs1 | rhs2)" is false
-		       then both rhs1 and rhs2 must be false.  */
-		    tree rhs1 = gimple_assign_rhs1 (assign);
-		    tree rhs2 = gimple_assign_rhs2 (assign);
-		    add_constraint (rhs1, EQ_EXPR, boolean_false_node, ctxt);
-		    add_constraint (rhs2, EQ_EXPR, boolean_false_node, ctxt);
-		    //gcc_unreachable ();
-		  }
-		  break;
-		case EQ_EXPR:
-		case NE_EXPR:
-		  {
-		    /* ...and hence "false == (rhs1 OP rhs2)"
-		       then rhs1 OP rhs2 must be false.  */
-		    tree rhs1 = gimple_assign_rhs1 (assign);
-		    tree rhs2 = gimple_assign_rhs2 (assign);
-		    add_constraint (rhs1,
-				    invert_tree_comparison (rhs_code,
-							    false /* honor_nans */),
-				    rhs2, ctxt);
-		  }
-		  break;
-		}
+	    default:
+	      break;
+	    case BIT_IOR_EXPR:
+	      {
+		/* ...and "LHS == (rhs1 | rhs2)
+		   i.e. "(rhs1 | rhs2)" is false
+		   then both rhs1 and rhs2 must be false.  */
+		tree rhs1 = gimple_assign_rhs1 (assign);
+		tree rhs2 = gimple_assign_rhs2 (assign);
+		add_constraint (rhs1, EQ_EXPR, boolean_false_node, ctxt);
+		add_constraint (rhs2, EQ_EXPR, boolean_false_node, ctxt);
+		//gcc_unreachable ();
+	      }
+	      break;
+	    case EQ_EXPR:
+	    case NE_EXPR:
+	      {
+		/* ...and hence "false == (rhs1 OP rhs2)"
+		   then rhs1 OP rhs2 must be false.  */
+		tree rhs1 = gimple_assign_rhs1 (assign);
+		tree rhs2 = gimple_assign_rhs2 (assign);
+		add_constraint (rhs1,
+				invert_tree_comparison (rhs_code,
+							false /* honor_nans */),
+				rhs2, ctxt);
+	      }
+	      break;
 	    }
 	}
     }
-
-  /* Notify the context, if any.  This exists so that the state machines
-     in a program_state can be notified about the condition, and so can
-     set sm-state for e.g. unchecked->checked, both for cfg-edges, and
-     when synthesizing constraints as above.  */
-  if (ctxt)
-    ctxt->on_condition (lhs, op, rhs);
-
-  return true;
 }
 
 /* Determine what is known about the condition "LHS OP RHS" within
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 04522ef..9836aa5 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -1193,6 +1193,11 @@ class region_model
   svalue_id get_value_by_name (const char *name) const;
 
  private:
+  void add_any_constraints_from_ssa_def_stmt (tree lhs,
+					      enum tree_code op,
+					      tree rhs,
+					      region_model_context *ctxt);
+
   void update_for_call_superedge (const call_superedge &call_edge,
 				  region_model_context *ctxt);
   void update_for_return_superedge (const return_superedge &return_edge,
-- 
1.8.5.3

