From eb6edcdf8710f11137012d2145ef275cabaf1db8 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 26 Sep 2019 11:02:18 -0400
Subject: [PATCH 122/124] FIXME: eliminate most of path-state.cc/h

---
 gcc/analyzer/analyzer-selftests.cc |    1 -
 gcc/analyzer/analyzer-selftests.h  |    1 -
 gcc/analyzer/impl-4.cc             |   67 --
 gcc/analyzer/path-state.cc         | 2213 ------------------------------------
 gcc/analyzer/path-state.h          |  261 -----
 5 files changed, 2543 deletions(-)

diff --git a/gcc/analyzer/analyzer-selftests.cc b/gcc/analyzer/analyzer-selftests.cc
index 685bf02..fb412a8 100644
--- a/gcc/analyzer/analyzer-selftests.cc
+++ b/gcc/analyzer/analyzer-selftests.cc
@@ -82,7 +82,6 @@ run_analyzer_selftests ()
   analyzer_constraint_manager_cc_tests ();
   analyzer_digraph_cc_tests ();
   analyzer_impl_4_cc_tests ();
-  analyzer_path_state_cc_tests ();
   analyzer_region_model_cc_tests ();
   analyzer_tristate_cc_tests ();
 }
diff --git a/gcc/analyzer/analyzer-selftests.h b/gcc/analyzer/analyzer-selftests.h
index a3dee4f..e1bece1 100644
--- a/gcc/analyzer/analyzer-selftests.h
+++ b/gcc/analyzer/analyzer-selftests.h
@@ -35,7 +35,6 @@ extern void analyzer_checker_script_cc_tests ();
 extern void analyzer_constraint_manager_cc_tests ();
 extern void analyzer_digraph_cc_tests ();
 extern void analyzer_impl_4_cc_tests ();
-extern void analyzer_path_state_cc_tests ();
 extern void analyzer_region_model_cc_tests ();
 extern void analyzer_tristate_cc_tests ();
 
diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index fc86eeb..9812322 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -3982,69 +3982,6 @@ program_state::on_edge (exploded_graph &eg,
   return true;
 }
 
-/* Implementation of purge_criteria for using state_purge_map.
-
-   Purge state within a path_state using PURGE_MAP for POINT.
-   Use the sm-states within OLD_STATE to avoid purging path_vars
-   that have any sm-state.  */
-
-class purge_at_point_criteria : public psn::purge_criteria
-{
-public:
-  purge_at_point_criteria (const program_point &point,
-			   const state_purge_map *purge_map,
-			   const extrinsic_state &ext_state,
-			   const program_state &old_state)
-  : m_point (point),
-    m_flat_point (point),
-    m_purge_map (purge_map),
-    m_ext_state (ext_state),
-    m_old_state (old_state)
-  {
-    m_flat_point.m_call_string = call_string ();
-  }
-
-  bool should_purge_p (path_var pv) const FINAL OVERRIDE
-  {
-    if (TREE_CODE (pv.m_tree) != SSA_NAME)
-      return false;
-    if (pv.m_stack_depth != m_point.get_stack_depth ())
-      return false;
-
-    if (!m_purge_map)
-      return false;
-
-    const state_purge_per_ssa_name &per_var_data
-      = m_purge_map->get_data_for_ssa_name (pv.m_tree);
-    if (!per_var_data.needed_at_point_p (m_flat_point))
-      {
-	/* Don't purge vars that have sm state, to avoid
-	   losing leak complaints.  */
-	int i;
-	sm_state_map *smap;
-	FOR_EACH_VEC_ELT (m_old_state.m_checker_states, i, smap)
-	  {
-	    // FIXME:
-#if 0
-	    const state_machine &sm = m_ext_state.get_sm (i);
-	    if (!sm.can_purge_p (smap->get_state (pv)))
-	      return false;
-#endif
-	  }
-
-	return true;
-      }
-    return false;
-  }
-
-private:
-  const program_point &m_point;
-  program_point m_flat_point;
-  const state_purge_map *m_purge_map;
-  const extrinsic_state &m_ext_state;
-  const program_state &m_old_state;
-};
-
 /* FIXME.
    Generate a simpler version of THIS, discarding state that's no longer
    relevant at POINT.
@@ -4067,10 +4004,6 @@ program_state::prune_for_point (exploded_graph &eg,
 
   program_state new_state (*this);
 
-  purge_at_point_criteria criteria (point, eg.get_purge_map (),
-				    eg.get_ext_state (),
-				    *this);
-
   purge_stats stats;
 
   const state_purge_map *pm = eg.get_purge_map ();
diff --git a/gcc/analyzer/path-state.cc b/gcc/analyzer/path-state.cc
index d8ce6a6..25f72e4 100644
--- a/gcc/analyzer/path-state.cc
+++ b/gcc/analyzer/path-state.cc
@@ -41,24 +41,6 @@
 #include "analyzer/path-state.h"
 #include "analyzer/supergraph.h"
 
-using namespace psn;
-
-/* A subclass of purge_criteria: purge a specific path_var.  */
-
-class purge_one_path_var : public purge_criteria
-{
-public:
-  purge_one_path_var (path_var victim) : m_victim (victim) {}
-
-  bool should_purge_p (path_var pv) const FINAL OVERRIDE
-  {
-    return pv == m_victim;
-  }
-
-private:
-  path_var m_victim;
-};
-
 /* FIXME.  */
 
 std::string
@@ -75,2198 +57,3 @@ path_var::to_str () const
 	    + std::to_string (m_stack_depth)
 	    + ")");
 }
-
-/* FIXME.  */
-
-equiv_class::equiv_class ()
-: m_constant (NULL_TREE), m_vars (), m_escaped (false), m_extra_state (NULL)
-{
-}
-
-/* FIXME.  */
-
-equiv_class::equiv_class (const equiv_class &other)
-: m_constant (other.m_constant),
-  m_vars (),
-  m_escaped (other.m_escaped),
-  m_extra_state (other.m_extra_state ? other.m_extra_state->clone () : NULL)
-{
-  // FIXME: copy-ctor for auto_vec!
-  int i;
-  path_var *v;
-  FOR_EACH_VEC_ELT (other.m_vars, i, v)
-    m_vars.safe_push (*v);
-}
-
-/* FIXME.  */
-
-equiv_class::~equiv_class ()
-{
-  delete m_extra_state;
-}
-
-/* FIXME.  */
-
-std::string
-equiv_class::to_str () const
-{
-  std::string result ("{");
-  int i;
-  path_var *v;
-  FOR_EACH_VEC_ELT (m_vars, i, v)
-    {
-      gcc_assert (!CONSTANT_CLASS_P (v->m_tree));
-      if (i > 0)
-	result += " == ";
-      result += v->to_str ();
-    }
-  if (m_constant)
-    {
-      if (i > 0)
-	result += " == ";
-      result += expr_to_string (m_constant);
-    }
-  if (m_escaped)
-    result += " (escaped)";
-  if (m_extra_state)
-    result += m_extra_state->to_str ();
-  return result + "}";
-}
-
-/* FIXME.  */
-
-hashval_t
-equiv_class::hash () const
-{
-  inchash::hash hstate;
-  int i;
-  path_var *pv;
-
-  inchash::add_expr (m_constant, hstate);
-  FOR_EACH_VEC_ELT (m_vars, i, pv)
-    inchash::add_path_var (*pv, hstate);
-  hstate.add_flag (m_escaped);
-  hstate.commit_flag ();
-  if (m_extra_state)
-    hstate.merge_hash (m_extra_state->hash ());
-  return hstate.end ();
-}
-
-/* FIXME.  */
-
-bool
-equiv_class::operator== (const equiv_class &other)
-{
-  if (m_constant != other.m_constant)
-    return false; // TODO: use tree equality here
-
-  if (m_vars.length () != other.m_vars.length ())
-    return false;
-
-  int i;
-  path_var *pv;
-  FOR_EACH_VEC_ELT (m_vars, i, pv)
-    if (! (*pv == other.m_vars[i]))
-      return false;
-  if (m_escaped != other.m_escaped)
-    return false;
-
-  if ((m_extra_state != NULL) != (other.m_extra_state != NULL))
-    return false;
-
-  if (m_extra_state != NULL)
-    if (!(*m_extra_state == *other.m_extra_state))
-      return false;
-
-  return true;
-}
-
-/* FIXME.  */
-
-void
-equiv_class::add (path_var v)
-{
-  if (CONSTANT_CLASS_P (v.m_tree))
-    {
-      gcc_assert (m_constant == NULL_TREE);
-      m_constant = v.m_tree;
-    }
-  else
-    {
-      m_vars.safe_push (v);
-
-      if (DECL_P (v.m_tree)
-	  && is_global_var (v.m_tree))
-	m_escaped = true;
-    }
-}
-
-/* Remove V from this equivalence class.
-   Return true if V was the last var in the equivalence class (suggesting
-   a possible leak).  */
-
-bool
-equiv_class::del (path_var v)
-{
-  gcc_assert (!CONSTANT_CLASS_P (v.m_tree));
-
-  int i;
-  path_var *iv;
-  FOR_EACH_VEC_ELT (m_vars, i, iv)
-    {
-      if (*iv == v)
-	{
-	  m_vars[i] = m_vars[m_vars.length () - 1];
-	  m_vars.pop ();
-	  return m_vars.length () == 0;
-	}
-    }
-
-  /* V must be in the class.  */
-  gcc_unreachable ();
-  return false;
-}
-
-/* FIXME.  */
-
-int
-equiv_class::get_min_stack_depth () const
-{
-  int result = INT_MAX;
-
-  int i;
-  path_var *iv;
-  FOR_EACH_VEC_ELT (m_vars, i, iv)
-    result = std::min (result, iv->m_stack_depth);
-  return result;
-}
-
-/* Get a representative member of this class, for handling cases
-   where the IDs can change mid-traversal.  */
-
-path_var
-equiv_class::get_representative () const
-{
-  if (m_constant)
-    return path_var (m_constant, 0);
-  else
-    {
-      gcc_assert (m_vars.length () > 0);
-      return m_vars[0];
-    }
-}
-
-/* FIXME.  */
-
-const char *
-psn::constraint_op_code (enum constraint_op c_op)
-{
-  switch (c_op)
-    {
-    default:
-      gcc_unreachable ();
-    case CONSTRAINT_NE: return "!=";
-    case CONSTRAINT_LT: return "<";
-    case CONSTRAINT_LE: return "<=";
-    }
-}
-
-/* Given "lhs C_OP rhs", determine "lhs T_OP rhs".
-
-   For example, given "x < y", then "x > y" is false.  */
-
-static tristate
-eval_constraint_op_for_op (enum constraint_op c_op, enum tree_code t_op)
-{
-  switch (c_op)
-    {
-    default:
-      gcc_unreachable ();
-    case CONSTRAINT_NE:
-      if (t_op == EQ_EXPR)
-	return tristate (tristate::TS_FALSE);
-      if (t_op == NE_EXPR)
-	return tristate (tristate::TS_TRUE);
-      break;
-    case CONSTRAINT_LT:
-      if (t_op == LT_EXPR || t_op == LE_EXPR || t_op == NE_EXPR)
-	return tristate (tristate::TS_TRUE);
-      if (t_op == EQ_EXPR || t_op == GT_EXPR || t_op == GE_EXPR)
-	return tristate (tristate::TS_FALSE);
-      break;
-    case CONSTRAINT_LE:
-      if (t_op == LE_EXPR)
-	return tristate (tristate::TS_TRUE);
-      if (t_op == GT_EXPR)
-	return tristate (tristate::TS_FALSE);
-      break;
-    }
-  return tristate (tristate::TS_UNKNOWN);
-}
-
-/* FIXME.  */
-
-std::string
-constraint::to_str (const path_state &ps) const
-{
-  return (m_lhs.to_str () + ": "
-	  + m_lhs.get_obj (ps).to_str ()
-	  + " "
-	  + constraint_op_code (m_op)
-	  + " "
-	  + m_rhs.to_str () + ": "
-	  + m_rhs.get_obj (ps).to_str ());
-}
-
-/* FIXME.  */
-
-hashval_t
-constraint::hash () const
-{
-  inchash::hash hstate;
-  hstate.add_int (m_lhs.m_idx);
-  hstate.add_int (m_op);
-  hstate.add_int (m_rhs.m_idx);
-  return hstate.end ();
-}
-
-/* FIXME.  */
-
-bool
-constraint::operator== (const constraint &other) const
-{
-  if (m_lhs != other.m_lhs)
-    return false;
-  if (m_op != other.m_op)
-    return false;
-  if (m_rhs != other.m_rhs)
-    return false;
-  return true;
-}
-
-/* FIXME.  */
-
-const equiv_class &
-equiv_class_id::get_obj (const path_state &ps) const
-{
-  return ps.get_equiv_class_by_index (m_idx);
-}
-
-/* FIXME.  */
-
-equiv_class &
-equiv_class_id::get_obj (path_state &ps) const
-{
-  return ps.get_equiv_class_by_index (m_idx);
-}
-
-/* FIXME.  */
-
-path_state::path_state (const path_state &other)
-: m_stack_depth (other.m_stack_depth)
-{
-  // FIXME: auto_vec's copy_ctor...
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (other.m_equiv_classes, i, ec)
-    m_equiv_classes.safe_push (new equiv_class (*ec));
-  constraint *c;
-  FOR_EACH_VEC_ELT (other.m_constraints, i, c)
-    m_constraints.safe_push (*c);
-}
-
-/* FIXME.  */
-
-path_state::~path_state ()
-{
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    delete ec;
-}
-
-/* FIXME.  */
-
-path_state&
-path_state::operator= (const path_state &other)
-{
-  m_stack_depth = other.m_stack_depth;
-
-  gcc_assert (m_equiv_classes.length () == 0);
-  gcc_assert (m_constraints.length () == 0);
-
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (other.m_equiv_classes, i, ec)
-    m_equiv_classes.safe_push (new equiv_class (*ec));
-  constraint *c;
-  FOR_EACH_VEC_ELT (other.m_constraints, i, c)
-    m_constraints.safe_push (*c);
-
-  return *this;
-}
-
-/* FIXME.  */
-
-hashval_t
-path_state::hash () const
-{
-  inchash::hash hstate;
-  int i;
-  equiv_class *ec;
-  constraint *c;
-
-  hstate.add_int (m_stack_depth);
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    hstate.merge_hash (ec->hash ());
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    hstate.merge_hash (c->hash ());
-  return hstate.end ();
-}
-
-/* FIXME.  */
-
-bool
-path_state::operator== (const path_state &other) const
-{
-  if (m_stack_depth != other.m_stack_depth)
-    return false;
-  if (m_equiv_classes.length () != other.m_equiv_classes.length ())
-    return false;
-  if (m_constraints.length () != other.m_constraints.length ())
-    return false;
-
-  int i;
-  equiv_class *ec;
-
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    if (!(*ec == *other.m_equiv_classes[i]))
-      return false;
-
-  constraint *c;
-
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    if (!(*c == other.m_constraints[i]))
-      return false;
-
-  return true;
-}
-
-/* FIXME.  */
-
-std::string
-path_state::to_str () const
-{
-  std::string result ("{");
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    {
-      if (i > 0)
-	result += ", ";
-      result += equiv_class_id (i).to_str () + ": ";
-      result += ec->to_str ();
-    }
-  result += "  |  ";
-  constraint *c;
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    {
-      if (i > 0)
-	result += " && ";
-      result += c->to_str (*this);
-    }
-  result += "}@";
-  result += std::to_string (m_stack_depth);
-  return result;
-}
-
-/* FIXME.  */
-
-void
-path_state::on_assignment (path_var lhs, path_var rhs)
-{
-  /* Clear LHS.  */
-  purge_one_path_var p (lhs);
-  purge (p);
-
-  add_constraint (lhs, EQ_EXPR, rhs);
-}
-
-/* FIXME.
-   Attempt to extend this path's state with the constraints required by
-   EDGE (where LAST_STMT, if non-NULL, was the stmt guarding the edge).
-   Return true if the edge can be followed, false if it can't be.  */
-
-bool
-path_state::apply_constraints_for_edge (const superedge &edge,
-					const gimple *last_stmt)
-{
-  if (edge.m_kind == SUPEREDGE_CALL)
-    // FIXME: use as_a<>
-    return apply_constraints_for_call (*edge.dyn_cast_call_superedge ());
-
-  if (edge.m_kind == SUPEREDGE_RETURN)
-    // FIXME: use as_a<>
-    return apply_constraints_for_return (*edge.dyn_cast_return_superedge ());
-
-  if (last_stmt == NULL)
-    return true;
-
-  if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
-    return apply_constraints_for_gcond (edge, cond_stmt);
-
-  // FIXME: some linker issues with is_a_helper const
-  if (const gswitch *switch_stmt = dyn_cast <gswitch *> (const_cast <gimple *> (last_stmt)))
-    return apply_constraints_for_gswitch (edge, switch_stmt);
-
-  return true;
-}
-
-/* FIXME.  */
-
-bool
-path_state::apply_constraints_for_call (const call_superedge& edge)
-{
-  /* Map args to parms at next stack_depth, incrementing stack depth.  */
-  int caller_stack_depth = m_stack_depth;
-  int callee_stack_depth = ++m_stack_depth;
-
-  tree callee = edge.get_callee_decl ();
-  gcall *call_stmt = 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 (edge.m_dest->m_fun, parm);
-      if (parm_default_ssa)
-	add_constraint (path_var (parm_default_ssa, callee_stack_depth),
-			EQ_EXPR,
-			path_var (gimple_call_arg (call_stmt, i),
-				  caller_stack_depth));
-    }
-  return true;
-}
-
-/* FIXME.  */
-
-bool
-path_state::apply_constraints_for_return (const return_superedge&)
-{
-  pop_stack_frame ();
-  return true;
-}
-
-/* A subclass of purge_criteria: purge anything above a given stack depth.  */
-
-class purge_above_stack_frame : public purge_criteria
-{
-public:
-  purge_above_stack_frame (int max_stack_depth)
-  : m_max_stack_depth (max_stack_depth) {}
-
-  bool should_purge_p (path_var pv) const FINAL OVERRIDE
-  {
-    return pv.m_stack_depth > m_max_stack_depth;
-  }
-
-private:
-  int m_max_stack_depth;
-};
-
-
-/* Decrement the stack depth, purging vars at the old stack depth (and beyond).
-   This is broken out as a subroutine so it can be unit-tested.  */
-
-void
-path_state::pop_stack_frame ()
-{
-  int caller_stack_depth = --m_stack_depth;
-
-  purge_above_stack_frame p (caller_stack_depth);
-  purge (p);
-}
-
-/* FIXME.  */
-
-bool
-path_state::apply_constraints_for_gcond (const superedge &edge,
-					 const gcond *cond_stmt)
-{
-  ::edge cfg_edge = edge.get_any_cfg_edge ();
-  gcc_assert (cfg_edge != NULL);
-  gcc_assert (cfg_edge->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE));
-
-  enum tree_code op = gimple_cond_code (cond_stmt);
-  tree lhs = gimple_cond_lhs (cond_stmt);
-  tree rhs = gimple_cond_rhs (cond_stmt);
-  if (cfg_edge->flags & EDGE_FALSE_VALUE)
-    op = invert_tree_comparison (op, false /* honor_nans */);
-  return add_constraint (path_var (lhs, m_stack_depth),
-			 op,
-			 path_var (rhs, m_stack_depth));
-}
-
-/* FIXME.  */
-
-bool
-path_state::apply_constraints_for_gswitch (const superedge &edge,
-					   const gswitch *switch_stmt)
-{
-  // FIXME: use an as_a for this cast:
-  const switch_cfg_superedge &switch_edge = (const switch_cfg_superedge &)edge;
-  path_var index (gimple_switch_index (switch_stmt), m_stack_depth);
-  tree case_label = switch_edge.get_case_label ();
-  gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
-  path_var lower_bound (CASE_LOW (case_label), m_stack_depth);
-  path_var upper_bound (CASE_HIGH (case_label), m_stack_depth);
-  if (lower_bound.m_tree)
-    {
-      if (upper_bound.m_tree)
-	{
-	  /* Range.  */
-	  if (!add_constraint (index, GE_EXPR, lower_bound))
-	    return false;
-	  return add_constraint (index, LE_EXPR, upper_bound);
-	}
-      else
-	/* Single-value.  */
-	return add_constraint (index, EQ_EXPR, lower_bound);
-    }
-  else
-    {
-      /* The default case.
-	 Add exclusions based on the other cases.  */
-      for (unsigned other_idx = 1;
-	   other_idx < gimple_switch_num_labels (switch_stmt);
-	   other_idx++)
-	{
-	  tree other_label = gimple_switch_label (switch_stmt,
-						  other_idx);
-	  path_var other_lower_bound (CASE_LOW (other_label), m_stack_depth);
-	  path_var other_upper_bound (CASE_HIGH (other_label), m_stack_depth);
-	  gcc_assert (other_lower_bound.m_tree);
-	  if (other_upper_bound.m_tree)
-	    {
-	      /* Exclude this range-valued case.
-		 For now, we just exclude the boundary values.
-		 TODO: exclude the values within the region.  */
-	      if (!add_constraint (index, NE_EXPR, other_lower_bound))
-		return false;
-	      if (!add_constraint (index, NE_EXPR, other_upper_bound))
-		return false;
-	    }
-	  else
-	    /* Exclude this single-valued case.  */
-	    if (!add_constraint (index, NE_EXPR, other_lower_bound))
-	      return false;
-	}
-      return true;
-    }
-}
-
-/* FIXME.  */
-
-bool
-path_state::add_constraint (path_var lhs, enum tree_code op, path_var rhs)
-{
-  equiv_class_id lhs_ec_id = get_or_add_equiv_class (lhs);
-  equiv_class_id rhs_ec_id = get_or_add_equiv_class (rhs);
-  return add_constraint (lhs_ec_id, op,rhs_ec_id);
-}
-
-/* FIXME.  */
-
-bool
-path_state::add_constraint (equiv_class_id lhs_ec_id,
-			    enum tree_code op,
-			    equiv_class_id rhs_ec_id)
-{
-  tristate t = eval_condition (lhs_ec_id, op, rhs_ec_id);
-
-  /* Discard constraints that are already known.  */
-  if (t.is_true ())
-    return true;
-
-  /* Reject unsatisfiable constraints.  */
-  if (t.is_false ())
-    return false;
-
-  gcc_assert (lhs_ec_id != rhs_ec_id);
-
-  /* For now, simply accumulate constraints, without attempting any further
-     optimization.  */
-  switch (op)
-    {
-    case EQ_EXPR:
-      {
-	/* Merge rhs_ec into lhs_ec.  */
-	equiv_class &lhs_ec_obj = lhs_ec_id.get_obj (*this);
-	const equiv_class &rhs_ec_obj = rhs_ec_id.get_obj (*this);
-
-	int i;
-	path_var *v;
-	FOR_EACH_VEC_ELT (rhs_ec_obj.m_vars, i, v)
-	  lhs_ec_obj.add (*v);
-
-	if (rhs_ec_obj.m_constant)
-	  {
-	    gcc_assert (lhs_ec_obj.m_constant == NULL);
-	    lhs_ec_obj.m_constant = rhs_ec_obj.m_constant;
-	  }
-
-	/* Merge any extra state.  */
-	extra_ec_state *lhs_extra_state = lhs_ec_obj.m_extra_state;
-	extra_ec_state *rhs_extra_state = rhs_ec_obj.m_extra_state;
-
-	/* How to merge two state objects?  */
-	gcc_assert (!(lhs_extra_state && rhs_extra_state));
-
-	if (lhs_extra_state == NULL && rhs_extra_state)
-	  lhs_ec_obj.m_extra_state = rhs_extra_state->clone ();
-
-	/* Drop rhs equivalence class, overwriting it with the
-	   final ec (which might be the same one).  */
-	equiv_class_id final_ec_id = m_equiv_classes.length () - 1;
-	equiv_class *old_ec = m_equiv_classes[rhs_ec_id.m_idx];
-	equiv_class *final_ec = m_equiv_classes.pop ();
-	if (final_ec != old_ec)
-	  m_equiv_classes[rhs_ec_id.m_idx] = final_ec;
-	delete old_ec;
-
-	/* Update the constraints.  */
-	constraint *c;
-	FOR_EACH_VEC_ELT (m_constraints, i, c)
-	  {
-	    /* Update references to the rhs_ec so that
-	       they refer to the lhs_ec.  */
-	    if (c->m_lhs == rhs_ec_id)
-	      c->m_lhs = lhs_ec_id;
-	    if (c->m_rhs == rhs_ec_id)
-	      c->m_rhs = lhs_ec_id;
-
-	    /* Renumber all constraints that refer to the final rhs_ec
-	       to the old rhs_ec, where the old final_ec now lives.  */
-	    if (c->m_lhs == final_ec_id)
-	      c->m_lhs = rhs_ec_id;
-	    if (c->m_rhs == final_ec_id)
-	      c->m_rhs = rhs_ec_id;
-	  }
-      }
-      break;
-    case GE_EXPR:
-      add_constraint_internal (rhs_ec_id, CONSTRAINT_LE, lhs_ec_id);
-      break;
-    case LE_EXPR:
-      add_constraint_internal (lhs_ec_id, CONSTRAINT_LE, rhs_ec_id);
-      break;
-    case NE_EXPR:
-      add_constraint_internal (lhs_ec_id, CONSTRAINT_NE, rhs_ec_id);
-      break;
-    case GT_EXPR:
-      add_constraint_internal (rhs_ec_id, CONSTRAINT_LT, lhs_ec_id);
-      break;
-    case LT_EXPR:
-      add_constraint_internal (lhs_ec_id, CONSTRAINT_LT, rhs_ec_id);
-      break;
-    default:
-      /* do nothing.  */
-      break;
-    }
-  validate ();
-  return true;
-}
-
-/* FIXME.  */
-
-void
-bound::ensure_closed (bool is_upper)
-{
-  if (!m_closed)
-    {
-      /* Offset by 1 in the appropriate direction.
-	 For example, convert 3 < x into 4 <= x,
-	 and convert x < 5 into x <= 4.  */
-      gcc_assert (CONSTANT_CLASS_P (m_constant));
-      m_constant = fold_build2 (is_upper ? MINUS_EXPR : PLUS_EXPR,
-				TREE_TYPE (m_constant),
-				m_constant, integer_one_node);
-      gcc_assert (CONSTANT_CLASS_P (m_constant));
-      m_closed = true;
-    }
-}
-
-/* FIXME.  */
-
-std::string
-range::to_str () const
-{
-  std::string result = expr_to_string (m_lower_bound.m_constant);
-  result += " <";
-  if (m_lower_bound.m_closed)
-    result += "=";
-  result += " x <";
-  if (m_upper_bound.m_closed)
-    result += "=";
-  result += " ";
-  result += expr_to_string (m_upper_bound.m_constant);
-  return result;  // TODO
-}
-
-/* FIXME.  */
-
-bool
-range::constrained_to_single_element (tree *out)
-{
-  if (!INTEGRAL_TYPE_P (TREE_TYPE (m_lower_bound.m_constant)))
-    return false;
-  if (!INTEGRAL_TYPE_P (TREE_TYPE (m_upper_bound.m_constant)))
-    return false;
-  // FIXME: also check the endpoint
-
-  /* Convert any open bounds to closed bounds.  */
-  m_lower_bound.ensure_closed (false);
-  m_upper_bound.ensure_closed (true);
-
-  // Are they equal?
-  tree comparison
-    = fold_build2 (EQ_EXPR, boolean_type_node,
-		   m_lower_bound.m_constant,
-		   m_upper_bound.m_constant);
-  if (comparison == boolean_true_node)
-    {
-      *out = m_lower_bound.m_constant;
-      return true;
-    }
-  else
-    return false;
-}
-
-
-/* FIXME.  */
-
-void
-path_state::add_constraint_internal (equiv_class_id lhs_id,
-				     enum constraint_op c_op,
-				     equiv_class_id rhs_id)
-{
-  /* Add the constraint.  */
-  m_constraints.safe_push (constraint (lhs_id, c_op, rhs_id));
-
-  if (c_op != CONSTRAINT_NE)
-    {
-      /* The following can potentially add EQ_EXPR facts, which could lead
-	 to ECs being merged, which would change the meaning of the EC IDs.
-	 Hence we need to do this via path vars.  */
-      path_var lhs = lhs_id.get_obj (*this).get_representative ();
-      path_var rhs = rhs_id.get_obj (*this).get_representative ();
-
-      /* We have LHS </<= RHS */
-
-      /* Handle transitivity of ordering by adding additional constraints
-	 based on what we already knew.
-
-	 So if we have already have:
-	   (a < b)
-	   (c < d)
-	 Then adding:
-	   (b < c)
-	 will also add:
-	   (a < c)
-	   (b < d)
-	 We need to recurse to ensure we also add:
-	   (a < d).
-	 We call the checked add_constraint to avoid adding constraints
-	 that are already present.  Doing so also ensures termination
-	 in the case of cycles.
-
-	 We also check for single-element ranges, adding EQ_EXPR facts
-	 where we discover them.  For example 3 < x < 5 implies
-	 that x == 4 (if x is an integer).  */
-      for (unsigned i = 0; i < m_constraints.length (); i++)
-	{
-	  const constraint *other = &m_constraints[i];
-	  if (other->is_ordering_p ())
-	    {
-	      /* Refresh the EC IDs, in case any mergers have happened.  */
-	      lhs_id = get_or_add_equiv_class (lhs);
-	      rhs_id = get_or_add_equiv_class (rhs);
-
-	      tree lhs_const = lhs_id.get_obj (*this).m_constant;
-	      tree rhs_const = rhs_id.get_obj (*this).m_constant;
-	      tree other_lhs_const
-		= other->m_lhs.get_obj (*this).m_constant;
-	      tree other_rhs_const
-		= other->m_rhs.get_obj (*this).m_constant;
-
-	      /* We have "LHS </<= RHS" and "other.lhs </<= other.rhs".  */
-
-	      /* If we have LHS </<= RHS and RHS </<= LHS, then we have a
-		 cycle.  */
-	      if (rhs_id == other->m_lhs
-		  && other->m_rhs == lhs_id)
-		{
-		  /* We must have equality for this to be possible.  */
-		  gcc_assert (c_op == CONSTRAINT_LE
-			      && other->m_op == CONSTRAINT_LE);
-		  add_constraint (lhs_id, EQ_EXPR, rhs_id);
-		  /* Adding an equality will merge the two ECs and potentially
-		     reorganize the constraints.  Stop iterating.  */
-		  return;
-		}
-	      /* Otherwise, check for transitivity.  */
-	      if (rhs_id == other->m_lhs)
-		{
-		  /* With RHS == other.lhs, we have:
-		     "LHS </<= (RHS, other.lhs) </<= other.rhs"
-		     and thus this implies "LHS </<= other.rhs".  */
-
-		  /* Do we have a tightly-constrained range?  */
-		  if (lhs_const
-		      && !rhs_const
-		      && INTEGRAL_TYPE_P (TREE_TYPE (rhs.m_tree))
-		      && other_rhs_const)
-		    {
-		      range r (bound (lhs_const, c_op == CONSTRAINT_LE),
-			       bound (other_rhs_const,
-				      other->m_op == CONSTRAINT_LE));
-		      tree constant;
-		      if (r.constrained_to_single_element (&constant))
-			{
-			  add_constraint
-			    (rhs_id, EQ_EXPR,
-			     get_or_add_equiv_class (path_var (constant, 0)));
-			  return;
-			}
-		    }
-		  /* Otherwise, add the constraint implied by transitivity.  */
-		  enum tree_code new_op
-		    = ((c_op == CONSTRAINT_LE && other->m_op == CONSTRAINT_LE)
-		       ? LE_EXPR : LT_EXPR);
-		  add_constraint (lhs_id, new_op, other->m_rhs);
-		}
-	      else if (other->m_rhs == lhs_id)
-		{
-		  /* With other.rhs == LHS, we have:
-		     "other.lhs </<= (other.rhs, LHS) </<= RHS"
-		     and thus this implies "other.lhs </<= RHS".  */
-
-		  /* Do we have a tightly-constrained range?  */
-		  if (other_lhs_const
-		      && !lhs_const
-		      && INTEGRAL_TYPE_P (TREE_TYPE (lhs.m_tree))
-		      && rhs_const)
-		    {
-		      range r (bound (other_lhs_const,
-				      other->m_op == CONSTRAINT_LE),
-			       bound (rhs_const,
-				      c_op == CONSTRAINT_LE));
-		      tree constant;
-		      if (r.constrained_to_single_element (&constant))
-			{
-			  add_constraint
-			    (lhs_id, EQ_EXPR,
-			     get_or_add_equiv_class (path_var (constant, 0)));
-			  return;
-			}
-		    }
-		  /* Otherwise, add the constraint implied by transitivity.  */
-		  enum tree_code new_op
-		    = ((c_op == CONSTRAINT_LE && other->m_op == CONSTRAINT_LE)
-		       ? LE_EXPR : LT_EXPR);
-		  add_constraint (other->m_lhs, new_op, rhs_id);
-		}
-	    }
-	}
-    }
-}
-
-/* FIXME.  */
-
-bool
-path_state::get_equiv_class (path_var pv, equiv_class_id *out) const
-{
-  gcc_assert (pv.m_tree);
-
-  if (CONSTANT_CLASS_P (pv.m_tree))
-    {
-      // FIXME: we want to ensure that constants that are equal are treated as equal here
-      int i;
-      equiv_class *ec;
-      FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-	if (pv.m_tree == ec->m_constant)
-	  {
-	    *out = equiv_class_id (i);
-	    return true;
-	  }
-    }
-  else
-    {
-      /* FIXME: probably should be a map, rather than these lookups.  */
-      int i;
-      equiv_class *ec;
-      FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-	{
-	  int j;
-	  path_var *v;
-	  FOR_EACH_VEC_ELT (ec->m_vars, j, v)
-	    if (*v == pv)
-	      {
-		*out = equiv_class_id (i);
-		return true;
-	      }
-	}
-    }
-  return false;
-}
-
-/* FIXME.  */
-
-equiv_class_id
-path_state::get_or_add_equiv_class (path_var pv)
-{
-  gcc_assert (pv.m_tree);
-
-  equiv_class_id result (-1);
-  if (get_equiv_class (pv, &result))
-    return result;
-
-  /* Not found.  */
-  equiv_class *new_ec = new equiv_class ();
-  new_ec->add (pv);
-  m_equiv_classes.safe_push (new_ec);
-
-  equiv_class_id new_id (m_equiv_classes.length () - 1);
-
-  if (CONSTANT_CLASS_P (pv.m_tree))
-    {
-      /* If we have a new EC for a constant, add constraints comparing this
-	 to other constants we may have (so that we accumulate the transitive
-	 closure of all constraints on constants as the constants are
-	 added).  */
-      for (equiv_class_id other_id (0); other_id.m_idx < new_id.m_idx;
-	   other_id.m_idx++)
-	{
-	  const equiv_class &other_ec = other_id.get_obj (*this);
-	  if (other_ec.m_constant)
-	    {
-	      /* If we have two ECs, both with constants, the constants must be
-		 non-equal (or they would be in the same EC).
-		 Determine the direction of the inequality, and record that
-		 fact.  */
-	      tree lt
-		= fold_build2 (LT_EXPR, boolean_type_node,
-			       new_ec->m_constant, other_ec.m_constant);
-	      //gcc_assert (lt == boolean_true_node || lt == boolean_false_node);
-	      // not true for int vs float comparisons
-	      if (lt == boolean_true_node)
-		add_constraint_internal (new_id, CONSTRAINT_LT, other_id);
-	      else if (lt == boolean_false_node)
-		add_constraint_internal (other_id, CONSTRAINT_LT, new_id);
-	      /* Refresh new_id, in case ECs were merged.  PV should always
-		 be present by now, so this should never lead to a
-		 recursion.  */
-	      new_id = get_or_add_equiv_class (pv);
-	    }
-	}
-    }
-
-  return new_id;
-}
-
-/* FIXME.  */
-/* For implementing "__analyzer_eval".  */
-
-tristate
-path_state::dump_condition (tree lhs, enum tree_code op, tree rhs)
-{
-  equiv_class_id lhs_ec_id
-    = get_or_add_equiv_class (path_var (lhs, m_stack_depth));
-  equiv_class_id rhs_ec_id
-    = get_or_add_equiv_class (path_var (rhs, m_stack_depth));
-
-  return eval_condition (lhs_ec_id, op, rhs_ec_id);
-}
-
-/* FIXME.  */
-
-tristate
-path_state::eval_condition (equiv_class_id lhs_ec,
-			    enum tree_code op,
-			    equiv_class_id rhs_ec)
-{
-  if (lhs_ec == rhs_ec)
-    {
-      switch (op)
-	{
-	case EQ_EXPR:
-	case GE_EXPR:
-	case LE_EXPR:
-	  return tristate (tristate::TS_TRUE);
-
-	case NE_EXPR:
-	case GT_EXPR:
-	case LT_EXPR:
-	  return tristate (tristate::TS_FALSE);
-	default:
-	  break;
-	}
-    }
-
-  tree lhs_const = lhs_ec.get_obj (*this).get_any_constant ();
-  tree rhs_const = rhs_ec.get_obj (*this).get_any_constant ();
-  if (lhs_const && rhs_const)
-    {
-      tree comparison
-	= fold_build2 (op, boolean_type_node, lhs_const, rhs_const);
-      if (comparison == boolean_true_node)
-	return tristate (tristate::TS_TRUE);
-      if (comparison == boolean_false_node)
-	return tristate (tristate::TS_FALSE);
-    }
-
-  enum tree_code swapped_op = swap_tree_comparison (op);
-
-  int i;
-  constraint *c;
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    {
-      if (c->m_lhs == lhs_ec
-	  && c->m_rhs == rhs_ec)
-	{
-	  tristate result_for_constraint
-	    = eval_constraint_op_for_op (c->m_op, op);
-	  if (result_for_constraint.is_known ())
-	    return result_for_constraint;
-	}
-      /* Swapped operands.  */
-      if (c->m_lhs == rhs_ec
-	  && c->m_rhs == lhs_ec)
-	{
-	  tristate result_for_constraint
-	    = eval_constraint_op_for_op (c->m_op, swapped_op);
-	  if (result_for_constraint.is_known ())
-	    return result_for_constraint;
-	}
-    }
-
-  return tristate (tristate::TS_UNKNOWN);
-}
-
-/* Mark EC_ID as having escaped; walk other ECs that haven't yet been marked
-   as escaped, and determine if they've now escaped, if so, mark them,
-   recursively.
-   e.g. if we know "ptr" escapes, then "ptr->foo" escapes.  */
-
-void
-path_state::recursively_mark_as_escaping (equiv_class_id ec_id)
-{
-  equiv_class &ec = ec_id.get_obj (*this);
-  if (ec.m_escaped)
-    {
-      /* Nothing to do.  */
-      return;
-    }
-
-  ec.m_escaped = true;
-
-  /* Look for other ECs that haven't yet been marked as escaped.  */
-  int other_ec_idx;
-  equiv_class *other_ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, other_ec_idx, other_ec)
-    {
-      if (other_ec->m_escaped)
-	continue;
-
-      int var_idx;
-      path_var *v;
-      FOR_EACH_VEC_ELT (other_ec->m_vars, var_idx, v)
-	{
-	  gcc_assert (!CONSTANT_CLASS_P (v->m_tree));
-	  if (calc_escaped_p (*v))
-	    {
-	      recursively_mark_as_escaping (other_ec_idx);
-	      break;
-	    }
-	}
-    }
-
-  // TODO: selftests
-  // TODO: selftest involving a cycle
-}
-
-/* Determine if PV (or something that points to it) has been marked as
-   having escaped.  */
-
-bool
-path_state::calc_escaped_p (path_var pv)
-{
-  switch (TREE_CODE (pv.m_tree))
-    {
-    case COMPONENT_REF:
-    case MEM_REF:
-      return calc_escaped_p (path_var (TREE_OPERAND (pv.m_tree, 0),
-				       pv.m_stack_depth));
-    case SSA_NAME:
-      {
-	equiv_class_id ec_id (-1);
-	if (get_equiv_class (pv, &ec_id))
-	  return ec_id.get_obj (*this).m_escaped;
-      }
-      break;
-    default:
-      return false;
-    }
-
-  return false;
-}
-
-/* Delete any information about path_var instances identified by P.
-   Such instances are removed from equivalence classes, and any
-   redundant ECs and constraints are also removed.
-   Return the number of path_vars that are purged.  */
-
-int
-path_state::purge (const purge_criteria &p)
-{
-  int num_purged = 0;
-
-  /* Delete any path_vars identified by P within the various equivalence
-     classes.  */
-  for (unsigned ec_idx = 0; ec_idx < m_equiv_classes.length (); )
-    {
-      equiv_class *ec = m_equiv_classes[ec_idx];
-
-      int i;
-      path_var *pv;
-      bool delete_ec = false;
-      FOR_EACH_VEC_ELT (ec->m_vars, i, pv)
-	{
-	  if (p.should_purge_p (*pv))
-	    {
-	      num_purged++;
-	      if (ec->del (*pv))
-		if (!ec->m_constant)
-		  delete_ec = true;
-	    }
-	}
-
-      if (delete_ec)
-	{
-	  delete ec;
-	  m_equiv_classes.ordered_remove (ec_idx);
-
-	  /* Update the constraints, potentially removing some.  */
-	  for (unsigned con_idx = 0; con_idx < m_constraints.length (); )
-	    {
-	      constraint *c = &m_constraints[con_idx];
-
-	      /* Remove constraints that refer to the deleted EC.  */
-	      if (c->m_lhs == ec_idx
-		  || c->m_rhs == ec_idx)
-		{
-		  m_constraints.ordered_remove (con_idx);
-		}
-	      else
-		{
-		  /* Renumber constraints that refer to ECs that have
-		     had their idx changed.  */
-		  c->m_lhs.update_for_removal (ec_idx);
-		  c->m_rhs.update_for_removal (ec_idx);
-
-		  con_idx++;
-		}
-	    }
-	}
-      else
-	ec_idx++;
-    }
-
-  /* Now delete any constraints that are purely between constants.  */
-  for (unsigned con_idx = 0; con_idx < m_constraints.length (); )
-    {
-      constraint *c = &m_constraints[con_idx];
-      if (m_equiv_classes[c->m_lhs.m_idx]->m_vars.length () == 0
-	  && m_equiv_classes[c->m_rhs.m_idx]->m_vars.length () == 0)
-	m_constraints.ordered_remove (con_idx);
-      else
-	{
-	  con_idx++;
-	}
-    }
-
-  /* Finally, delete any ECs that purely contain constants and aren't
-     referenced by any constraints.  */
-  for (unsigned ec_idx = 0; ec_idx < m_equiv_classes.length (); )
-    {
-      equiv_class *ec = m_equiv_classes[ec_idx];
-      if (ec->m_vars.length () == 0)
-	{
-	  bool has_constraint = false;
-	  for (unsigned con_idx = 0; con_idx < m_constraints.length ();
-	       con_idx++)
-	    {
-	      constraint *c = &m_constraints[con_idx];
-	      if (c->m_lhs.m_idx == ec_idx
-		  || c->m_rhs.m_idx == ec_idx)
-		{
-		  has_constraint = true;
-		  break;
-		}
-	    }
-	  if (!has_constraint)
-	    {
-	      delete ec;
-	      m_equiv_classes.ordered_remove (ec_idx);
-
-	      /* Renumber constraints that refer to ECs that have
-		 had their idx changed.  */
-	      for (unsigned con_idx = 0; con_idx < m_constraints.length ();
-		   con_idx++)
-		{
-		  constraint *c = &m_constraints[con_idx];
-		  c->m_lhs.update_for_removal (ec_idx);
-		  c->m_rhs.update_for_removal (ec_idx);
-		}
-	      continue;
-	    }
-	}
-      ec_idx++;
-    }
-
-  validate ();
-
-  return num_purged;
-}
-
-/* FIXME.  */
-
-void
-path_state::validate () const
-{
-  // TODO: skip this in a release build
-
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    {
-      gcc_assert (ec);
-
-      int j;
-      path_var *pv;
-      FOR_EACH_VEC_ELT (ec->m_vars, j, pv)
-	{
-	  gcc_assert (!CONSTANT_CLASS_P (pv->m_tree));
-	  //gcc_assert (pv->m_stack_depth <= m_stack_depth);
-	}
-      if (ec->m_constant)
-	gcc_assert (CONSTANT_CLASS_P (ec->m_constant));
-      else
-	gcc_assert (ec->m_vars.length () > 0);
-    }
-
-  constraint *c;
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    {
-      gcc_assert (c->m_lhs.m_idx <= m_equiv_classes.length ());
-      gcc_assert (c->m_rhs.m_idx <= m_equiv_classes.length ());
-    }
-}
-
-// FIXME:
-void
-debug (const path_state &ps)
-{
-  fprintf (stderr, "%s\n", ps.to_str ().c_str ());
-}
-
-void
-inchash::add_path_var (path_var pv, hash &hstate)
-{
-  inchash::add_expr (pv.m_tree, hstate);
-  hstate.add_int (pv.m_stack_depth);
-}
-
-#if CHECKING_P
-
-namespace selftest {
-
-/* Attempt to add the constraint (LHS OP RHS) to PS.
-   Verify that PS remains satisfiable.  */
-
-#define ADD_SAT_CONSTRAINT(PS, LHS, OP, RHS)				\
-  SELFTEST_BEGIN_STMT							\
-    bool sat = (PS).add_constraint (LHS, OP, RHS);			\
-    ASSERT_TRUE (sat);							\
-  SELFTEST_END_STMT
-
-/* Attempt to add the constraint (LHS OP RHS) to PS.
-   Verify that the result is not satisfiable.  */
-
-#define ADD_UNSAT_CONSTRAINT(PS, LHS, OP, RHS)				\
-  SELFTEST_BEGIN_STMT							\
-    bool sat = (PS).add_constraint (LHS, OP, RHS);			\
-    ASSERT_FALSE (sat);							\
-  SELFTEST_END_STMT
-
-static void
-assert_condition (const location &loc,
-		  path_state &ps,
-		  path_var lhs, tree_code op, path_var rhs,
-		  tristate expected)
-{
-  equiv_class_id lhs_ec = ps.get_or_add_equiv_class (lhs);
-  equiv_class_id rhs_ec = ps.get_or_add_equiv_class (rhs);
-  tristate actual = ps.eval_condition (lhs_ec, op, rhs_ec);
-  ASSERT_EQ_AT (loc, actual, expected);
-}
-
-#define ASSERT_CONDITION_TRUE(PATH_STATE, LHS, OP, RHS) \
-  SELFTEST_BEGIN_STMT							\
-  assert_condition (SELFTEST_LOCATION, PATH_STATE, LHS, OP, RHS,	\
-		    tristate (tristate::TS_TRUE));		\
-  SELFTEST_END_STMT
-
-#define ASSERT_CONDITION_FALSE(PATH_STATE, LHS, OP, RHS) \
-  SELFTEST_BEGIN_STMT							\
-  assert_condition (SELFTEST_LOCATION, PATH_STATE, LHS, OP, RHS,	\
-		    tristate (tristate::TS_FALSE));		\
-  SELFTEST_END_STMT
-
-#define ASSERT_CONDITION_UNKNOWN(PATH_STATE, LHS, OP, RHS) \
-  SELFTEST_BEGIN_STMT							\
-  assert_condition (SELFTEST_LOCATION, PATH_STATE, LHS, OP, RHS,	\
-		    tristate (tristate::TS_UNKNOWN));		\
-  SELFTEST_END_STMT
-
-/* FIXME.  */
-
-static void
-test_constraint_conditions ()
-{
-  path_var int_42 (build_int_cst (integer_type_node, 42), 0);
-  path_var int_0 (build_int_cst (integer_type_node, 0), 0);
-
-  path_var x (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("x"),
-			  integer_type_node), 0);
-  path_var y (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("y"),
-			  integer_type_node), 0);
-  path_var z (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("z"),
-			  integer_type_node), 0);
-
-  /* Self-comparisons.  */
-  {
-    path_state ps;
-    ASSERT_CONDITION_TRUE (ps, x, EQ_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, x, LE_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, x, GE_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, x, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, x, LT_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, x, GT_EXPR, x);
-  }
-
-  /* x == y.  */
-  {
-    path_state ps;
-    ASSERT_CONDITION_UNKNOWN (ps, x, EQ_EXPR, y);
-
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, y);
-
-    ASSERT_CONDITION_TRUE (ps, x, EQ_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, LE_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, GE_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, LT_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, GT_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_TRUE (ps, y, EQ_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, LE_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, GE_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, y, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, y, LT_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, y, GT_EXPR, x);
-
-    /* Comparison with other var.  */
-    ASSERT_CONDITION_UNKNOWN (ps, x, EQ_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, LE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, NE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, LT_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GT_EXPR, z);
-  }
-
-  /* x == y, then y == z  */
-  {
-    path_state ps;
-    ASSERT_CONDITION_UNKNOWN (ps, x, EQ_EXPR, y);
-
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, y);
-    ADD_SAT_CONSTRAINT (ps, y, EQ_EXPR, z);
-
-    ASSERT_CONDITION_TRUE (ps, x, EQ_EXPR, z);
-    ASSERT_CONDITION_TRUE (ps, x, LE_EXPR, z);
-    ASSERT_CONDITION_TRUE (ps, x, GE_EXPR, z);
-    ASSERT_CONDITION_FALSE (ps, x, NE_EXPR, z);
-    ASSERT_CONDITION_FALSE (ps, x, LT_EXPR, z);
-    ASSERT_CONDITION_FALSE (ps, x, GT_EXPR, z);
-  }
-
-  /* x != y.  */
-  {
-    path_state ps;
-
-    ADD_SAT_CONSTRAINT (ps, x, NE_EXPR, y);
-
-    ASSERT_CONDITION_TRUE (ps, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, EQ_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, LE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, LT_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GT_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_TRUE (ps, y, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, y, EQ_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, LE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, GE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, LT_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, GT_EXPR, x);
-
-    /* Comparison with other var.  */
-    ASSERT_CONDITION_UNKNOWN (ps, x, EQ_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, LE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, NE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, LT_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GT_EXPR, z);
-  }
-
-  /* x < y.  */
-  {
-    path_state ps;
-
-    ADD_SAT_CONSTRAINT (ps, x, LT_EXPR, y);
-
-    ASSERT_CONDITION_TRUE (ps, x, LT_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, LE_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, EQ_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, GT_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, GE_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_FALSE (ps, y, LT_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, y, LE_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, y, EQ_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, GT_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, GE_EXPR, x);
-  }
-
-  /* x <= y.  */
-  {
-    path_state ps;
-
-    ADD_SAT_CONSTRAINT (ps, x, LE_EXPR, y);
-
-    ASSERT_CONDITION_UNKNOWN (ps, x, LT_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, LE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, NE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, EQ_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, GT_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GE_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_FALSE (ps, y, LT_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, LE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, NE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, EQ_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, GT_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, GE_EXPR, x);
-  }
-
-  /* x > y.  */
-  {
-    path_state ps;
-
-    ADD_SAT_CONSTRAINT (ps, x, GT_EXPR, y);
-
-    ASSERT_CONDITION_TRUE (ps, x, GT_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, GE_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, EQ_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, LT_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, LE_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_FALSE (ps, y, GT_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, y, GE_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (ps, y, EQ_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, LT_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, LE_EXPR, x);
-  }
-
-  /* x >= y.  */
-  {
-    path_state ps;
-
-    ADD_SAT_CONSTRAINT (ps, x, GE_EXPR, y);
-
-    ASSERT_CONDITION_UNKNOWN (ps, x, GT_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, GE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, NE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, EQ_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, LT_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, LE_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_FALSE (ps, y, GT_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, GE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, NE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, EQ_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (ps, y, LT_EXPR, x);
-    ASSERT_CONDITION_TRUE (ps, y, LE_EXPR, x);
-  }
-
-  // TODO: implied orderings
-
-  /* Constants.  */
-  {
-    path_state ps;
-    ASSERT_CONDITION_FALSE (ps, int_0, EQ_EXPR, int_42);
-    ASSERT_CONDITION_TRUE (ps, int_0, NE_EXPR, int_42);
-    ASSERT_CONDITION_TRUE (ps, int_0, LT_EXPR, int_42);
-    ASSERT_CONDITION_TRUE (ps, int_0, LE_EXPR, int_42);
-    ASSERT_CONDITION_FALSE (ps, int_0, GT_EXPR, int_42);
-    ASSERT_CONDITION_FALSE (ps, int_0, GE_EXPR, int_42);
-  }
-
-  /* x == 0, y == 42.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, int_0);
-    ADD_SAT_CONSTRAINT (ps, y, EQ_EXPR, int_42);
-
-    ASSERT_CONDITION_TRUE (ps, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, EQ_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, LE_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, GE_EXPR, y);
-    ASSERT_CONDITION_TRUE (ps, x, LT_EXPR, y);
-    ASSERT_CONDITION_FALSE (ps, x, GT_EXPR, y);
-  }
-
-  /* Unsatisfiable combinations.  */
-
-  /* x == y && x != y.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, y);
-    ADD_UNSAT_CONSTRAINT (ps, x, NE_EXPR, y);
-  }
-
-  /* x == 0 then x == 42.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, int_0);
-    ADD_UNSAT_CONSTRAINT (ps, x, EQ_EXPR, int_42);
-  }
-
-  /* x == 0 then x != 0.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, int_0);
-    ADD_UNSAT_CONSTRAINT (ps, x, NE_EXPR, int_0);
-  }
-
-  /* x == 0 then x > 0.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, int_0);
-    ADD_UNSAT_CONSTRAINT (ps, x, GT_EXPR, int_0);
-  }
-
-  /* x != y && x == y.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, x, NE_EXPR, y);
-    ADD_UNSAT_CONSTRAINT (ps, x, EQ_EXPR, y);
-  }
-
-  /* x <= y && x > y.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, x, LE_EXPR, y);
-    ADD_UNSAT_CONSTRAINT (ps, x, GT_EXPR, y);
-  }
-
-  // etc
-}
-
-/* FIXME.  */
-
-static void
-test_transitivity ()
-{
-  path_var int_42 (build_int_cst (integer_type_node, 42), 0);
-  path_var int_0 (build_int_cst (integer_type_node, 0), 0);
-
-  path_var a (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("a"),
-			  integer_type_node), 0);
-  path_var b (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("b"),
-			  integer_type_node), 0);
-  path_var c (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("c"),
-			  integer_type_node), 0);
-  path_var d (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("d"),
-			  integer_type_node), 0);
-
-  /* a == b, then c == d, then c == b.  */
-  {
-    path_state ps;
-    ASSERT_CONDITION_UNKNOWN (ps, a, EQ_EXPR, b);
-    ASSERT_CONDITION_UNKNOWN (ps, b, EQ_EXPR, c);
-    ASSERT_CONDITION_UNKNOWN (ps, c, EQ_EXPR, d);
-    ASSERT_CONDITION_UNKNOWN (ps, a, EQ_EXPR, d);
-
-    ADD_SAT_CONSTRAINT (ps, a, EQ_EXPR, b);
-    ASSERT_CONDITION_TRUE (ps, a, EQ_EXPR, b);
-
-    ADD_SAT_CONSTRAINT (ps, c, EQ_EXPR, d);
-    ASSERT_CONDITION_TRUE (ps, c, EQ_EXPR, d);
-    ASSERT_CONDITION_UNKNOWN (ps, a, EQ_EXPR, d);
-
-    ADD_SAT_CONSTRAINT (ps, c, EQ_EXPR, b);
-    ASSERT_CONDITION_TRUE (ps, c, EQ_EXPR, b);
-    ASSERT_CONDITION_TRUE (ps, a, EQ_EXPR, d);
-  }
-
-  /* Transitivity: "a < b", "b < c" should imply "a < c".  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, LT_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, b, LT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (ps, a, LT_EXPR, c);
-    ASSERT_CONDITION_FALSE (ps, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a <= b", "b < c" should imply "a < c".  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, LE_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, b, LT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (ps, a, LT_EXPR, c);
-    ASSERT_CONDITION_FALSE (ps, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a <= b", "b <= c" should imply "a <= c".  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, LE_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, b, LE_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (ps, a, LE_EXPR, c);
-    ASSERT_CONDITION_UNKNOWN (ps, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a > b", "b > c" should imply "a > c".  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GT_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, b, GT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (ps, a, GT_EXPR, c);
-    ASSERT_CONDITION_FALSE (ps, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a >= b", "b > c" should imply " a > c".  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GE_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, b, GT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (ps, a, GT_EXPR, c);
-    ASSERT_CONDITION_FALSE (ps, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a >= b", "b >= c" should imply "a >= c".  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GE_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, b, GE_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (ps, a, GE_EXPR, c);
-    ASSERT_CONDITION_UNKNOWN (ps, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "(a < b)", "(c < d)", "(b < c)" should
-     imply the easy cases:
-       (a < c)
-       (b < d)
-     but also that:
-       (a < d).  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, LT_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, c, LT_EXPR, d);
-    ADD_SAT_CONSTRAINT (ps, b, LT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (ps, a, LT_EXPR, c);
-    ASSERT_CONDITION_TRUE (ps, b, LT_EXPR, d);
-    ASSERT_CONDITION_TRUE (ps, a, LT_EXPR, d);
-  }
-
-  /* Transitivity: "a >= b", "b >= a" should imply that a == b.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GE_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, b, GE_EXPR, a);
-
-    // TODO:
-    ASSERT_CONDITION_TRUE (ps, a, EQ_EXPR, b);
-  }
-
-  /* Transitivity: "a >= b", "b > a" should be impossible.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GE_EXPR, b);
-    ADD_UNSAT_CONSTRAINT (ps, b, GT_EXPR, a);
-  }
-
-  /* Transitivity: "a >= b", "b >= c", "c >= a" should imply
-     that a == b == c.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GE_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, b, GE_EXPR, c);
-    ADD_SAT_CONSTRAINT (ps, c, GE_EXPR, a);
-
-    ASSERT_CONDITION_TRUE (ps, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a > b", "b > c", "c > a"
-     should be impossible.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GT_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, b, GT_EXPR, c);
-    ADD_UNSAT_CONSTRAINT (ps, c, GT_EXPR, a);
-  }
-
-}
-
-/* FIXME.  */
-
-static void
-test_constant_comparisons ()
-{
-  path_var int_3 (build_int_cst (integer_type_node, 3), 0);
-  path_var int_4 (build_int_cst (integer_type_node, 4), 0);
-  path_var int_5 (build_int_cst (integer_type_node, 5), 0);
-
-  path_var int_1023 (build_int_cst (integer_type_node, 1023), 0);
-  path_var int_1024 (build_int_cst (integer_type_node, 1024), 0);
-
-  path_var a (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("a"),
-			  integer_type_node), 0);
-  path_var b (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("b"),
-			  integer_type_node), 0);
-
-  /* Given a >= 1024, then a <= 1023 should be impossible.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GE_EXPR, int_1024);
-    ADD_UNSAT_CONSTRAINT (ps, a, LE_EXPR, int_1023);
-  }
-
-  /* a > 4.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GT_EXPR, int_4);
-    ASSERT_CONDITION_TRUE (ps, a, GT_EXPR, int_4);
-    ASSERT_CONDITION_TRUE (ps, a, NE_EXPR, int_3);
-    ASSERT_CONDITION_UNKNOWN (ps, a, NE_EXPR, int_5);
-  }
-
-  /* a <= 4.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, LE_EXPR, int_4);
-    ASSERT_CONDITION_FALSE (ps, a, GT_EXPR, int_4);
-    ASSERT_CONDITION_FALSE (ps, a, GT_EXPR, int_5);
-    ASSERT_CONDITION_UNKNOWN (ps, a, NE_EXPR, int_3);
-  }
-
-  /* If "a > b" and "a == 3", then "b == 4" ought to be unsatisfiable.  */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, a, GT_EXPR, b);
-    ADD_SAT_CONSTRAINT (ps, a, EQ_EXPR, int_3);
-    ADD_UNSAT_CONSTRAINT (ps, b, EQ_EXPR, int_4);
-  }
-
-  /* Various tests of int ranges where there is only one possible candidate.  */
-  {
-    /* If "a <= 4" && "a > 3", then "a == 4",
-       assuming a is of integral type.  */
-    {
-      path_state ps;
-      ADD_SAT_CONSTRAINT (ps, a, LE_EXPR, int_4);
-      ADD_SAT_CONSTRAINT (ps, a, GT_EXPR, int_3);
-      ASSERT_CONDITION_TRUE (ps, a, EQ_EXPR, int_4);
-    }
-
-    /* If "a > 3" && "a <= 4", then "a == 4",
-       assuming a is of integral type.  */
-    {
-      path_state ps;
-      ADD_SAT_CONSTRAINT (ps, a, GT_EXPR, int_3);
-      ADD_SAT_CONSTRAINT (ps, a, LE_EXPR, int_4);
-      ASSERT_CONDITION_TRUE (ps, a, EQ_EXPR, int_4);
-    }
-    /* If "a > 3" && "a < 5", then "a == 4",
-       assuming a is of integral type.  */
-    {
-      path_state ps;
-      ADD_SAT_CONSTRAINT (ps, a, GT_EXPR, int_3);
-      ADD_SAT_CONSTRAINT (ps, a, LT_EXPR, int_5);
-      ASSERT_CONDITION_TRUE (ps, a, EQ_EXPR, int_4);
-    }
-    /* If "a >= 4" && "a < 5", then "a == 4",
-       assuming a is of integral type.  */
-    {
-      path_state ps;
-      ADD_SAT_CONSTRAINT (ps, a, GE_EXPR, int_4);
-      ADD_SAT_CONSTRAINT (ps, a, LT_EXPR, int_5);
-      ASSERT_CONDITION_TRUE (ps, a, EQ_EXPR, int_4);
-    }
-    /* If "a >= 4" && "a <= 4", then "a == 4".  */
-    {
-      path_state ps;
-      ADD_SAT_CONSTRAINT (ps, a, GE_EXPR, int_4);
-      ADD_SAT_CONSTRAINT (ps, a, LE_EXPR, int_4);
-      ASSERT_CONDITION_TRUE (ps, a, EQ_EXPR, int_4);
-    }
-  }
-
-#if 0
-  /* As above, but for float.   */
-  {
-    path_state ps;
-    ADD_SAT_CONSTRAINT (ps, f, GT_EXPR, float_3);
-    ADD_SAT_CONSTRAINT (ps, f, LE_EXPR, float_4);
-    ASSERT_CONDITION_UNKNOWN (ps, f, EQ_EXPR, int_4);
-  }
-#endif
-}
-
-/* FIXME.  */
-
-static void
-test_constraint_impl ()
-{
-  path_var int_42 (build_int_cst (integer_type_node, 42), 0);
-  path_var int_0 (build_int_cst (integer_type_node, 0), 0);
-
-  path_var x (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("x"),
-			  integer_type_node), 0);
-  path_var y (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("y"),
-			  integer_type_node), 0);
-  path_var z (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("z"),
-			  integer_type_node), 0);
-
-  /* x == y.  */
-  {
-    path_state ps;
-
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, y);
-
-    /* Assert various things about the insides of ps.  */
-    ASSERT_EQ (ps.m_constraints.length (), 0);
-    ASSERT_EQ (ps.m_equiv_classes.length (), 1);
-  }
-
-  /* y <= z; x == y.  */
-  {
-    path_state ps;
-    ASSERT_CONDITION_UNKNOWN (ps, x, EQ_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GE_EXPR, z);
-
-    ADD_SAT_CONSTRAINT (ps, y, GE_EXPR, z);
-    ASSERT_CONDITION_TRUE (ps, y, GE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GE_EXPR, z);
-
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, y);
-
-    /* Assert various things about the insides of ps.  */
-    ASSERT_EQ (ps.m_constraints.length (), 1);
-    ASSERT_EQ (ps.m_equiv_classes.length (), 2);
-
-    /* Ensure that we merged the constraints.  */
-    ASSERT_CONDITION_TRUE (ps, x, GE_EXPR, z);
-  }
-
-  /* y <= z; y == x.  */
-  {
-    path_state ps;
-    ASSERT_CONDITION_UNKNOWN (ps, x, EQ_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GE_EXPR, z);
-
-    ADD_SAT_CONSTRAINT (ps, y, GE_EXPR, z);
-    ASSERT_CONDITION_TRUE (ps, y, GE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (ps, x, GE_EXPR, z);
-
-    ADD_SAT_CONSTRAINT (ps, y, EQ_EXPR, x);
-
-    /* Assert various things about the insides of ps.  */
-    ASSERT_EQ (ps.m_constraints.length (), 1);
-    ASSERT_EQ (ps.m_equiv_classes.length (), 2);
-
-    /* Ensure that we merged the constraints.  */
-    ASSERT_CONDITION_TRUE (ps, x, GE_EXPR, z);
-  }
-
-  /* x == 0, then x != 42.  */
-  {
-    path_state ps;
-
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, int_0);
-    ADD_SAT_CONSTRAINT (ps, x, NE_EXPR, int_42);
-
-    /* Assert various things about the insides of ps.  */
-    ASSERT_EQ (ps.m_constraints.length (), 1);
-    ASSERT_EQ (ps.m_equiv_classes.length (), 2);
-    ASSERT_EQ (ps.m_constraints[0].m_lhs, ps.get_or_add_equiv_class (int_0));
-    ASSERT_EQ (ps.m_constraints[0].m_rhs, ps.get_or_add_equiv_class (int_42));
-    ASSERT_EQ (ps.m_constraints[0].m_op, CONSTRAINT_LT);
-  }
-
-  // TODO: selftest for merging ecs "in the middle"
-  // where a non-final one gets overwritten
-
-  // TODO: selftest where there are pre-existing constraints
-}
-
-/* FIXME.  */
-
-static void
-test_assignment ()
-{
-  path_var int_0 (build_int_cst (integer_type_node, 0), 0);
-
-  path_var x (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("x"),
-			  integer_type_node), 0);
-  path_var y (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("y"),
-			  integer_type_node), 0);
-  /* "x == 0", then use of y, then "y = 0".  */
-  path_state ps;
-  ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, int_0);
-  ASSERT_CONDITION_UNKNOWN (ps, y, EQ_EXPR, int_0);
-  ps.on_assignment (y, int_0);
-  ASSERT_CONDITION_TRUE (ps, y, EQ_EXPR, int_0);
-  ASSERT_CONDITION_TRUE (ps, y, EQ_EXPR, x);
-}
-
-/* FIXME.  */
-
-static void
-test_stack_frames ()
-{
-  path_var int_42 (build_int_cst (integer_type_node, 42), 0);
-  path_var int_0 (build_int_cst (integer_type_node, 0), 0);
-
-  /* "a" in the parent frame.  */
-  path_var a (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("a"),
-			  integer_type_node), 0);
-  /* "x" in a child frame.  */
-  path_var x (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("x"),
-			  integer_type_node), 1);
-
-  {
-    path_state ps;
-    ps.m_stack_depth = 1;
-
-    /* x == a.  */
-    ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, a);
-    ASSERT_CONDITION_TRUE (ps, x, EQ_EXPR, a);
-
-    /* Pop the stack.  */
-    ps.pop_stack_frame ();
-    ASSERT_CONDITION_UNKNOWN (ps, x, EQ_EXPR, a);
-  }
-}
-
-/* Check that operator== and hashing works as expected for the
-   various types.  */
-
-static void
-test_equality ()
-{
-  path_var int_42 (build_int_cst (integer_type_node, 42), 0);
-  path_var int_0 (build_int_cst (integer_type_node, 0), 0);
-
-  path_var x (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("x"),
-			  integer_type_node), 0);
-  path_var y (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("y"),
-			  integer_type_node), 0);
-  path_var z (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("z"),
-			  integer_type_node), 0);
-
-  {
-    path_state ps0;
-    path_state ps1;
-
-    ASSERT_EQ (ps0.hash (), ps1.hash ());
-    ASSERT_EQ (ps0, ps1);
-
-    ADD_SAT_CONSTRAINT (ps1, x, EQ_EXPR, y);
-    ASSERT_NE (ps0.hash (), ps1.hash ());
-    ASSERT_NE (ps0, ps1);
-
-    path_state ps2;
-    /* Make the same change to ps2.  */
-    ADD_SAT_CONSTRAINT (ps2, x, EQ_EXPR, y);
-    ASSERT_EQ (ps1.hash (), ps2.hash ());
-    ASSERT_EQ (ps1, ps2);
-  }
-}
-
-/* A subclass of purge_criteria for selftests: purge all path_var instances.  */
-
-class purge_all_path_vars : public purge_criteria
-{
-public:
-  bool should_purge_p (path_var) const FINAL OVERRIDE
-  {
-    return true;
-  }
-};
-
-/* Check that path_state objects can "forget".  */
-
-static void
-test_purging ()
-{
-  path_var int_42 (build_int_cst (integer_type_node, 42), 0);
-  path_var int_0 (build_int_cst (integer_type_node, 0), 0);
-
-  path_var x (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("x"),
-			  integer_type_node), 0);
-  path_var y (build_decl (UNKNOWN_LOCATION, PARM_DECL,
-			  get_identifier ("y"),
-			  integer_type_node), 0);
-
-  {
-    path_state ps0;
-    path_state ps1;
-
-    ADD_SAT_CONSTRAINT (ps1, x, EQ_EXPR, y);
-    ASSERT_NE (ps0, ps1);
-
-    purge_one_path_var px (x);
-    ps1.purge (px);
-
-    purge_one_path_var py (y);
-    ps1.purge (py);
-
-    ASSERT_EQ (ps0, ps1);
-  }
-
-  {
-    path_state ps0;
-    path_state ps1;
-
-    ADD_SAT_CONSTRAINT (ps1, x, EQ_EXPR, int_42);
-    ASSERT_NE (ps0, ps1);
-
-    purge_one_path_var px (x);
-    ps1.purge (px);
-
-    ASSERT_EQ (ps0, ps1);
-  }
-
-  {
-    path_state ps0;
-    path_state ps1;
-
-    ADD_SAT_CONSTRAINT (ps1, x, GE_EXPR, int_0);
-    ADD_SAT_CONSTRAINT (ps1, x, LE_EXPR, int_42);
-    ASSERT_NE (ps0, ps1);
-
-    purge_one_path_var px (x);
-    ps1.purge (px);
-
-    ASSERT_EQ (ps0, ps1);
-  }
-
-  {
-    path_state ps0;
-    path_state ps1;
-
-    ADD_SAT_CONSTRAINT (ps1, x, NE_EXPR, int_42);
-    ADD_SAT_CONSTRAINT (ps1, y, NE_EXPR, int_0);
-    ASSERT_NE (ps0, ps1);
-
-    purge_one_path_var px (x);
-    ps1.purge (px);
-    ASSERT_NE (ps0, ps1);
-
-    ASSERT_CONDITION_TRUE (ps1, y, NE_EXPR, int_0);
-  }
-
-  {
-    path_state ps0;
-    path_state ps1;
-
-    ADD_SAT_CONSTRAINT (ps1, x, NE_EXPR, int_42);
-    ADD_SAT_CONSTRAINT (ps1, y, NE_EXPR, int_0);
-    ASSERT_NE (ps0, ps1);
-
-    purge_all_path_vars p;
-    ps1.purge (p);
-    ASSERT_EQ (ps0, ps1);
-  }
-
-}
-
-
-/* Run all of the selftests within this file.  */
-
-void
-analyzer_path_state_cc_tests ()
-{
-  test_constraint_conditions ();
-  test_transitivity ();
-  test_constant_comparisons ();
-  test_constraint_impl ();
-  test_assignment ();
-  test_stack_frames ();
-  test_equality ();
-  test_purging ();
-}
-
-} // namespace selftest
-
-#endif /* CHECKING_P */
diff --git a/gcc/analyzer/path-state.h b/gcc/analyzer/path-state.h
index b53b511..fd836c1 100644
--- a/gcc/analyzer/path-state.h
+++ b/gcc/analyzer/path-state.h
@@ -21,47 +21,6 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_ANALYZER_PATH_STATE_H
 #define GCC_ANALYZER_PATH_STATE_H
 
-class superedge;
-class call_superedge;
-class return_superedge;
-
-/* FIXME: put everything to do with path_state in its own namespace
-   while building up the alternative impl.  */
-
-namespace psn {
-
-/* One of the end-points of a range.  */
-
-struct bound
-{
-  bound () : m_constant (NULL_TREE), m_closed (false) {}
-  bound (tree constant, bool closed)
-  : m_constant (constant), m_closed (closed) {}
-
-  void ensure_closed (bool is_upper);
-
-  tree m_constant;
-  bool m_closed;
-};
-
-/* FIXME.  */
-
-struct range
-{
-  range () : m_lower_bound (), m_upper_bound () {}
-  range (const bound &lower, const bound &upper)
-  : m_lower_bound (lower), m_upper_bound (upper) {}
-
-  std::string to_str () const;
-
-  bool constrained_to_single_element (tree *out);
-
-  bound m_lower_bound;
-  bound m_upper_bound;
-};
-
-} // namespace psn
-
 /* A tree, extended with stack frame information for locals, so that
    we can distinguish between different values of locals within a potentially
    recursive callstack.  */
@@ -88,226 +47,6 @@ public:
   int m_stack_depth; // or -1 for globals?
 };
 
-/* FIXME: put everything to do with path_state in its own namespace
-   while building up the alternative impl.  */
-
-namespace psn {
-
-/* Abstract base class for specifying how state should be purged.  */
-
-class purge_criteria
-{
-public:
-  virtual ~purge_criteria () {}
-  virtual bool should_purge_p (path_var pv) const = 0;
-};
-
-} // namespace psn
-
-
-class path_state;
-
-namespace psn {
-
-/* Optional per-engine extra state (to avoid making path_state a
-   template).  */
-
-class extra_ec_state
-{
- public:
-  virtual ~extra_ec_state () {}
-  virtual extra_ec_state *clone () const = 0;
-  virtual std::string to_str () const = 0;
-  virtual hashval_t hash () const = 0;
-  virtual bool operator== (const extra_ec_state &other) const = 0;
-};
-
-/* FIXME.  */
-
-class equiv_class
-{
-public:
-  equiv_class ();
-  equiv_class (const equiv_class &other);
-  ~equiv_class ();
-
-  std::string to_str () const;
-  hashval_t hash () const;
-  bool operator== (const equiv_class &other);
-
-  void add (path_var v);
-  bool del (path_var v);
-
-  tree get_any_constant () const { return m_constant; }
-
-  int get_min_stack_depth () const;
-
-  path_var get_representative () const;
-
-  /* An equivalence class can contain at most one constant.  */
-  tree m_constant;
-
-  // FIXME: this is a bad representation, probably should be a set:
-  auto_vec<path_var> m_vars;
-
-  /* Has this value escaped from this function?  */
-  bool m_escaped;
-
-  /* Optional per-engine extra state (to avoid making path_state a
-     template).  */
-  extra_ec_state *m_extra_state;
-};
-
-enum constraint_op
-{
-  CONSTRAINT_NE,
-  CONSTRAINT_LT,
-  CONSTRAINT_LE
-};
-
-const char *constraint_op_code (enum constraint_op c_op);
-
-class equiv_class_id
-{
-public:
-  equiv_class_id (unsigned idx) : m_idx (idx) {}
-  const equiv_class &get_obj (const path_state &ps) const;
-  equiv_class &get_obj (path_state &ps) const;
-
-  bool operator== (const equiv_class_id &other) const
-  {
-    return m_idx == other.m_idx;
-  }
-  bool operator!= (const equiv_class_id &other) const
-  {
-    return m_idx != other.m_idx;
-  }
-
-  std::string to_str () const
-  {
-    return std::string ("ec") + std::to_string (m_idx);
-  }
-
-  void update_for_removal (equiv_class_id other)
-  {
-    if (m_idx > other.m_idx)
-      m_idx--;
-  }
-
-  unsigned m_idx;
-};
-
-class constraint {
- public:
-  constraint (equiv_class_id lhs, enum constraint_op c_op, equiv_class_id rhs)
-    : m_lhs (lhs), m_op (c_op), m_rhs (rhs) {}
-
-  std::string to_str (const path_state &ps) const;
-  hashval_t hash () const;
-  bool operator== (const constraint &other) const;
-
-  /* Is this an ordering, rather than a "!=".  */
-  bool is_ordering_p () const
-  {
-    return m_op != CONSTRAINT_NE;
-  }
-
-  equiv_class_id m_lhs;
-  enum constraint_op m_op;
-  equiv_class_id m_rhs;
-};
-
-} // namespace psn
-
-/* The state of a particular point at one point in the traversal (not including
-   state-machine information).  */
-
-class path_state
-{
-public:
-  path_state () : m_stack_depth (0) {}
-  path_state (const path_state &other);
-  ~path_state ();
-
-  path_state& operator= (const path_state &other);
-
-  hashval_t hash () const;
-  bool operator== (const path_state &other) const;
-  bool operator!= (const path_state &other) const
-  {
-    return !(*this == other);
-  }
-
-  std::string to_str () const;
-
-  const psn::equiv_class &get_equiv_class_by_index (unsigned idx) const
-  {
-    return *m_equiv_classes[idx];
-  }
-  psn::equiv_class &get_equiv_class_by_index (unsigned idx)
-  {
-    return *m_equiv_classes[idx];
-  }
-
-  psn::equiv_class &get_equiv_class (path_var pv)
-  {
-    psn::equiv_class_id ec_id = get_or_add_equiv_class (pv);
-    return ec_id.get_obj (*this);
-  }
-
-  path_var make_path_var (tree expr) const
-  {
-    return path_var (expr, m_stack_depth);
-  }
-
-  void on_assignment (path_var lhs, path_var rhs);
-
-  bool apply_constraints_for_edge (const superedge &edge,
-				   const gimple *last_stmt);
-
-  bool add_constraint (path_var lhs, enum tree_code op, path_var rhs);
-
-  bool add_constraint (psn::equiv_class_id lhs_ec_id,
-		       enum tree_code op,
-		       psn::equiv_class_id rhs_ec_id);
-
-  //private:
-  bool apply_constraints_for_call (const call_superedge& edge);
-
-  bool apply_constraints_for_return (const return_superedge& edge);
-
-  void pop_stack_frame ();
-
-  bool apply_constraints_for_gcond (const superedge &edge,
-				    const gcond *cond_stmt);
-  bool apply_constraints_for_gswitch (const superedge &edge,
-				      const gswitch *switch_stmt);
-  bool get_equiv_class (path_var pv, psn::equiv_class_id *out) const;
-  psn::equiv_class_id get_or_add_equiv_class (path_var vr);
-  tristate eval_condition (psn::equiv_class_id lhs,
-			   enum tree_code op,
-			   psn::equiv_class_id rhs);
-
-  /* For implementing "__analyzer_eval".  */
-  tristate dump_condition (tree lhs, enum tree_code op, tree rhs);
-
-  void recursively_mark_as_escaping (psn::equiv_class_id ec_id);
-  bool calc_escaped_p (path_var pv);
-
-  int purge (const psn::purge_criteria &p);
-
-  void validate () const;
-
-  auto_vec<psn::equiv_class *> m_equiv_classes;
-  auto_vec<psn::constraint> m_constraints;
-  int m_stack_depth;
-
- private:
-  void add_constraint_internal (psn::equiv_class_id lhs_id,
-				enum psn::constraint_op c_op,
-				psn::equiv_class_id rhs_id);
-};
-
 namespace inchash
 {
   extern void add_path_var (path_var pv, hash &hstate);
-- 
1.8.5.3

