From ab6d50876cca0c035f55ea138b714d14fff2eed0 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 19 Jun 2019 18:06:16 -0400
Subject: [PATCH 28/47] FIXME: impl-4: drop path_state, make region_model
 compulsory

---
 gcc/analyzer/impl-4.cc | 841 ++++++++-----------------------------------------
 gcc/common.opt         |   4 -
 2 files changed, 129 insertions(+), 716 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index 55eb12e..2de9ff7 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -219,11 +219,6 @@ public:
 
   int get_stack_depth () const { return m_return_edges.length (); }
 
-  path_var make_path_var (tree expr) const
-  {
-    return path_var (expr, get_stack_depth ());
-  }
-
   int calc_recursion_depth () const;
 
 private:
@@ -326,11 +321,6 @@ public:
 
   const gimple *get_stmt () const;
 
-  path_var make_path_var (tree expr) const
-  {
-    return m_call_string.make_path_var (expr);
-  }
-
   static program_point from_function_entry (const supergraph &sg,
 					    function *fun)
   {
@@ -652,16 +642,11 @@ public:
 		       state_machine::state_t state,
 		       svalue_id origin);
 
-  void purge_stack_frame (int callee_stack_depth);
-
   void purge_for_unknown_fncall (const exploded_graph &eg,
 				 const state_machine &sm,
 				 const gcall *call, tree fndecl,
 				 region_model *new_model);
 
-  int purge (const state_machine &sm,
-	     const psn::purge_criteria &p);
-
   void remap_svalue_ids (const svalue_id_map &map);
 
   int on_svalue_purge (const state_machine &sm,
@@ -686,11 +671,12 @@ private:
    analysis.
 
    Currently this is a combination of:
-   - a path_state giving a set of equivalence classes of path_vars and
-     inequalities between them
-   - an optional region_model, for when -fanalyzer-region-model is enabled
-   - sm_state_maps per state machine, giving a sparse mapping of
-     path_vars to states.  */
+   (a) a region_model
+      (a.1) a hierarchy of memory regions
+      (a.2) values for the regions
+      (a.3) inequalities between values
+   (b) sm_state_maps per state machine, giving a sparse mapping of
+       values to states.  */
 
 class program_state
 {
@@ -710,12 +696,6 @@ public:
 		   pretty_printer *pp) const;
   void dump (const extrinsic_state &ext_state) const;
 
-  psn::equiv_class &get_ec (path_var pv)
-  {
-    psn::equiv_class_id ec_id = m_path_state.get_or_add_equiv_class (pv);
-    return ec_id.get_obj (m_path_state);
-  }
-
   program_state prune_for_point (exploded_graph &eg,
 				 const program_point &point) const;
 
@@ -749,8 +729,7 @@ public:
   void validate (const extrinsic_state &ext_state) const;
 
   //private:
-  path_state m_path_state;
-
+  // FIXME: lose the pointer here (but there are const-correctness issues):
   region_model *m_region_model;
 
   auto_delete_vec<sm_state_map> m_checker_states;
@@ -812,31 +791,6 @@ class exploded_node : public dnode
 		program_point *next_point,
 		program_state *next_state) const;
 
-  void on_assignment (const exploded_graph &eg,
-		      path_var lhs,
-		      path_var rhs,
-		      const program_state &old_state,
-		      program_state *new_state) const;
-
-  void on_assignment_for_region_model (exploded_graph &eg,
-				       const gassign *stmt,
-				       const program_state &old_state,
-				       program_state *new_state) const;
-  void on_call_for_region_model (exploded_graph &eg,
-				 const gcall *stmt,
-				 const program_state &old_state,
-				 program_state *new_state) const;
-  void on_return_for_region_model (exploded_graph &eg,
-				   const greturn *return_,
-				   const program_state &old_state,
-				   program_state *new_state) const;
-
-  void copy_sm_state (const exploded_graph &eg,
-		      path_var lhs,
-		      path_var rhs,
-		      const program_state &old_state,
-		      program_state *new_state) const;
-
   void detect_leaks (exploded_graph &eg) const;
 
   const program_point &get_point () const { return m_ps.m_point; }
@@ -901,7 +855,6 @@ struct stats
 
   int m_num_nodes[NUM_POINT_KINDS];
   int m_node_reuse_count;
-  int m_path_vars_purged;
   int m_num_supernodes;
 };
 
@@ -1656,13 +1609,6 @@ public:
 		  state_machine::state_t baseline_state,
 		  state_machine::state_t new_state);
 
-  equiv_class &get_ec (tree expr)
-  {
-    path_var pv (expr, get_stack_depth ());
-    equiv_class_id ec_id = m_ps.get_or_add_equiv_class (pv);
-    return ec_id.get_obj (m_ps);
-  }
-
   const supergraph &get_sg () const;
   const state_machine &get_sm () const;
 
@@ -2146,30 +2092,6 @@ sm_state_map::impl_set_state (svalue_id sid, state_machine::state_t state,
   m_map.put (sid, entry_t (state, origin));
 }
 
-/* FIXME.  */
-
-void
-sm_state_map::purge_stack_frame (int callee_stack_depth)
-{
-  /* TODO: I *think* this can be empty (and removed); the other purging
-     calls ought to do it for us.  */
-#if 0
-  /* FIXME: not sure how to safely remove during a traversal, so for now
-     do it in two stages.  */
-  auto_vec <Expr_T> keys;
-  for (typename map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    keys.safe_push ((*iter).first);
-
-  int i;
-  Expr_T *pv;
-  FOR_EACH_VEC_ELT (keys, i, pv)
-    if (pv->m_stack_depth >= callee_stack_depth)
-      m_map.remove (*pv);
-#endif
-}
-
 /* Handle CALL to unknown FNDECL with an unknown function body, which
    could do anything to the states passed to it.
    Clear any state for SM for the params and any LHS.
@@ -2222,35 +2144,6 @@ sm_state_map::purge_for_unknown_fncall (const exploded_graph &eg,
     }
 }
 
-int
-sm_state_map::purge (const state_machine &sm,
-		     const psn::purge_criteria &p)
-{
-  // FIXME:
-#if 0
-  /* FIXME: not sure how to safely remove during a traversal, so for now
-     do it in two stages.  */
-  auto_vec<path_var> to_remove;
-  for (typename map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      if (p.should_purge_p ((*iter).first)
-	  && sm.can_purge_p ((*iter).second.m_state))
-	to_remove.safe_push ((*iter).first);
-    }
-
-  int i;
-  path_var *pv;
-  FOR_EACH_VEC_ELT (to_remove, i, pv)
-    m_map.remove (*pv);
-
-  return to_remove.length ();
-#else
-  return 0;
-#endif
-}
-
 /* FIXME.  */
 
 void
@@ -2484,10 +2377,6 @@ public:
 		      tree origin) FINAL OVERRIDE
   {
     JIT_LOG_FUNC (get_logger ());
-    if (m_enode->get_state ().m_region_model == NULL)
-      return;
-    gcc_assert (m_new_state->m_region_model != NULL);
-
     impl_region_model_context old_ctxt
       (m_eg, m_enode, NULL/*m_enode->get_state ()*/, NULL);
     svalue_id var_old_sid
@@ -2693,7 +2582,7 @@ readability (const_tree expr)
 }
 
 // FIXME:
-/* A qsort comparator for path_var for use by exploded_node::detect_leaks,
+/* A qsort comparator for trees for use by exploded_node::detect_leaks,
    to sort them into most user-readable to least user-readable.  */
 
 static int
@@ -2731,9 +2620,6 @@ impl_region_model_context::on_state_leak (const state_machine &sm,
   const program_state &old_state = m_enode->get_state ();
   svalue_id old_sid = map.get_src_for_dst (sid);
 
-  if (!old_state.m_region_model)
-    return;
-
   auto_vec<tree> leaked_trees;
   old_state.m_region_model->get_trees_for_svalue (old_sid, &leaked_trees);
 
@@ -2789,12 +2675,8 @@ impl_region_model_context::on_inherited_svalue (svalue_id parent_sid,
 /* FIXME.  */
 
 program_state::program_state (const extrinsic_state &ext_state)
-: m_path_state (),
-  m_region_model (NULL)
+: m_region_model (new region_model ())
 {
-  if (flag_analyzer_region_model)
-    m_region_model = new region_model ();
-
   int num_states = ext_state.m_checkers.length ();
   for (int i = 0; i < num_states; i++)
     m_checker_states.safe_push (new sm_state_map ());
@@ -2803,10 +2685,7 @@ program_state::program_state (const extrinsic_state &ext_state)
 /* FIXME.  */
 
 program_state::program_state (const program_state &other)
-: m_path_state (other.m_path_state),
-  m_region_model (other.m_region_model
-		  ? new region_model (*other.m_region_model)
-		  : NULL)
+: m_region_model (new region_model (*other.m_region_model))
 {
   int i;
   sm_state_map *smap;
@@ -2819,13 +2698,8 @@ program_state::program_state (const program_state &other)
 program_state&
 program_state::operator= (const program_state &other)
 {
-  m_path_state = other.m_path_state;
-
   delete m_region_model;
-  if (other.m_region_model)
-    m_region_model = new region_model (*other.m_region_model);
-  else
-    m_region_model = NULL;
+  m_region_model = new region_model (*other.m_region_model);
 
   // TODO: eliminate existing things
   gcc_assert (m_checker_states.length () == 0);
@@ -2843,10 +2717,7 @@ program_state::operator= (const program_state &other)
 hashval_t
 program_state::hash () const
 {
-  hashval_t result = m_path_state.hash ();
-
-  if (m_region_model)
-    result ^= m_region_model->hash ();
+  hashval_t result = m_region_model->hash ();
 
   int i;
   sm_state_map *smap;
@@ -2860,17 +2731,7 @@ program_state::hash () const
 bool
 program_state::operator== (const program_state &other) const
 {
-  if (!(m_path_state == other.m_path_state))
-    return false;
-
-  if (m_region_model)
-    {
-      if (other.m_region_model == NULL)
-	return false;
-      if (!(*m_region_model == *other.m_region_model))
-	return false;
-    }
-  else if (other.m_region_model)
+  if (!(*m_region_model == *other.m_region_model))
     return false;
 
   int i;
@@ -2887,16 +2748,10 @@ void
 program_state::print (const extrinsic_state &ext_state,
 		      pretty_printer *pp) const
 {
-  pp_printf (pp, "ps: %s", m_path_state.to_str ().c_str ());
+  pp_printf (pp, "rmodel: ");
+  m_region_model->print (pp);
   pp_newline (pp);
 
-  if (m_region_model)
-    {
-      pp_printf (pp, "rmodel: ");
-      m_region_model->print (pp);
-      pp_newline (pp);
-    }
-
   int i;
   sm_state_map *smap;
   FOR_EACH_VEC_ELT (m_checker_states, i, smap)
@@ -2927,15 +2782,8 @@ void
 program_state::dump_to_pp (const extrinsic_state &ext_state,
 			   pretty_printer *pp) const
 {
-  // FIXME: multiline format?
-  pp_printf (pp, "ps: %s", m_path_state.to_str ().c_str ());
-  pp_newline (pp);
-
-  if (m_region_model)
-    {
-      pp_printf (pp, "rmodel: ");
-      m_region_model->dump_to_pp (pp);
-    }
+  pp_printf (pp, "rmodel: ");
+  m_region_model->dump_to_pp (pp);
 
   int i;
   sm_state_map *smap;
@@ -3051,105 +2899,81 @@ program_state::prune_for_point (exploded_graph &eg,
   purge_at_point_criteria criteria (point, eg.get_purge_map (),
 				    eg.get_ext_state (),
 				    *this);
-  int num_purged = new_state.m_path_state.purge (criteria);
-  eg.log ("path_vars purged: %i", num_purged);
-
-  eg.get_global_stats ()->m_path_vars_purged++;
-  stats *per_fn_stats = eg.get_or_create_function_stats (point.get_function ());
-  per_fn_stats->m_path_vars_purged++;
 
-  // FIXME: state maps also
-  int i;
-  sm_state_map *smap;
-  int num_sm_purged = 0;
-  FOR_EACH_VEC_ELT (new_state.m_checker_states, i, smap)
-    {
-      const state_machine &sm = eg.get_ext_state ().get_sm (i);
-      num_sm_purged += smap->purge (sm, criteria);
-    }
-  eg.log ("num_sm_purged: %i", num_sm_purged);
+  purge_stats stats;
 
-  if (new_state.m_region_model)
+  const state_purge_map *pm = eg.get_purge_map ();
+  if (pm)
     {
-#if 0
-      if (eg.get_logger ())
-	new_state.m_region_model->dump_to_pp (eg.get_logger_pp ());
-#endif
-      purge_stats stats;
-
-      const state_purge_map *pm = eg.get_purge_map ();
-      if (pm)
+      region_id_set purgeable_ssa_regions (new_state.m_region_model);
+      region_id frame_rid
+	= new_state.m_region_model->get_current_frame_id ();
+      frame_region *frame
+	= new_state.m_region_model->get_region <frame_region>(frame_rid);
+
+      /* FIXME: move to a member of region_model, once the state_purge_map
+	 etc decls are visible there.  */
+
+      auto_vec<tree> ssa_names_to_purge;
+      for (frame_region::map_t::iterator iter = frame->m_map.begin ();
+	   iter != frame->m_map.end ();
+	   ++iter)
 	{
-	  region_id_set purgeable_ssa_regions (new_state.m_region_model);
-	  region_id frame_rid
-	    = new_state.m_region_model->get_current_frame_id ();
-	  frame_region *frame
-	    = new_state.m_region_model->get_region <frame_region>(frame_rid);
-
-	  /* FIXME: move to a member of region_model, once the state_purge_map
-	     etc decls are visible there.  */
-
-	  auto_vec<tree> ssa_names_to_purge;
-	  for (frame_region::map_t::iterator iter = frame->m_map.begin ();
-	       iter != frame->m_map.end ();
-	       ++iter)
+	  tree var = (*iter).first;
+	  region_id rid = (*iter).second;
+	  if (TREE_CODE (var) == SSA_NAME)
 	    {
-	      tree var = (*iter).first;
-	      region_id rid = (*iter).second;
-	      if (TREE_CODE (var) == SSA_NAME)
+	      const state_purge_per_ssa_name &per_ssa
+		= pm->get_data_for_ssa_name (var);
+	      if (!per_ssa.needed_at_point_p (flat_point))
 		{
-		  const state_purge_per_ssa_name &per_ssa
-		    = pm->get_data_for_ssa_name (var);
-		  if (!per_ssa.needed_at_point_p (flat_point))
-		    {
-		      region *region
-			= new_state.m_region_model->get_region (rid);
-		      svalue_id sid = region->get_value_direct ();
-		      if (!sid.null_p ())
-			if (!new_state.can_purge_p (eg.get_ext_state (), sid))
-			  {
-			    /* (currently only state maps can keep things
-			       alive).  */
-			    eg.log ("not purging RID: %i for %qE"
-				    " (used by state map)",
-				    rid.as_int (), var);
-			    continue;
-			  }
-		      purgeable_ssa_regions.add_region (rid);
-		      ssa_names_to_purge.safe_push (var);
-		      eg.log ("purging RID: %i for %qE", rid.as_int (), var);
-		      // FIXME: we also need to remove the region from the map
-		      // note that we're mid-traversal: this is done in unbind
-		      // below
-		    }
+		  region *region
+		    = new_state.m_region_model->get_region (rid);
+		  svalue_id sid = region->get_value_direct ();
+		  if (!sid.null_p ())
+		    if (!new_state.can_purge_p (eg.get_ext_state (), sid))
+		      {
+			/* (currently only state maps can keep things
+			   alive).  */
+			eg.log ("not purging RID: %i for %qE"
+				" (used by state map)",
+				rid.as_int (), var);
+			continue;
+		      }
+		  purgeable_ssa_regions.add_region (rid);
+		  ssa_names_to_purge.safe_push (var);
+		  eg.log ("purging RID: %i for %qE", rid.as_int (), var);
+		  // FIXME: we also need to remove the region from the map
+		  // note that we're mid-traversal: this is done in unbind
+		  // below
 		}
 	    }
-
-	  /* Unbind the regions from the frame's map of vars-to-regions.  */
-	  tree var;
-	  FOR_EACH_VEC_ELT (ssa_names_to_purge, i, var)
-	    frame->unbind (var);
-
-	  /* Purge the regions.  Nothing should point to them, and they
-	     should have no children, as they are for SSA names.  */
-	  new_state.m_region_model->purge_regions (purgeable_ssa_regions,
-						   &stats,
-						   eg.get_logger ());
 	}
 
-      /* Purge unused svalues.  */
-      // FIXME: which enode to use, if any?
-      impl_region_model_context ctxt (eg, NULL /* FIXME: old_state*/,
-				      &new_state, NULL);
-      new_state.m_region_model->purge_unused_svalues (&stats, &ctxt);
-
-      eg.log ("num svalues purged: %i", stats.m_num_svalues);
-      eg.log ("num regions purged: %i", stats.m_num_regions);
-      eg.log ("num equiv_classes purged: %i", stats.m_num_equiv_classes);
-      eg.log ("num constraints purged: %i", stats.m_num_constraints);
-      eg.log ("num sm map items purged: %i", stats.m_num_client_items);
+      /* Unbind the regions from the frame's map of vars-to-regions.  */
+      unsigned i;
+      tree var;
+      FOR_EACH_VEC_ELT (ssa_names_to_purge, i, var)
+	frame->unbind (var);
+
+      /* Purge the regions.  Nothing should point to them, and they
+	 should have no children, as they are for SSA names.  */
+      new_state.m_region_model->purge_regions (purgeable_ssa_regions,
+					       &stats,
+					       eg.get_logger ());
     }
 
+  /* Purge unused svalues.  */
+  // FIXME: which enode to use, if any?
+  impl_region_model_context ctxt (eg, NULL /* FIXME: old_state*/,
+				  &new_state, NULL);
+  new_state.m_region_model->purge_unused_svalues (&stats, &ctxt);
+  eg.log ("num svalues purged: %i", stats.m_num_svalues);
+  eg.log ("num regions purged: %i", stats.m_num_regions);
+  eg.log ("num equiv_classes purged: %i", stats.m_num_equiv_classes);
+  eg.log ("num constraints purged: %i", stats.m_num_constraints);
+  eg.log ("num sm map items purged: %i", stats.m_num_client_items);
+
   return new_state;
 }
 
@@ -3169,8 +2993,6 @@ program_state::remap_svalue_ids (const svalue_id_map &map)
 tree
 program_state::get_representative_tree (svalue_id sid) const
 {
-  if (m_region_model == NULL)
-    return NULL_TREE;
   return m_region_model->get_representative_tree (sid);
 }
 
@@ -3179,17 +3001,13 @@ program_state::get_representative_tree (svalue_id sid) const
 void
 program_state::validate (const extrinsic_state &ext_state) const
 {
-  m_path_state.validate ();
-  if (m_region_model)
+  m_region_model->validate ();
+  int sm_idx;
+  sm_state_map *smap;
+  FOR_EACH_VEC_ELT (m_checker_states, sm_idx, smap)
     {
-      m_region_model->validate ();
-      int sm_idx;
-      sm_state_map *smap;
-      FOR_EACH_VEC_ELT (m_checker_states, sm_idx, smap)
-	{
-	  const state_machine &sm = ext_state.get_sm (sm_idx);
-	  smap->validate (sm, m_region_model->get_num_svalues ());
-	}
+      const state_machine &sm = ext_state.get_sm (sm_idx);
+      smap->validate (sm, m_region_model->get_num_svalues ());
     }
 }
 
@@ -3384,13 +3202,10 @@ exploded_node::on_stmt (exploded_graph &eg) const
 {
   const program_point &point = m_ps.m_point;
   const program_state &old_state = m_ps.m_state;
-  //const path_state &old_ps = old_state.m_path_state;
 
   program_state new_state (old_state);
-  path_state *new_ps = &new_state.m_path_state;
 
   const gimple *stmt = point.get_stmt ();
-  int stack_depth = point.get_stack_depth ();
 
   /* Update cfun and input_location in case of ICE: make it easier to
      track down which source construct we're failing to handle.  */
@@ -3400,92 +3215,21 @@ exploded_node::on_stmt (exploded_graph &eg) const
   impl_region_model_context ctxt (eg, this, &new_state, NULL);
 
   if (const gassign *assign = dyn_cast <const gassign *> (stmt))
-    {
-      tree lhs = gimple_assign_lhs (assign);
-      tree rhs1 = gimple_assign_rhs1 (assign);
-      enum tree_code op = gimple_assign_rhs_code (assign);
-      switch (op)
-	{
-	default:
-	  break;
-
-	case FLOAT_EXPR:
-	case NOP_EXPR:
-	case SSA_NAME:
-	case INTEGER_CST:
-	  {
-	    /* Direct assignment of the form LHS = RHS;  */
-	    on_assignment (eg,
-			   new_ps->make_path_var (lhs),
-			   new_ps->make_path_var (rhs1),
-			   old_state,
-			   &new_state);
-	  }
-	  break;
-
-	case EQ_EXPR:
-	case NE_EXPR:
-	case GE_EXPR:
-	case LE_EXPR:
-	case GT_EXPR:
-	case LT_EXPR:
-	  {
-	    /* If we see a comparison, evaluate it based on what we know along
-	       this path, and record the result, if known.  */
-	    tree rhs2 = gimple_assign_rhs2 (assign);
-	    psn::equiv_class_id rhs1_ec_id
-	      = new_ps->get_or_add_equiv_class (path_var (rhs1, stack_depth));
-	    psn::equiv_class_id rhs2_ec_id
-	      = new_ps->get_or_add_equiv_class (path_var (rhs2, stack_depth));
-	    tristate t = new_ps->eval_condition (rhs1_ec_id, op, rhs2_ec_id);
-	    if (eg.get_logger ())
-	      eg.log ("eval condition: %s", t.as_string ());
-	    if (t.is_known ())
-	      new_ps->add_constraint (path_var (lhs, stack_depth),
-				      t.is_true () ? NE_EXPR : EQ_EXPR,
-				      path_var (integer_zero_node,
-						stack_depth));
-	  }
-	  break;
-
-	case COMPONENT_REF:
-	  {
-	    /* Propagate any state from RHS's operand 0 to LHS
-	       (e.g. for use by the taint checker).  */
-	    copy_sm_state (eg,
-			   new_ps->make_path_var (lhs),
-			   new_ps->make_path_var (TREE_OPERAND (rhs1, 0)),
-			   old_state,
-			   &new_state);
-	  }
-	  break;
-	}
-
-      /* TODO: working on having region model handle all assignments.  */
-      on_assignment_for_region_model (eg, assign, old_state, &new_state);
-    }
+    new_state.m_region_model->on_assignment (assign, &ctxt);
 
   if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
-    {
-      tree callee = point.get_function ()->decl;
-      tree lhs = DECL_RESULT (callee);
-      tree rhs = gimple_return_retval (return_);
-      if (rhs)
-	on_assignment (eg,
-		       new_ps->make_path_var (lhs),
-		       new_ps->make_path_var (rhs),
-		       old_state,
-		       &new_state);
-      on_return_for_region_model (eg, return_, old_state, &new_state);
-    }
+    new_state.m_region_model->on_return (return_, &ctxt);
 
   if (const gcall *call = dyn_cast <const gcall *> (stmt))
     {
       /* Debugging/test support.  */
       if (is_named_call_p (call, "__dump_constraints", 0))
 	{
+	  // FIXME: port to region model?
+#if 0
 	  inform (stmt->location, "__dump_constraints: %s",
 		  new_ps->to_str ().c_str ());
+#endif
 	}
       else if (is_named_call_p (call, "__analyzer_dump", 0))
 	{
@@ -3496,9 +3240,8 @@ exploded_node::on_stmt (exploded_graph &eg) const
       else if (is_named_call_p (call, "__analyzer_dump_region_model", 0))
 	{
 	  /* Handle the builtin "__analyzer_dump_region_model" by dumping
-	     the region model's state to stderr (if any).  */
-	  if (new_state.m_region_model)
-	    new_state.m_region_model->dump ();
+	     the region model's state to stderr.  */
+	  new_state.m_region_model->dump ();
 	}
       else if (is_named_call_p (call, "__analyzer_eval", 1))
 	{
@@ -3508,12 +3251,10 @@ exploded_node::on_stmt (exploded_graph &eg) const
 	     lead to DejaGnu failures).  */
 	  tree t_arg = gimple_call_arg (call, 0);
 	  tristate t
-	    = (new_state.m_region_model
-	       ? new_state.m_region_model->eval_condition (t_arg,
-							   NE_EXPR,
-							   integer_zero_node,
-							   &ctxt)
-	       : new_ps->dump_condition (t_arg, NE_EXPR, integer_zero_node));
+	    = new_state.m_region_model->eval_condition (t_arg,
+							NE_EXPR,
+							integer_zero_node,
+							&ctxt);
 	  warning_at (call->location, 0, "%s", t.as_string ());
 	}
       else if (is_named_call_p (call, "__analyzer_break", 0))
@@ -3521,7 +3262,7 @@ exploded_node::on_stmt (exploded_graph &eg) const
 	  raise (SIGINT); // FIXME: cross-platform way to do this?
 	  //gcc_unreachable (); // FIXME: compare to a hard breakpoint
 	}
-      on_call_for_region_model (eg, call, old_state, &new_state);
+      new_state.m_region_model->on_call (call, &ctxt);
     }
 
   int sm_idx;
@@ -3554,116 +3295,6 @@ exploded_node::on_stmt (exploded_graph &eg) const
   return new_state;
 }
 
-void
-exploded_node::on_assignment (const exploded_graph &eg,
-			      path_var lhs,
-			      path_var rhs,
-			      const program_state &old_state,
-			      program_state *new_state) const
-{
-  JIT_LOG_FUNC (eg.get_logger ());
-  if (eg.get_logger ())
-    {
-      eg.log ("lhs: %s", lhs.to_str ().c_str ());
-      eg.log ("rhs: %s", rhs.to_str ().c_str ());
-    }
-
-#if 0
-  if (TREE_CODE (lhs.m_tree) != SSA_NAME
-      && TREE_CODE (lhs.m_tree) != RESULT_DECL
-      && TREE_CODE (lhs.m_tree) != VAR_DECL)
-    return;
-#endif
-
-  new_state->m_path_state.on_assignment (lhs, rhs);
-
-  copy_sm_state (eg, lhs, rhs, old_state, new_state);
-}
-
-/* FIXME.  */
-
-void
-exploded_node::on_assignment_for_region_model (exploded_graph &eg,
-					       const gassign *stmt,
-					       const program_state &/*old_state*/,
-					       program_state *new_state) const
-{
-  if (new_state->m_region_model)
-    {
-      impl_region_model_context ctxt (eg, this, new_state, NULL);
-      new_state->m_region_model->on_assignment (stmt, &ctxt);
-    }
-}
-
-/* FIXME.  */
-
-void
-exploded_node::on_call_for_region_model (exploded_graph &eg,
-					 const gcall *stmt,
-					 const program_state &/*old_state*/,
-					 program_state *new_state) const
-{
-  if (new_state->m_region_model)
-    {
-      impl_region_model_context ctxt (eg, this, new_state, NULL);
-      new_state->m_region_model->on_call (stmt, &ctxt);
-    }
-}
-
-/* FIXME.  */
-
-void
-exploded_node::on_return_for_region_model (exploded_graph &eg,
-					   const greturn *stmt,
-					   const program_state &/*old_state*/,
-					   program_state *new_state) const
-{
-  if (new_state->m_region_model)
-    {
-      impl_region_model_context ctxt (eg, this, new_state, NULL);
-      new_state->m_region_model->on_return (stmt, &ctxt);
-    }
-}
-
-/* Copy SM state (if any) from RHS to LHS.  */
-
-void
-exploded_node::copy_sm_state (const exploded_graph &eg,
-			      path_var lhs,
-			      path_var rhs,
-			      const program_state &old_state,
-			      program_state *new_state) const
-{
-  /* Don't attempt to copy SM state from constants, since otherwise
-     for "ptr = NULL;" it would overwrite the SM-matched "null" state
-     for "ptr" with the implicit "start" state of the NULL constant.  */
-  if (CONSTANT_CLASS_P (rhs.m_tree))
-    return;
-
-  const extrinsic_state &ext_state = eg.get_ext_state ();
-  gcc_assert (old_state.m_checker_states.length ()
-	      == ext_state.m_checkers.length ());
-  gcc_assert (new_state->m_checker_states.length ()
-	      == ext_state.m_checkers.length ());
-  for (unsigned i = 0; i < ext_state.m_checkers.length (); i++)
-    {
-      const state_machine &sm = ext_state.get_sm (i);
-      const sm_state_map *src_smap = old_state.m_checker_states[i];
-      sm_state_map *dst_smap = new_state->m_checker_states[i];
-      // FIXME:
-#if 0
-      state_machine::state_t rhs_state = src_smap->get_state (rhs);
-      dst_smap->set_state (&new_state->m_path_state, lhs, rhs_state, rhs);
-      if (eg.get_logger ())
-	eg.log ("%s: copying state %qs to %s from %s",
-		sm.get_name (),
-		sm.get_state_name (rhs_state),
-		lhs.to_str ().c_str (),
-		rhs.to_str ().c_str ());
-#endif
-    }
-}
-
 /* FIXME.
    Consider the effect of following superedge SUCC from this node.
 
@@ -3697,6 +3328,7 @@ exploded_node::on_edge (exploded_graph &eg,
   return true;
 }
 
+// FIXME: this comment needs rewriting:
 /* Called when finding the successors of the supernode for a function exit
    basic block.
 
@@ -3713,9 +3345,6 @@ exploded_node::detect_leaks (exploded_graph &eg) const
 {
   JIT_LOG_FUNC_1 (eg.get_logger (), "EN: %i", m_index);
 
-  // FIXME:
-#if 1
-
   /* FIXME: with region model, should we only do this when the callstring
      is empty?  when we're popping the stack, purge_unused_svalues ought
      to detect leaks due to popping the frame.  */
@@ -3726,104 +3355,15 @@ exploded_node::detect_leaks (exploded_graph &eg) const
     return;
   gcc_assert (get_point ().get_stack_depth () == 0);
 
-  if (old_state.m_region_model == NULL)
-    return;
-
-  /* Work with a temporary copy of the state.  */
+  /* Work with a temporary copy of the state: pop the frame, and see
+     what leaks (via purge_unused_svalues).  */
   program_state new_state (old_state);
 
   gcc_assert (new_state.m_region_model);
 
   purge_stats stats;
   impl_region_model_context ctxt(eg, this, &new_state);
-  // stmt_finder *stmt_finder = NULL)
   new_state.m_region_model->pop_frame (&stats, &ctxt);
-
-  //gcc_unreachable ();
-
-  /* FIXME: maybe clone the state, and then pop the frame, and see what leaks,
-     somehow marking any return value as escaping.  */
-
-#else
-
-  const program_state &old_state = get_state ();
-
-  /* Work with a temporary copy of the state.  */
-  program_state new_state (old_state);
-  path_state *new_ps = &new_state.m_path_state;
-
-  const supernode *snode = get_supernode ();
-  const int stack_depth = get_stack_depth ();
-
-  /* Mark EC of return value (if any) as escaping.  */
-  {
-    tree result = DECL_RESULT (snode->m_fun->decl);
-    if (result)
-      {
-	if (eg.get_logger ())
-	  eg.log ("new_ps before escapes: %s", new_ps->to_str ().c_str ());
-	psn::equiv_class_id ec_id
-	  = new_ps->get_or_add_equiv_class (path_var (result, stack_depth));
-	new_ps->recursively_mark_as_escaping (ec_id);
-	if (eg.get_logger ())
-	  eg.log ("new_ps after escapes: %s", new_ps->to_str ().c_str ());
-      }
-  }
-
-  int i;
-  psn::equiv_class *ec;
-  FOR_EACH_VEC_ELT (new_ps->m_equiv_classes, i, ec)
-    {
-      if (eg.get_logger ())
-	eg.log ("considering %s", ec->to_str ().c_str ());
-
-      if (ec->m_escaped)
-	{
-	  eg.log ("no leak: ec escaped");
-	  continue;
-	}
-
-      /* If anything in this EC is still alive in a parent stack frame,
-	 then this isn't a leak.  */
-      if (ec->get_min_stack_depth () < stack_depth)
-	{
-	  eg.log ("no leak: ec member alive within ancestor stack frame");
-	  continue;
-	}
-
-      /* Sort the leaks into most human-readable first, through
-	 to least user-readable.  Given that we only emit one
-	 leak per EC, this ought to ensure that we pick the most
-	 user-readable description of each leaking EC.
-	 This assumes that all vars in the EC have the same state.  */
-      ec->m_vars.qsort (leak_comparator);
-
-      if (ec->m_vars.length () < 1)
-	continue;
-
-      path_var best_pv (ec->m_vars[0]);
-      if (eg.get_logger ())
-	eg.log ("best_pv: %s", best_pv.to_str ().c_str ());
-
-      /* Determining the best statement for the leak needs to happen
-	 after we have an emission path, so pass in a stmt_finder.  */
-      leak_stmt_finder stmt_finder (eg, best_pv);
-
-      int i;
-      sm_state_map *smap;
-      FOR_EACH_VEC_ELT (old_state.m_checker_states, i, smap)
-	{
-	  const state_machine &sm = m_ext_state.get_sm (i);
-	  impl_sm_context ctxt (eg, sm, this,
-				&new_state,
-				*old_state.m_checker_states[i],
-				new_state.m_checker_states[i],
-				&stmt_finder);
-	  sm.on_leak (&ctxt, snode, NULL, best_pv.m_tree,
-		      smap->get_state (best_pv));
-	}
-    }
-#endif
 }
 
 // TODO: move this fn
@@ -3900,6 +3440,13 @@ program_state::on_edge (exploded_graph &eg,
 {
   /* Update state.  */
 
+  if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL)
+    {
+      /* We ignore these edges.  FIXME: why have them?  */
+      eg.log ("rejecting interprocedural edge");
+      return false;
+    }
+
   const program_point &point = enode.get_point ();
   const program_state &old_state = enode.get_state ();
   const gimple *last_stmt = point.m_supernode->get_last_stmt ();
@@ -3907,99 +3454,16 @@ program_state::on_edge (exploded_graph &eg,
   /* For conditionals and switch statements, add the
      relevant conditions (for the specific edge) to new_state;
      skip edges for which the resulting constraints
-     are impossible.  */
-  if (!m_path_state.apply_constraints_for_edge (*succ,
-						last_stmt))
-    {
-      eg.log ("edge to SN: %i is impossible due to path_state constraints",
-	      succ->m_dest->m_index);
-      return false;
-    }
+     are impossible.
+     This also updates frame information for call/return superedges.  */
 
   impl_region_model_context ctxt (eg, &enode, this, NULL);
-
-  if (m_region_model)
-    if (!m_region_model->apply_constraints_for_edge (*succ,
-						     last_stmt,
-						     &ctxt))
-      {
-	eg.log ("edge to SN: %i is impossible due to region_model constraints",
-		succ->m_dest->m_index);
-	return false;
-      }
-
-  /* FIXME: the above is setting ECs for args/params on calls, but not
-     updating states.  should we call on_assignment instead.
-     Also, where should it happen for return values at returns?
-     Similarly, the above is pruning state in path_state, but not within
-     the sm_state_map.
-
-     Should we be passing on_assignment to it as a callback?
-     Similarly for frame purging?  */
-
-  /* Hack to do it for interprocedural calls/returns.  */
-  switch (succ->m_kind)
+  if (!m_region_model->apply_constraints_for_edge (*succ,
+						   last_stmt,
+						   &ctxt))
     {
-    case SUPEREDGE_CFG_EDGE:
-      break;
-
-    case SUPEREDGE_CALL:
-      /* Copy state from args to params.  */
-      {
-	const call_superedge *call_edge
-	  = succ->dyn_cast_call_superedge ();
-	// FIXME: should be an as_a
-
-	/* Map args to parms at next stack_depth, incrementing stack depth.  */
-	int caller_stack_depth = enode.get_stack_depth ();
-	int callee_stack_depth = caller_stack_depth + 1;
-
-	tree callee = call_edge->get_callee_decl ();
-	gcall *call_stmt = call_edge->get_call_stmt ();
-
-	int i = 0;
-	for (tree parm = DECL_ARGUMENTS (callee); parm;
-	     parm = DECL_CHAIN (parm), ++i)
-	  {
-	    tree parm_default_ssa
-	      = ssa_default_def (call_edge->m_dest->m_fun, parm);
-	    if (parm_default_ssa)
-	      enode.on_assignment (eg,
-				   path_var (parm_default_ssa,
-					     callee_stack_depth),
-				   path_var (gimple_call_arg (call_stmt, i),
-					     caller_stack_depth),
-				   old_state,
-				   this);
-	  }
-      }
-      break;
-
-    case SUPEREDGE_RETURN:
-      {
-	const return_superedge *return_edge
-	  = succ->dyn_cast_return_superedge ();
-	// FIXME: should be an as_a
-	int callee_stack_depth = enode.get_stack_depth ();
-	int caller_stack_depth = callee_stack_depth - 1;
-	tree callee = return_edge->get_callee_decl ();
-	tree result = DECL_RESULT (callee);
-	gcall *call_stmt = return_edge->get_call_stmt ();
-	tree lhs = gimple_call_lhs (call_stmt);
-	if (lhs)
-	  {
-	    enode.on_assignment (eg,
-				 path_var (lhs, caller_stack_depth),
-				 path_var (result, callee_stack_depth),
-				 old_state,
-				 this);
-	  }
-      }
-      break;
-
-    case SUPEREDGE_INTRAPROCEDURAL_CALL:
-      /* We ignore these edges.  FIXME: why have them?  */
-      eg.log ("rejecting interprocedural edge");
+      eg.log ("edge to SN: %i is impossible due to region_model constraints",
+	      succ->m_dest->m_index);
       return false;
     }
 
@@ -4015,27 +3479,6 @@ program_state::on_edge (exploded_graph &eg,
 			    old_state.m_checker_states[i],
 			    m_checker_states[i]);
       sm.on_edge (&ctxt, last_stmt, succ);
-
-      switch (succ->m_kind)
-	{
-	case SUPEREDGE_CFG_EDGE:
-	  break;
-
-	case SUPEREDGE_CALL:
-	  /* Copy state from params to args.  */
-	  // TODO
-	  break;
-
-	case SUPEREDGE_RETURN:
-	  {
-	    int callee_stack_depth = enode.get_stack_depth ();
-	    m_checker_states[i]->purge_stack_frame (callee_stack_depth);
-	  }
-	  break;
-
-	case SUPEREDGE_INTRAPROCEDURAL_CALL:
-	  break;
-	}
     }
 
   return true;
@@ -4105,7 +3548,6 @@ exploded_edge::dump_dot (graphviz_out *gv) const
 
 stats::stats (int num_supernodes)
 : m_node_reuse_count (0),
-  m_path_vars_purged (0),
   m_num_supernodes (num_supernodes)
 {
   for (int i = 0; i < NUM_POINT_KINDS; i++)
@@ -4123,7 +3565,6 @@ stats::log (logger *logger) const
 		 point_kind_to_string (static_cast <enum point_kind> (i)),
 		 m_num_nodes[i]);
   logger->log ("m_node_reuse_count: %i", m_node_reuse_count);
-  logger->log ("m_path_vars_purged: %i", m_path_vars_purged);
 }
 
 /* FIXME.  */
@@ -4136,7 +3577,6 @@ stats::dump (FILE *out) const
 	     point_kind_to_string (static_cast <enum point_kind> (i)),
 	     m_num_nodes[i]);
   fprintf (out, "m_node_reuse_count: %i\n", m_node_reuse_count);
-  fprintf (out, "m_path_vars_purged: %i\n", m_path_vars_purged);
 
   if (m_num_supernodes > 0)
     fprintf (out, "PK_AFTER_SUPERNODE nodes per supernode: %.2f\n",
@@ -4671,9 +4111,8 @@ diagnostic_manager::build_emission_path (const exploded_graph &eg,
 	      state_machine::state_t dst_sm_val = (*iter).second.m_state;
 
 	      auto_vec<tree> dst_trees;
-	      if (dst_state.m_region_model)
-		dst_state.m_region_model->get_trees_for_svalue (dst_sid,
-								&dst_trees);
+	      dst_state.m_region_model->get_trees_for_svalue (dst_sid,
+							      &dst_trees);
 
 #if 1
 	      unsigned j;
@@ -4727,9 +4166,8 @@ diagnostic_manager::build_emission_path (const exploded_graph &eg,
 		  else
 		    {
 		      auto_vec<tree> origin_trees;
-		      if (dst_state.m_region_model)
-			dst_state.m_region_model->get_trees_for_svalue
-			  (dst_origin_sid, &origin_trees);
+		      dst_state.m_region_model->get_trees_for_svalue
+			(dst_origin_sid, &origin_trees);
 		      unsigned k;
 		      tree origin_rep;
 		      FOR_EACH_VEC_ELT (origin_trees, j, origin_rep)
@@ -5053,8 +4491,7 @@ exploded_graph::add_function_entry (function *fun)
 {
   program_point point = program_point::from_function_entry (m_sg, fun);
   program_state state (m_ext_state);
-  if (state.m_region_model)
-    state.m_region_model->push_frame (fun, NULL);
+  state.m_region_model->push_frame (fun, NULL);
 
   add_edge (m_origin, get_or_create_node (point, state), NULL);
 }
@@ -5091,8 +4528,7 @@ exploded_graph::get_or_create_node (const program_point &point,
   if (get_logger ())
     {
       log ("pruned_state: %s", pruned_state.to_str (m_ext_state).c_str ());
-      if (pruned_state.m_region_model)
-	pruned_state.m_region_model->dump_to_pp (get_logger_pp ());
+      pruned_state.m_region_model->dump_to_pp (get_logger_pp ());
     }
 
   stats *per_fn_stats = get_or_create_function_stats (point.get_function ());
@@ -5125,13 +4561,10 @@ exploded_graph::get_or_create_node (const program_point &point,
       log ("pruned_state: %s", pruned_state.to_str (m_ext_state).c_str ());
     }
 
-  if (pruned_state.m_region_model)
-    {
-      pretty_printer pp;
-      pp_printf (&pp, "%s.EN-%i.rmodel.dot",
-		 dump_base_name, node->m_index);
-      pruned_state.m_region_model->dump_dot (pp_formatted_text (&pp));
-    }
+  pretty_printer pp;
+  pp_printf (&pp, "%s.EN-%i.rmodel.dot",
+	     dump_base_name, node->m_index);
+  pruned_state.m_region_model->dump_dot (pp_formatted_text (&pp));
 
   /* Add the new node to the worlist.  */
   m_worklist.safe_push (node);
@@ -5237,19 +4670,10 @@ exploded_graph::process_node (exploded_node *node)
 	    tree lhs = gimple_phi_result (phi);
 
 	    /* Update next_state based on phi.  */
-	    node->on_assignment (*this,
-				 point.make_path_var (lhs),
-				 point.make_path_var (src),
-				 state,
-				 &next_state);
-
-	    if (next_state.m_region_model)
-	      {
-		bool is_back_edge = last_cfg_superedge->back_edge_p ();
-		impl_region_model_context ctxt (*this, node, &next_state, NULL);
-		next_state.m_region_model->handle_phi (lhs, src, is_back_edge,
-						       &ctxt);
-	      }
+	    bool is_back_edge = last_cfg_superedge->back_edge_p ();
+	    impl_region_model_context ctxt (*this, node, &next_state, NULL);
+	    next_state.m_region_model->handle_phi (lhs, src, is_back_edge,
+						   &ctxt);
 	  }
 
 	if (point.m_supernode->m_stmts.length () > 0)
@@ -6704,13 +6128,6 @@ test_assignments ()
 {
   /* Verify X = Y, then Y = Z.
      Should propagate states accordingly.  */
-#if 0
-exploded_node::on_assignment (const exploded_graph &eg,
-			      path_var lhs,
-			      path_var rhs,
-			      const program_state &old_state,
-			      program_state *new_state) const
-#endif
 }
 
 /* Run all of the selftests within this file.  */
diff --git a/gcc/common.opt b/gcc/common.opt
index 93be813..e38d5a9 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1456,10 +1456,6 @@ fanalyzer-verbose-state-changes
 Common Var(flag_analyzer_verbose_state_changes) Init(0)
 FIXME
 
-fanalyzer-region-model
-Common Var(flag_analyzer_region_model) Init(1)
-FIXME
-
 fdump-final-insns
 Driver RejectNegative
 
-- 
1.8.5.3

