class region_model_manager consolidates and manages svalue and region
instances.  I'm about to add various new subclasses of symbolic::node,
each with their own manager class.

This patch adds a new symbolic::node_manager class to be a "hub" that
all the various node manager classes will be able to access.

For now, we merely moves region_model_manager from being a top-level
object to being one owned by node_manager; followup patches will add
more managers for more kinds of symbolic::node.

gcc/analyzer/ChangeLog:
        * access-diagram.cc: Update for introduction of
        symbolic::node_manager, creating node_manager and
        accessing its region_model_manager rather than creating
        the latter directly.
        * common.h (class symbolic::node_manager): New forward decl.
        (class call_string): Likewise.
        * constraint-manager.cc: Update for introduction of
        symbolic::node_manager, creating node_manager instances and
        accessing their region_model_manager rather than creating
        instances of the latter directly.  Update for region_model ctor
        taking a node_manager & rather than a region_model_manager *.
        * diagnostic-manager.cc: Likewise.
        * engine.cc: Likewise.
        * program-point.cc: Likewise.
        * program-state.cc: Likewise.
        * program-state.h: Likewise.
        * ranges.cc: Likewise.
        * region-model-manager.cc
        (region_model_manager::region_model_manager): Add "node_mgr" param
        and use it to initialize m_node_mgr.  Update for move of
        m_next_node_id into node_manager.
        (region_model_manager::log_stats): Drop logging of m_next_node_id.
        * region-model-manager.h
        (region_model_manager::region_model_manager): Add "node_mgr"
        param.
        (region_model_manager::get_num_nodes): Move to node_manager.
        (region_model_manager::alloc_node_id): Delegate to m_node_mgr.
        (region_model_manager::get_node_manager): New accessor.
        (region_model_manager::m_node_mgr): New field.
        (region_model_manager::m_next_node_id): Move to node_manager.
        * region-model.cc (region_model::region_model): Update param from
        region_model_manager * to symbolic::node_manager &.
        (engine::engine): Update for introduction of node_manager.
        (engine::log_stats): Likewise.
        (selftest) Update selftests for introduction of
        symbolic::node_manager, creating node_manager instances and
        accessing their region_model_manager rather than creating
        instances of the latter directly.  Update for region_model ctor
        taking a node_manager & rather than a region_model_manager *.
        * region-model.h (region_model::region_model): Change param from
        region_model_manager * to symbolic::node_manager &.
        (region_model::get_node_manager): New accessor.
        (region_model::m_node_mgr): New field.
        (engine::engine): Change param from region_model_manager & to
        symbolic::node_manager &.
        (engine::get_node_manager): New.
        (engine::get_model_manager): New.
        (engine::get_known_function_manager): Update.
        (engine::m_mgr): Replace field with...
        (engine::m_node_mgr): ...this.
        * region.cc: Update for region_model ctor taking a node_manager &
        rather than a region_model_manager *.
        * sm-signal.cc (update_model_for_signal_handler): Likewise.
        * state-purge.cc (state_purge_per_decl::process_worklists):
        Likewise.
        * store.cc (get_svalue_for_ctor_val): Likewise.
        (selftest::test_binding_key_overlap): Update for introduction of
        symbolic::node_manager
        * symbolic-nodes.cc: Include "analyzer/analyzer-logging.h",
        "analyzer/region-model.h", and "analyzer/region-model-manager.h".
        (symbolic::node_manager::node_manager): New.
        (ymbolic::node_manager::~node_manager): New.
        (symbolic::node_manager::log_stats): New.
        * symbolic-nodes.h (class node_manager): New.

Signed-off-by: David Malcolm <[email protected]>
---
 gcc/analyzer/access-diagram.cc       |   3 +-
 gcc/analyzer/common.h                |   2 +
 gcc/analyzer/constraint-manager.cc   | 295 +++++++++++++++------------
 gcc/analyzer/diagnostic-manager.cc   |   2 +-
 gcc/analyzer/engine.cc               |   7 +-
 gcc/analyzer/program-point.cc        |   3 +-
 gcc/analyzer/program-state.cc        |  42 ++--
 gcc/analyzer/program-state.h         |   4 +
 gcc/analyzer/ranges.cc               |   5 +-
 gcc/analyzer/region-model-manager.cc |   8 +-
 gcc/analyzer/region-model-manager.h  |  16 +-
 gcc/analyzer/region-model.cc         | 279 +++++++++++++------------
 gcc/analyzer/region-model.h          |  28 ++-
 gcc/analyzer/region.cc               |   2 +-
 gcc/analyzer/sm-signal.cc            |   2 +-
 gcc/analyzer/state-purge.cc          |   2 +-
 gcc/analyzer/store.cc                |   5 +-
 gcc/analyzer/symbolic-nodes.cc       |  24 +++
 gcc/analyzer/symbolic-nodes.h        |  35 ++++
 19 files changed, 467 insertions(+), 297 deletions(-)

diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc
index 861823f6aea..f9822e856c4 100644
--- a/gcc/analyzer/access-diagram.cc
+++ b/gcc/analyzer/access-diagram.cc
@@ -2704,7 +2704,8 @@ assert_eq_typeless_integer (const location &loc,
 static void
 test_bit_size_expr_to_bytes ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
 
   /* 40 bits: should be 5 bytes.  */
   {
diff --git a/gcc/analyzer/common.h b/gcc/analyzer/common.h
index 04abf1dd0ff..9f100068722 100644
--- a/gcc/analyzer/common.h
+++ b/gcc/analyzer/common.h
@@ -57,6 +57,7 @@ class superedge;
 namespace symbolic
 {
   class node;
+  class node_manager;
 }
 
 class svalue;
@@ -120,6 +121,7 @@ class checker_event;
 class checker_path;
 class extrinsic_state;
 class sm_state_map;
+class call_string;
 class program_point;
 class program_state;
 class exploded_graph;
diff --git a/gcc/analyzer/constraint-manager.cc 
b/gcc/analyzer/constraint-manager.cc
index 3293f21b324..4819c53e20f 100644
--- a/gcc/analyzer/constraint-manager.cc
+++ b/gcc/analyzer/constraint-manager.cc
@@ -3458,8 +3458,8 @@ test_constraint_conditions ()
 
   /* Self-comparisons.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
     ASSERT_CONDITION_TRUE (model, x, EQ_EXPR, x);
     ASSERT_CONDITION_TRUE (model, x, LE_EXPR, x);
     ASSERT_CONDITION_TRUE (model, x, GE_EXPR, x);
@@ -3470,23 +3470,23 @@ test_constraint_conditions ()
 
   /* Adding self-equality shouldn't add equiv classes.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, x);
     ADD_SAT_CONSTRAINT (model, int_42, EQ_EXPR, int_42);
     /* ...even when done directly via svalues: */
     const svalue *sval_int_42 = model.get_rvalue (int_42, nullptr);
     bool sat = model.get_constraints ()->add_constraint (sval_int_42,
-                                                         EQ_EXPR,
-                                                         sval_int_42);
+                                                        EQ_EXPR,
+                                                        sval_int_42);
     ASSERT_TRUE (sat);
     ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 0);
   }
 
   /* x == y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
 
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, y);
@@ -3517,8 +3517,8 @@ test_constraint_conditions ()
 
   /* x == y, then y == z  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
 
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, y);
@@ -3534,8 +3534,8 @@ test_constraint_conditions ()
 
   /* x != y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
 
     ADD_SAT_CONSTRAINT (model, x, NE_EXPR, y);
 
@@ -3565,8 +3565,8 @@ test_constraint_conditions ()
 
   /* x < y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
 
     ADD_SAT_CONSTRAINT (model, x, LT_EXPR, y);
 
@@ -3588,8 +3588,8 @@ test_constraint_conditions ()
 
   /* x <= y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
 
     ADD_SAT_CONSTRAINT (model, x, LE_EXPR, y);
 
@@ -3611,8 +3611,8 @@ test_constraint_conditions ()
 
   /* x > y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
 
     ADD_SAT_CONSTRAINT (model, x, GT_EXPR, y);
 
@@ -3634,8 +3634,8 @@ test_constraint_conditions ()
 
   /* x >= y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
 
     ADD_SAT_CONSTRAINT (model, x, GE_EXPR, y);
 
@@ -3659,8 +3659,9 @@ test_constraint_conditions ()
 
   /* Constants.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ASSERT_CONDITION_FALSE (model, int_0, EQ_EXPR, int_42);
     ASSERT_CONDITION_TRUE (model, int_0, NE_EXPR, int_42);
     ASSERT_CONDITION_TRUE (model, int_0, LT_EXPR, int_42);
@@ -3671,8 +3672,9 @@ test_constraint_conditions ()
 
   /* x == 0, y == 42.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
     ADD_SAT_CONSTRAINT (model, y, EQ_EXPR, int_42);
 
@@ -3688,48 +3690,54 @@ test_constraint_conditions ()
 
   /* x == y && x != y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, y);
     ADD_UNSAT_CONSTRAINT (model, x, NE_EXPR, y);
   }
 
   /* x == 0 then x == 42.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
     ADD_UNSAT_CONSTRAINT (model, x, EQ_EXPR, int_42);
   }
 
   /* x == 0 then x != 0.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
     ADD_UNSAT_CONSTRAINT (model, x, NE_EXPR, int_0);
   }
 
   /* x == 0 then x > 0.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
     ADD_UNSAT_CONSTRAINT (model, x, GT_EXPR, int_0);
   }
 
   /* x != y && x == y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, x, NE_EXPR, y);
     ADD_UNSAT_CONSTRAINT (model, x, EQ_EXPR, y);
   }
 
   /* x <= y && x > y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, x, LE_EXPR, y);
     ADD_UNSAT_CONSTRAINT (model, x, GT_EXPR, y);
   }
@@ -3749,8 +3757,9 @@ test_transitivity ()
 
   /* a == b, then c == d, then c == b.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ASSERT_CONDITION_UNKNOWN (model, a, EQ_EXPR, b);
     ASSERT_CONDITION_UNKNOWN (model, b, EQ_EXPR, c);
     ASSERT_CONDITION_UNKNOWN (model, c, EQ_EXPR, d);
@@ -3770,8 +3779,9 @@ test_transitivity ()
 
   /* Transitivity: "a < b", "b < c" should imply "a < c".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, LT_EXPR, b);
     ADD_SAT_CONSTRAINT (model, b, LT_EXPR, c);
 
@@ -3781,8 +3791,9 @@ test_transitivity ()
 
   /* Transitivity: "a <= b", "b < c" should imply "a < c".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, LE_EXPR, b);
     ADD_SAT_CONSTRAINT (model, b, LT_EXPR, c);
 
@@ -3792,8 +3803,9 @@ test_transitivity ()
 
   /* Transitivity: "a <= b", "b <= c" should imply "a <= c".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, LE_EXPR, b);
     ADD_SAT_CONSTRAINT (model, b, LE_EXPR, c);
 
@@ -3803,8 +3815,9 @@ test_transitivity ()
 
   /* Transitivity: "a > b", "b > c" should imply "a > c".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GT_EXPR, b);
     ADD_SAT_CONSTRAINT (model, b, GT_EXPR, c);
 
@@ -3814,8 +3827,9 @@ test_transitivity ()
 
   /* Transitivity: "a >= b", "b > c" should imply " a > c".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
     ADD_SAT_CONSTRAINT (model, b, GT_EXPR, c);
 
@@ -3825,8 +3839,9 @@ test_transitivity ()
 
   /* Transitivity: "a >= b", "b >= c" should imply "a >= c".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
     ADD_SAT_CONSTRAINT (model, b, GE_EXPR, c);
 
@@ -3841,8 +3856,9 @@ test_transitivity ()
      but also that:
        (a < d).  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, LT_EXPR, b);
     ADD_SAT_CONSTRAINT (model, c, LT_EXPR, d);
     ADD_SAT_CONSTRAINT (model, b, LT_EXPR, c);
@@ -3854,8 +3870,9 @@ test_transitivity ()
 
   /* Transitivity: "a >= b", "b >= a" should imply that a == b.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
     ADD_SAT_CONSTRAINT (model, b, GE_EXPR, a);
 
@@ -3869,8 +3886,9 @@ test_transitivity ()
 
   /* Transitivity: "a >= b", "b > a" should be impossible.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
     ADD_UNSAT_CONSTRAINT (model, b, GT_EXPR, a);
   }
@@ -3878,8 +3896,9 @@ test_transitivity ()
   /* Transitivity: "a >= b", "b >= c", "c >= a" should imply
      that a == b == c.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
     ADD_SAT_CONSTRAINT (model, b, GE_EXPR, c);
     ADD_SAT_CONSTRAINT (model, c, GE_EXPR, a);
@@ -3890,8 +3909,9 @@ test_transitivity ()
   /* Transitivity: "a > b", "b > c", "c > a"
      should be impossible.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GT_EXPR, b);
     ADD_SAT_CONSTRAINT (model, b, GT_EXPR, c);
     ADD_UNSAT_CONSTRAINT (model, c, GT_EXPR, a);
@@ -3920,16 +3940,18 @@ test_constant_comparisons ()
 
   /* Given a >= 1024, then a <= 1023 should be impossible.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GE_EXPR, int_1024);
     ADD_UNSAT_CONSTRAINT (model, a, LE_EXPR, int_1023);
   }
 
   /* a > 4.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_4);
     ASSERT_CONDITION_TRUE (model, a, GT_EXPR, int_4);
     ASSERT_CONDITION_TRUE (model, a, NE_EXPR, int_3);
@@ -3938,8 +3960,9 @@ test_constant_comparisons ()
 
   /* a <= 4.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, LE_EXPR, int_4);
     ASSERT_CONDITION_FALSE (model, a, GT_EXPR, int_4);
     ASSERT_CONDITION_FALSE (model, a, GT_EXPR, int_5);
@@ -3948,8 +3971,9 @@ test_constant_comparisons ()
 
   /* If "a > b" and "a == 3", then "b == 4" ought to be unsatisfiable.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GT_EXPR, b);
     ADD_SAT_CONSTRAINT (model, a, EQ_EXPR, int_3);
     ADD_UNSAT_CONSTRAINT (model, b, EQ_EXPR, int_4);
@@ -3960,8 +3984,8 @@ test_constant_comparisons ()
     /* If "a <= 4" && "a > 3", then "a == 4",
        assuming a is of integral type.  */
     {
-      region_model_manager mgr;
-      region_model model (&mgr);
+      symbolic::node_manager node_mgr;
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, a, LE_EXPR, int_4);
       ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_3);
       ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
@@ -3970,8 +3994,8 @@ test_constant_comparisons ()
     /* If "a > 3" && "a <= 4", then "a == 4",
        assuming a is of integral type.  */
     {
-      region_model_manager mgr;
-      region_model model (&mgr);
+      symbolic::node_manager node_mgr;
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_3);
       ADD_SAT_CONSTRAINT (model, a, LE_EXPR, int_4);
       ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
@@ -3979,8 +4003,9 @@ test_constant_comparisons ()
     /* If "a > 3" && "a < 5", then "a == 4",
        assuming a is of integral type.  */
     {
-      region_model_manager mgr;
-      region_model model (&mgr);
+      symbolic::node_manager node_mgr;
+      region_model model (node_mgr);
+
       ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_3);
       ADD_SAT_CONSTRAINT (model, a, LT_EXPR, int_5);
       ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
@@ -3988,16 +4013,18 @@ test_constant_comparisons ()
     /* If "a >= 4" && "a < 5", then "a == 4",
        assuming a is of integral type.  */
     {
-      region_model_manager mgr;
-      region_model model (&mgr);
+      symbolic::node_manager node_mgr;
+      region_model model (node_mgr);
+
       ADD_SAT_CONSTRAINT (model, a, GE_EXPR, int_4);
       ADD_SAT_CONSTRAINT (model, a, LT_EXPR, int_5);
       ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
     }
     /* If "a >= 4" && "a <= 4", then "a == 4".  */
     {
-      region_model_manager mgr;
-      region_model model (&mgr);
+      symbolic::node_manager node_mgr;
+      region_model model (node_mgr);
+
       ADD_SAT_CONSTRAINT (model, a, GE_EXPR, int_4);
       ADD_SAT_CONSTRAINT (model, a, LE_EXPR, int_4);
       ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
@@ -4011,8 +4038,9 @@ test_constant_comparisons ()
     tree float_3 = build_real_from_int_cst (double_type_node, int_3);
     tree float_4 = build_real_from_int_cst (double_type_node, int_4);
 
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, f, GT_EXPR, float_3);
     ADD_SAT_CONSTRAINT (model, f, LE_EXPR, float_4);
     ASSERT_CONDITION_UNKNOWN (model, f, EQ_EXPR, float_4);
@@ -4021,22 +4049,23 @@ test_constant_comparisons ()
 
   /* "a > 3 && a <= 3" should be impossible.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_3);
     ADD_UNSAT_CONSTRAINT (model, a, LE_EXPR, int_3);
   }
 
   /* "(a + 1) > 3 && a < 3" should be impossible.  */
   {
-    region_model_manager mgr;
+    symbolic::node_manager node_mgr;
     {
-      region_model model (&mgr);
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, a_plus_one, GT_EXPR, int_3);
       ADD_UNSAT_CONSTRAINT (model, a, LT_EXPR, int_3);
     }
     {
-      region_model model (&mgr);
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, a, LT_EXPR, int_3);
       ADD_UNSAT_CONSTRAINT (model, a_plus_one, GT_EXPR, int_3);
     }
@@ -4044,38 +4073,38 @@ test_constant_comparisons ()
 
   /* "3 < a < 4" should be impossible for integer a.  */
   {
-    region_model_manager mgr;
+    symbolic::node_manager node_mgr;
     {
-      region_model model (&mgr);
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, int_3, LT_EXPR, a);
       ADD_UNSAT_CONSTRAINT (model, a, LT_EXPR, int_4);
     }
     {
-      region_model model (&mgr);
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, int_1, LT_EXPR, a);
       ADD_SAT_CONSTRAINT (model, int_3, LT_EXPR, a);
       ADD_SAT_CONSTRAINT (model, a, LT_EXPR, int_5);
       ADD_UNSAT_CONSTRAINT (model, a, LT_EXPR, int_4);
     }
     {
-      region_model model (&mgr);
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, int_1, LT_EXPR, a);
       ADD_SAT_CONSTRAINT (model, a, LT_EXPR, int_5);
       ADD_SAT_CONSTRAINT (model, int_3, LT_EXPR, a);
       ADD_UNSAT_CONSTRAINT (model, a, LT_EXPR, int_4);
     }
     {
-      region_model model (&mgr);
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, a, LT_EXPR, int_4);
       ADD_UNSAT_CONSTRAINT (model, int_3, LT_EXPR, a);
     }
     {
-      region_model model (&mgr);
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_3);
       ADD_UNSAT_CONSTRAINT (model, int_4, GT_EXPR, a);
     }
     {
-      region_model model (&mgr);
+      region_model model (node_mgr);
       ADD_SAT_CONSTRAINT (model, int_4, GT_EXPR, a);
       ADD_UNSAT_CONSTRAINT (model, a, GT_EXPR, int_3);
     }
@@ -4097,8 +4126,8 @@ test_constraint_impl ()
 
   /* x == y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
 
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, y);
 
@@ -4110,8 +4139,9 @@ test_constraint_impl ()
 
   /* y <= z; x == y.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
     ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, z);
 
@@ -4132,8 +4162,9 @@ test_constraint_impl ()
 
   /* y <= z; y == x.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
     ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, z);
 
@@ -4154,8 +4185,8 @@ test_constraint_impl ()
 
   /* x == 0, then x != 42.  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
 
     ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
     ADD_SAT_CONSTRAINT (model, x, NE_EXPR, int_42);
@@ -4182,9 +4213,10 @@ test_equality ()
   tree y = build_global_decl ("y", integer_type_node);
 
   {
-    region_model_manager mgr;
-    region_model model0 (&mgr);
-    region_model model1 (&mgr);
+    symbolic::node_manager node_mgr;
+
+    region_model model0 (node_mgr);
+    region_model model1 (node_mgr);
 
     constraint_manager *cm0 = model0.get_constraints ();
     constraint_manager *cm1 = model1.get_constraints ();
@@ -4202,7 +4234,7 @@ test_equality ()
     ASSERT_NE (model0.hash (), model1.hash ());
     ASSERT_NE (model0, model1);
 
-    region_model model2 (&mgr);
+    region_model model2 (node_mgr);
     constraint_manager *cm2 = model2.get_constraints ();
     /* Make the same change to cm2.  */
     ADD_SAT_CONSTRAINT (model2, x, EQ_EXPR, y);
@@ -4219,11 +4251,12 @@ test_equality ()
 static void
 test_many_constants ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   program_point point (program_point::origin (mgr));
   tree a = build_global_decl ("a", integer_type_node);
 
-  region_model model (&mgr);
+  region_model model (node_mgr);
   auto_vec<tree> constants;
   for (int i = 0; i < 20; i++)
     {
@@ -4234,7 +4267,7 @@ test_many_constants ()
       /* Merge, and check the result.  */
       region_model other (model);
 
-      region_model merged (&mgr);
+      region_model merged (node_mgr);
       ASSERT_TRUE (model.can_merge_with_p (other, point, &merged));
       model.canonicalize ();
       merged.canonicalize ();
@@ -4257,8 +4290,9 @@ test_purging (void)
 
   /*  "a != 0".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, NE_EXPR, int_0);
     ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 2);
     ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 1);
@@ -4274,8 +4308,9 @@ test_purging (void)
 
   /*  "a != 0" && "b != 0".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, NE_EXPR, int_0);
     ADD_SAT_CONSTRAINT (model, b, NE_EXPR, int_0);
     ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 3);
@@ -4293,8 +4328,9 @@ test_purging (void)
 
   /*  "a != 0" && "b == 0".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, NE_EXPR, int_0);
     ADD_SAT_CONSTRAINT (model, b, EQ_EXPR, int_0);
     ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 2);
@@ -4312,8 +4348,9 @@ test_purging (void)
 
   /*  "a == 0".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, EQ_EXPR, int_0);
     ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 1);
     ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 0);
@@ -4329,8 +4366,9 @@ test_purging (void)
 
   /*  "a == 0" && "b != 0".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, EQ_EXPR, int_0);
     ADD_SAT_CONSTRAINT (model, b, NE_EXPR, int_0);
     ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 2);
@@ -4348,8 +4386,9 @@ test_purging (void)
 
   /*  "a == 0" && "b == 0".  */
   {
-    region_model_manager mgr;
-    region_model model (&mgr);
+    symbolic::node_manager node_mgr;
+    region_model model (node_mgr);
+
     ADD_SAT_CONSTRAINT (model, a, EQ_EXPR, int_0);
     ADD_SAT_CONSTRAINT (model, b, EQ_EXPR, int_0);
     ASSERT_EQ (model.get_constraints ()->m_equiv_classes.length (), 1);
@@ -4683,7 +4722,7 @@ test_bounded_ranges ()
 static void
 test_bits (void)
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
 
   tree int_0 = integer_zero_node;
   tree int_0x80 = build_int_cst (integer_type_node, 0x80);
@@ -4695,7 +4734,7 @@ test_bits (void)
 
   /* "x & 0x80 == 0x80".  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
     ADD_SAT_CONSTRAINT (model, x_bit_and_0x80, EQ_EXPR, int_0x80);
     ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0x80);
@@ -4703,7 +4742,7 @@ test_bits (void)
 
   /* "x & 0x80 != 0x80".  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
     ADD_SAT_CONSTRAINT (model, x_bit_and_0x80, NE_EXPR, int_0x80);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0);
     ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0x80);
@@ -4711,7 +4750,7 @@ test_bits (void)
 
   /* "x & 0x80 == 0".  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
 
     ADD_SAT_CONSTRAINT (model, x_bit_and_0x80, EQ_EXPR, int_0);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0);
@@ -4720,7 +4759,7 @@ test_bits (void)
 
   /* "x & 0x80 != 0".  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
     ADD_SAT_CONSTRAINT (model, x_bit_and_0x80, NE_EXPR, int_0);
     ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0x80);
@@ -4730,7 +4769,7 @@ test_bits (void)
 
   /* "x & 0xff == 0x80".  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
     ADD_SAT_CONSTRAINT (model, x_bit_and_0xff, EQ_EXPR, int_0x80);
     ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0x80);
@@ -4739,7 +4778,7 @@ test_bits (void)
 
   /* "x & 0xff != 0x80".  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
     ADD_SAT_CONSTRAINT (model, x_bit_and_0xff, NE_EXPR, int_0x80);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0);
     ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0x80);
@@ -4748,7 +4787,7 @@ test_bits (void)
 
   /* "x & 0xff == 0".  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
 
     ADD_SAT_CONSTRAINT (model, x_bit_and_0xff, EQ_EXPR, int_0);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0);
@@ -4758,7 +4797,7 @@ test_bits (void)
 
   /* "x & 0xff != 0".  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
     ADD_SAT_CONSTRAINT (model, x_bit_and_0xff, NE_EXPR, int_0);
     ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0);
     ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0x80);
diff --git a/gcc/analyzer/diagnostic-manager.cc 
b/gcc/analyzer/diagnostic-manager.cc
index 2e7acba0910..053d8153ce3 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -1918,7 +1918,7 @@ diagnostic_manager::annotate_exploded_path (const 
path_builder &pb,
                     idx,
                     eedge->m_src->m_index,
                     eedge->m_dest->m_index);
-      region_model src_model (pb.get_ext_state ().get_model_manager ());
+      region_model src_model (pb.get_ext_state ().get_node_manager ());
       if (idx > 0)
        src_model = dst_models[idx - 1];
       src_models.push_back (src_model);
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index a42350531b4..4856966c700 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -3976,7 +3976,7 @@ feasibility_problem::to_json () const
 
 feasibility_state::feasibility_state (region_model_manager *manager,
                                      const supergraph &sg)
-: m_model (manager),
+: m_model (manager->get_node_manager ()),
   m_snodes_visited (sg.m_nodes.length ())
 {
   bitmap_clear (m_snodes_visited);
@@ -4975,7 +4975,8 @@ impl_run_checkers (logger *logger)
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
     node->get_untransformed_body ();
 
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
 
   /* Create the supergraph.  */
   supergraph sg (mgr, logger);
@@ -4986,7 +4987,7 @@ impl_run_checkers (logger *logger)
 
   maybe_dump_supergraph (sg, "fixup-locations");
 
-  engine eng (mgr, &sg);
+  engine eng (node_mgr, &sg);
 
   state_purge_map *purge_map = nullptr;
   if (flag_analyzer_state_purge)
diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
index 228c36070f8..79ba0442f3a 100644
--- a/gcc/analyzer/program-point.cc
+++ b/gcc/analyzer/program-point.cc
@@ -246,7 +246,8 @@ namespace selftest {
 static void
 test_program_point_equality ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
 
   const supernode *snode = nullptr;
 
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 1c1c58784f4..c549a8baff1 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -118,6 +118,13 @@ extrinsic_state::get_model_manager () const
     return nullptr; /* for selftests.  */
 }
 
+symbolic::node_manager &
+extrinsic_state::get_node_manager () const
+{
+  gcc_assert (m_engine);
+  return m_engine->get_node_manager ();
+}
+
 /* Try to find a state machine named NAME.
    If found, return true and write its index to *OUT.
    Otherwise return false.  */
@@ -932,8 +939,8 @@ program_state::program_state (const extrinsic_state 
&ext_state)
   m_valid (true)
 {
   engine *eng = ext_state.get_engine ();
-  region_model_manager *mgr = eng->get_model_manager ();
-  m_region_model = new region_model (mgr);
+  auto &node_mgr = eng->get_node_manager ();
+  m_region_model = new region_model (node_mgr);
   const int num_states = ext_state.get_num_checkers ();
   for (int i = 0; i < num_states; i++)
     {
@@ -1700,15 +1707,15 @@ test_sm_state_map ()
   std::vector<std::unique_ptr<state_machine>> checkers;
   const state_machine &borrowed_sm = *sm.get ();
   checkers.push_back (std::move (sm));
-  region_model_manager mgr;
-  engine eng (mgr);
+  symbolic::node_manager node_mgr;
+  engine eng (node_mgr);
   extrinsic_state ext_state (std::move (checkers), &eng);
 
   /* Test setting states on svalue_id instances directly.  */
   {
     const state_machine::state test_state_42 ("test state 42", 42);
     const state_machine::state_t TEST_STATE_42 = &test_state_42;
-    region_model model (&mgr);
+    region_model model (node_mgr);
     const svalue *x_sval = model.get_rvalue (x, nullptr);
     const svalue *y_sval = model.get_rvalue (y, nullptr);
     const svalue *z_sval = model.get_rvalue (z, nullptr);
@@ -1736,7 +1743,7 @@ test_sm_state_map ()
 
   /* Test setting states via equivalence classes.  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
     const svalue *x_sval = model.get_rvalue (x, nullptr);
     const svalue *y_sval = model.get_rvalue (y, nullptr);
     const svalue *z_sval = model.get_rvalue (z, nullptr);
@@ -1759,7 +1766,7 @@ test_sm_state_map ()
 
   /* Test equality and hashing.  */
   {
-    region_model model (&mgr);
+    region_model model (node_mgr);
     const svalue *y_sval = model.get_rvalue (y, nullptr);
     const svalue *z_sval = model.get_rvalue (z, nullptr);
 
@@ -1793,7 +1800,7 @@ test_sm_state_map ()
     ASSERT_EQ (map0.hash (), map1.hash ());
     ASSERT_EQ (map0, map1);
 
-    region_model model (&mgr);
+    region_model model (node_mgr);
     const svalue *x_sval = model.get_rvalue (x, nullptr);
     const svalue *y_sval = model.get_rvalue (y, nullptr);
     const svalue *z_sval = model.get_rvalue (z, nullptr);
@@ -1826,8 +1833,9 @@ test_program_state_1 ()
   const state_machine::state_t UNCHECKED_STATE
     = sm->get_state_by_name ("unchecked");
 
-  region_model_manager mgr;
-  engine eng (mgr);
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+  engine eng (node_mgr);
   extrinsic_state ext_state (std::move (sm), &eng);
   program_state s (ext_state);
   region_model *model = s.m_region_model;
@@ -1856,8 +1864,8 @@ test_program_state_2 ()
   tree string_cst_ptr = build_string_literal (4, "foo");
 
   std::vector<std::unique_ptr<state_machine>> checkers;
-  region_model_manager mgr;
-  engine eng (mgr);
+  symbolic::node_manager node_mgr;
+  engine eng (node_mgr);
   extrinsic_state ext_state (std::move (checkers), &eng);
 
   program_state s (ext_state);
@@ -1877,8 +1885,9 @@ test_program_state_merging ()
      malloc sm-state, pointing to a region on the heap.  */
   tree p = build_global_decl ("p", ptr_type_node);
 
-  region_model_manager mgr;
-  engine eng (mgr);
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+  engine eng (node_mgr);
   program_point point (program_point::origin (mgr));
   extrinsic_state ext_state (make_malloc_state_machine (nullptr),
                             &eng);
@@ -1944,8 +1953,9 @@ test_program_state_merging ()
 static void
 test_program_state_merging_2 ()
 {
-  region_model_manager mgr;
-  engine eng (mgr);
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+  engine eng (node_mgr);
   program_point point (program_point::origin (mgr));
   extrinsic_state ext_state (make_signal_state_machine (nullptr), &eng);
 
diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h
index e098d84a455..b8219158c11 100644
--- a/gcc/analyzer/program-state.h
+++ b/gcc/analyzer/program-state.h
@@ -73,6 +73,10 @@ public:
   std::unique_ptr<json::object> to_json () const;
 
   engine *get_engine () const { return m_engine; }
+
+  symbolic::node_manager &
+  get_node_manager () const;
+
   region_model_manager *get_model_manager () const;
 
   bool get_sm_idx_by_name (const char *name, unsigned *out) const;
diff --git a/gcc/analyzer/ranges.cc b/gcc/analyzer/ranges.cc
index 241d7bfd07d..d5977b60784 100644
--- a/gcc/analyzer/ranges.cc
+++ b/gcc/analyzer/ranges.cc
@@ -232,8 +232,9 @@ namespace selftest {
 
 static void test_intersects (void)
 {
-  region_model_manager mgr;
-  region_model m (&mgr);
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+  region_model m (node_mgr);
 
   /* Test various concrete ranges.  */
   symbolic_byte_offset zero (0, mgr);
diff --git a/gcc/analyzer/region-model-manager.cc 
b/gcc/analyzer/region-model-manager.cc
index fd5d91c8ee4..1a7bfc22572 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -42,9 +42,10 @@ namespace ana {
 
 /* region_model_manager's ctor.  */
 
-region_model_manager::region_model_manager (logger *logger)
-: m_logger (logger),
-  m_next_node_id (0),
+region_model_manager::region_model_manager (symbolic::node_manager &node_mgr,
+                                           logger *logger)
+: m_node_mgr (node_mgr),
+  m_logger (logger),
   m_empty_call_string (),
   m_root_region (alloc_node_id ()),
   m_stack_region (alloc_node_id (), &m_root_region),
@@ -2158,7 +2159,6 @@ region_model_manager::log_stats (logger *logger, bool 
show_objs) const
   LOG_SCOPE (logger);
   logger->log ("call string consolidation");
   m_empty_call_string.recursive_log (logger);
-  logger->log ("next node id: %i", m_next_node_id);
   logger->log ("svalue consolidation");
   log_uniq_map (logger, show_objs, "constant_svalue", m_constants_map);
   log_uniq_map (logger, show_objs, "unknown_svalue", m_unknowns_map);
diff --git a/gcc/analyzer/region-model-manager.h 
b/gcc/analyzer/region-model-manager.h
index 6e6cbe74700..fd4ff449344 100644
--- a/gcc/analyzer/region-model-manager.h
+++ b/gcc/analyzer/region-model-manager.h
@@ -31,11 +31,12 @@ namespace ana {
 class region_model_manager
 {
 public:
-  region_model_manager (logger *logger = nullptr);
+  region_model_manager (symbolic::node_manager &node_mgr,
+                       logger *logger = nullptr);
   ~region_model_manager ();
 
-  unsigned get_num_nodes () const { return m_next_node_id; }
-  unsigned alloc_node_id () { return m_next_node_id++; }
+  unsigned
+  alloc_node_id () { return m_node_mgr.alloc_node_id (); }
 
   /* call_string consolidation.  */
   const call_string &get_empty_call_string () const
@@ -153,6 +154,12 @@ public:
                                       tree t,
                                       const dump_location_t &loc);
 
+  symbolic::node_manager &
+  get_node_manager () const
+  {
+    return m_node_mgr;
+  }
+
   store_manager *get_store_manager () { return &m_store_mgr; }
   bounded_ranges_manager *get_range_manager () const { return m_range_mgr; }
 
@@ -203,10 +210,9 @@ private:
   const svalue *maybe_fold_asm_output_svalue (tree type,
                                              const vec<const svalue *> 
&inputs);
 
+  symbolic::node_manager &m_node_mgr;
   logger *m_logger;
 
-  unsigned m_next_node_id;
-
   const call_string m_empty_call_string;
 
   root_region m_root_region;
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 60e80a9e69e..1e7b84134ea 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -408,19 +408,24 @@ exception_node::add_to_reachable_regions 
(reachable_regions &regs) const
 
 /* Ctor for region_model: construct an "empty" model.  */
 
-region_model::region_model (region_model_manager *mgr)
-: m_mgr (mgr), m_store (), m_current_frame (nullptr),
+region_model::region_model (symbolic::node_manager &node_mgr)
+: m_node_mgr (node_mgr),
+  m_mgr (&node_mgr.get_region_model_manager ()),
+  m_store (),
+  m_current_frame (nullptr),
   m_thrown_exceptions_stack (),
   m_caught_exceptions_stack (),
   m_dynamic_extents ()
 {
-  m_constraints = new constraint_manager (mgr);
+  m_constraints = new constraint_manager (m_mgr);
 }
 
 /* region_model's copy ctor.  */
 
 region_model::region_model (const region_model &other)
-: m_mgr (other.m_mgr), m_store (other.m_store),
+: m_node_mgr (other.m_node_mgr),
+  m_mgr (other.m_mgr),
+  m_store (other.m_store),
   m_constraints (new constraint_manager (*other.m_constraints)),
   m_current_frame (other.m_current_frame),
   m_thrown_exceptions_stack (other.m_thrown_exceptions_stack),
@@ -7567,9 +7572,9 @@ rejected_ranges_constraint::to_json () const
 
 /* engine's ctor.  */
 
-engine::engine (region_model_manager &mgr,
+engine::engine (symbolic::node_manager &node_mgr,
                const supergraph *sg)
-: m_mgr (mgr),
+: m_node_mgr (node_mgr),
   m_sg (sg)
 {
 }
@@ -7579,7 +7584,7 @@ engine::engine (region_model_manager &mgr,
 void
 engine::log_stats (logger *logger) const
 {
-  m_mgr.log_stats (logger, true);
+  m_node_mgr.log_stats (logger, true);
 }
 
 namespace ana {
@@ -7711,8 +7716,8 @@ assert_dump_eq (const location &loc,
 static void
 test_dump ()
 {
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model (node_mgr);
 
   ASSERT_DUMP_EQ (model, false,
                  "stack depth: 0\n"
@@ -7802,8 +7807,9 @@ test_struct ()
   tree int_17 = build_int_cst (integer_type_node, 17);
   tree int_m3 = build_int_cst (integer_type_node, -3);
 
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+  region_model model (node_mgr);
   /* Set fields in order y, then x.  */
   model.set_value (c_y, int_m3, nullptr);
   model.set_value (c_x, int_17, nullptr);
@@ -7856,8 +7862,8 @@ test_array_1 ()
 
   tree a = build_global_decl ("a", arr_type);
 
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model (node_mgr);
   tree int_0 = integer_zero_node;
   tree a_0 = build4 (ARRAY_REF, char_type_node,
                     a, int_0, NULL_TREE, NULL_TREE);
@@ -7870,12 +7876,12 @@ test_array_1 ()
 static void
 test_get_representative_tree ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
 
   /* STRING_CST.  */
   {
     tree string_cst = build_string (4, "foo");
-    region_model m (&mgr);
+    region_model m (node_mgr);
     const svalue *str_sval = m.get_rvalue (string_cst, nullptr);
     tree rep = m.get_representative_tree (str_sval);
     ASSERT_EQ (rep, string_cst);
@@ -7884,7 +7890,7 @@ test_get_representative_tree ()
   /* String literal.  */
   {
     tree string_cst_ptr = build_string_literal (4, "foo");
-    region_model m (&mgr);
+    region_model m (node_mgr);
     const svalue *str_sval = m.get_rvalue (string_cst_ptr, nullptr);
     tree rep = m.get_representative_tree (str_sval);
     ASSERT_DUMP_TREE_EQ (rep, "&\"foo\"[0]");
@@ -7895,13 +7901,13 @@ test_get_representative_tree ()
     tree tlen = size_int (10);
     tree arr_type = build_array_type (char_type_node, build_index_type (tlen));
     tree a = build_global_decl ("a", arr_type);
-    placeholder_svalue test_sval (mgr.alloc_node_id (),
+    placeholder_svalue test_sval (node_mgr.alloc_node_id (),
                                  char_type_node, "test value");
 
     /* Value of a[3].  */
     {
       test_region_model_context ctxt;
-      region_model model (&mgr);
+      region_model model (node_mgr);
       tree int_3 = build_int_cst (integer_type_node, 3);
       tree a_3 = build4 (ARRAY_REF, char_type_node,
                         a, int_3, NULL_TREE, NULL_TREE);
@@ -7914,7 +7920,7 @@ test_get_representative_tree ()
     /* Value of a[0].  */
     {
       test_region_model_context ctxt;
-      region_model model (&mgr);
+      region_model model (node_mgr);
       tree idx = integer_zero_node;
       tree a_0 = build4 (ARRAY_REF, char_type_node,
                         a, idx, NULL_TREE, NULL_TREE);
@@ -7939,9 +7945,9 @@ test_get_representative_tree ()
 
     /* Value of initial field.  */
     {
-      region_model m (&mgr);
+      region_model m (node_mgr);
       const region *c_x_reg = m.get_lvalue (c_x, &ctxt);
-      placeholder_svalue test_sval_x (mgr.alloc_node_id (),
+      placeholder_svalue test_sval_x (node_mgr.alloc_node_id (),
                                      integer_type_node, "test x val");
       m.set_value (c_x_reg, &test_sval_x, &ctxt);
       tree rep = m.get_representative_tree (&test_sval_x);
@@ -7950,9 +7956,9 @@ test_get_representative_tree ()
 
     /* Value of non-initial field.  */
     {
-      region_model m (&mgr);
+      region_model m (node_mgr);
       const region *c_y_reg = m.get_lvalue (c_y, &ctxt);
-      placeholder_svalue test_sval_y (mgr.alloc_node_id (),
+      placeholder_svalue test_sval_y (node_mgr.alloc_node_id (),
                                      integer_type_node, "test y val");
       m.set_value (c_y_reg, &test_sval_y, &ctxt);
       tree rep = m.get_representative_tree (&test_sval_y);
@@ -7971,8 +7977,8 @@ test_unique_constants ()
   tree int_42 = build_int_cst (integer_type_node, 42);
 
   test_region_model_context ctxt;
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model (node_mgr);
   ASSERT_EQ (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_0, &ctxt));
   ASSERT_EQ (model.get_rvalue (int_42, &ctxt),
             model.get_rvalue (int_42, &ctxt));
@@ -7999,7 +8005,8 @@ test_unique_constants ()
 static void
 test_unique_unknowns ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   const svalue *unknown_int
     = mgr.get_or_create_unknown_svalue (integer_type_node);
   /* Repeated calls with the same type should get the same "unknown"
@@ -8024,12 +8031,13 @@ test_unique_unknowns ()
 static void
 test_initial_svalue_folding ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   tree x = build_global_decl ("x", integer_type_node);
   tree y = build_global_decl ("y", integer_type_node);
 
   test_region_model_context ctxt;
-  region_model model (&mgr);
+  region_model model (node_mgr);
   const svalue *x_init = model.get_rvalue (x, &ctxt);
   const svalue *y_init = model.get_rvalue (y, &ctxt);
   ASSERT_NE (x_init, y_init);
@@ -8043,12 +8051,14 @@ test_initial_svalue_folding ()
 static void
 test_unaryop_svalue_folding ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+
   tree x = build_global_decl ("x", integer_type_node);
   tree y = build_global_decl ("y", integer_type_node);
 
   test_region_model_context ctxt;
-  region_model model (&mgr);
+  region_model model (node_mgr);
   const svalue *x_init = model.get_rvalue (x, &ctxt);
   const svalue *y_init = model.get_rvalue (y, &ctxt);
   const region *x_reg = model.get_lvalue (x, &ctxt);
@@ -8083,7 +8093,8 @@ test_binop_svalue_folding ()
 {
 #define NUM_CSTS 10
   tree cst_int[NUM_CSTS];
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   const svalue *cst_sval[NUM_CSTS];
   for (int i = 0; i < NUM_CSTS; i++)
     {
@@ -8131,7 +8142,7 @@ test_binop_svalue_folding ()
   tree x = build_global_decl ("x", integer_type_node);
 
   test_region_model_context ctxt;
-  region_model model (&mgr);
+  region_model model (node_mgr);
   const svalue *x_init = model.get_rvalue (x, &ctxt);
 
   /* PLUS_EXPR folding.  */
@@ -8236,8 +8247,9 @@ test_sub_svalue_folding ()
   tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
                     c, ct.m_x_field, NULL_TREE);
 
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+  region_model model (node_mgr);
   test_region_model_context ctxt;
   const region *c_x_reg = model.get_lvalue (c_x, &ctxt);
 
@@ -8270,7 +8282,8 @@ get_bit (region_model_manager *mgr,
 static void
 test_bits_within_svalue_folding ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
 
   const svalue *zero = mgr.get_or_create_int_cst (boolean_type_node, 0);
   const svalue *one = mgr.get_or_create_int_cst (boolean_type_node, 1);
@@ -8307,7 +8320,8 @@ test_bits_within_svalue_folding ()
 static void
 test_descendent_of_p ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   const region *stack = mgr.get_stack_region ();
   const region *heap = mgr.get_heap_region ();
   const region *code = mgr.get_code_region ();
@@ -8334,7 +8348,8 @@ static void
 test_bit_range_regions ()
 {
   tree x = build_global_decl ("x", integer_type_node);
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   const region *x_reg = mgr.get_region_for_global (x);
   const region *byte0
     = mgr.get_bit_range (x_reg, char_type_node, bit_range (0, 8));
@@ -8355,8 +8370,8 @@ test_assignment ()
   tree y = build_global_decl ("y", integer_type_node);
 
   /* "x == 0", then use of y, then "y = 0;".  */
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model (node_mgr);
   ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
   ASSERT_CONDITION_UNKNOWN (model, y, EQ_EXPR, int_0);
   model.set_value (model.get_lvalue (y, nullptr),
@@ -8387,8 +8402,8 @@ test_compound_assignment ()
   tree int_17 = build_int_cst (integer_type_node, 17);
   tree int_m3 = build_int_cst (integer_type_node, -3);
 
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model (node_mgr);
   model.set_value (c_x, int_17, nullptr);
   model.set_value (c_y, int_m3, nullptr);
 
@@ -8447,9 +8462,10 @@ test_stack_frames ()
   /* "q" global.  */
   tree q = build_global_decl ("q", ptr_type_node);
 
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   test_region_model_context ctxt;
-  region_model model (&mgr);
+  region_model model (node_mgr);
 
   /* Push stack frame for "parent_fn".  */
   const region *parent_frame_reg
@@ -8553,9 +8569,10 @@ test_get_representative_path_var ()
                       integer_type_node);
   DECL_CONTEXT (n) = fndecl;
 
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   test_region_model_context ctxt;
-  region_model model (&mgr);
+  region_model model (node_mgr);
 
   /* Push 5 stack frames for "factorial", each with a param  */
   auto_vec<const region *> parm_regs;
@@ -8608,9 +8625,9 @@ test_equality_1 ()
   tree int_17 = build_int_cst (integer_type_node, 17);
 
 /* Verify that "empty" region_model instances are equal to each other.  */
-  region_model_manager mgr;
-  region_model model0 (&mgr);
-  region_model model1 (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model0 (node_mgr);
+  region_model model1 (node_mgr);
   ASSERT_EQ (model0, model1);
 
   /* Verify that setting state in model1 makes the models non-equal.  */
@@ -8647,8 +8664,8 @@ test_canonicalization_2 ()
   tree x = build_global_decl ("x", integer_type_node);
   tree y = build_global_decl ("y", integer_type_node);
 
-  region_model_manager mgr;
-  region_model model0 (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model0 (node_mgr);
   model0.set_value (model0.get_lvalue (x, nullptr),
                    model0.get_rvalue (int_42, nullptr),
                    nullptr);
@@ -8656,7 +8673,7 @@ test_canonicalization_2 ()
                    model0.get_rvalue (int_113, nullptr),
                    nullptr);
 
-  region_model model1 (&mgr);
+  region_model model1 (node_mgr);
   model1.set_value (model1.get_lvalue (y, nullptr),
                    model1.get_rvalue (int_113, nullptr),
                    nullptr);
@@ -8681,12 +8698,12 @@ test_canonicalization_3 ()
   tree x = build_global_decl ("x", integer_type_node);
   tree y = build_global_decl ("y", integer_type_node);
 
-  region_model_manager mgr;
-  region_model model0 (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model0 (node_mgr);
   model0.add_constraint (x, GT_EXPR, int_3, nullptr);
   model0.add_constraint (y, GT_EXPR, int_42, nullptr);
 
-  region_model model1 (&mgr);
+  region_model model1 (node_mgr);
   model1.add_constraint (y, GT_EXPR, int_42, nullptr);
   model1.add_constraint (x, GT_EXPR, int_3, nullptr);
 
@@ -8704,8 +8721,8 @@ test_canonicalization_4 ()
   auto_vec<tree> csts;
   append_interesting_constants (&csts);
 
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model (node_mgr);
 
   for (tree cst : csts)
     model.get_rvalue (cst, nullptr);
@@ -8726,10 +8743,11 @@ assert_region_models_merge (tree expr, tree val_a, tree 
val_b,
                             const svalue **out_merged_svalue)
 {
   region_model_manager *mgr = out_merged_model->get_manager ();
+  auto &node_mgr = mgr->get_node_manager ();
   program_point point (program_point::origin (*mgr));
   test_region_model_context ctxt;
-  region_model model0 (mgr);
-  region_model model1 (mgr);
+  region_model model0 (node_mgr);
+  region_model model1 (node_mgr);
   if (val_a)
     model0.set_value (model0.get_lvalue (expr, &ctxt),
                      model0.get_rvalue (val_a, &ctxt),
@@ -8776,13 +8794,14 @@ test_state_merging ()
                       ptr_type_node);
   DECL_CONTEXT (q) = test_fndecl;
 
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   program_point point (program_point::origin (mgr));
 
   {
-    region_model model0 (&mgr);
-    region_model model1 (&mgr);
-    region_model merged (&mgr);
+    region_model model0 (node_mgr);
+    region_model model1 (node_mgr);
+    region_model merged (node_mgr);
     /* Verify empty models can be merged.  */
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
     ASSERT_EQ (model0, merged);
@@ -8793,9 +8812,9 @@ test_state_merging ()
   /* TODO: verify that the merged model doesn't have a value for
      the global  */
   {
-    region_model model0 (&mgr);
-    region_model model1 (&mgr);
-    region_model merged (&mgr);
+    region_model model0 (node_mgr);
+    region_model model1 (node_mgr);
+    region_model merged (node_mgr);
     test_region_model_context ctxt;
     model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
     model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
@@ -8807,8 +8826,8 @@ test_state_merging ()
   /* Verify handling of a PARM_DECL.  */
   {
     test_region_model_context ctxt;
-    region_model model0 (&mgr);
-    region_model model1 (&mgr);
+    region_model model0 (node_mgr);
+    region_model model1 (node_mgr);
     ASSERT_EQ (model0.get_stack_depth (), 0);
     model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
                       nullptr, nullptr, &ctxt);
@@ -8823,7 +8842,7 @@ test_state_merging ()
     ASSERT_EQ (model0, model1);
 
     /* They should be mergeable, and the result should be the same.  */
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
     ASSERT_EQ (model0, merged);
     /* In particular, "a" should have the placeholder value.  */
@@ -8833,8 +8852,8 @@ test_state_merging ()
   /* Verify handling of a global.  */
   {
     test_region_model_context ctxt;
-    region_model model0 (&mgr);
-    region_model model1 (&mgr);
+    region_model model0 (node_mgr);
+    region_model model1 (node_mgr);
 
     placeholder_svalue test_sval (mgr.alloc_node_id (),
                                  integer_type_node, "test sval");
@@ -8843,7 +8862,7 @@ test_state_merging ()
     ASSERT_EQ (model0, model1);
 
     /* They should be mergeable, and the result should be the same.  */
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
     ASSERT_EQ (model0, merged);
     /* In particular, "x" should have the placeholder value.  */
@@ -8854,7 +8873,7 @@ test_state_merging ()
 
   /* Two equal constant values.  */
   {
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     const svalue *merged_x_sval;
     assert_region_models_merge (x, int_42, int_42, &merged, &merged_x_sval);
 
@@ -8866,7 +8885,7 @@ test_state_merging ()
 
   /* Two non-equal constant values.  */
   {
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     const svalue *merged_x_sval;
     assert_region_models_merge (x, int_42, int_113, &merged, &merged_x_sval);
 
@@ -8876,7 +8895,7 @@ test_state_merging ()
 
   /* Initial and constant.  */
   {
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     const svalue *merged_x_sval;
     assert_region_models_merge (x, NULL_TREE, int_113, &merged, 
&merged_x_sval);
 
@@ -8886,7 +8905,7 @@ test_state_merging ()
 
   /* Constant and initial.  */
   {
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     const svalue *merged_x_sval;
     assert_region_models_merge (x, int_42, NULL_TREE, &merged, &merged_x_sval);
 
@@ -8905,7 +8924,7 @@ test_state_merging ()
 
   /* Pointers: non-NULL and non-NULL: ptr to a local.  */
   {
-    region_model model0 (&mgr);
+    region_model model0 (node_mgr);
     model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
                       nullptr, nullptr, nullptr);
     model0.set_value (model0.get_lvalue (p, nullptr),
@@ -8915,14 +8934,14 @@ test_state_merging ()
     ASSERT_EQ (model0, model1);
 
     /* They should be mergeable, and the result should be the same.  */
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
     ASSERT_EQ (model0, merged);
   }
 
   /* Pointers: non-NULL and non-NULL: ptr to a global.  */
   {
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     /* p == &y in both input models.  */
     const svalue *merged_p_sval;
     assert_region_models_merge (p, addr_of_y, addr_of_y, &merged,
@@ -8939,13 +8958,13 @@ test_state_merging ()
   /* Pointers: non-NULL ptrs to different globals should not merge;
      see e.g. gcc.dg/analyzer/torture/uninit-pr108725.c  */
   {
-    region_model merged_model (&mgr);
+    region_model merged_model (node_mgr);
     program_point point (program_point::origin (mgr));
     test_region_model_context ctxt;
     /* x == &y vs x == &z in the input models; these are actually casts
        of the ptrs to "int".  */
-    region_model model0 (&mgr);
-    region_model model1 (&mgr);
+    region_model model0 (node_mgr);
+    region_model model1 (node_mgr);
     model0.set_value (model0.get_lvalue (x, &ctxt),
                      model0.get_rvalue (addr_of_y, &ctxt),
                      &ctxt);
@@ -8959,7 +8978,7 @@ test_state_merging ()
   /* Pointers: non-NULL and non-NULL: ptr to a heap region.  */
   {
     test_region_model_context ctxt;
-    region_model model0 (&mgr);
+    region_model model0 (node_mgr);
     tree size = build_int_cst (size_type_node, 1024);
     const svalue *size_sval = mgr.get_or_create_constant_svalue (size);
     const region *new_reg
@@ -8972,7 +8991,7 @@ test_state_merging ()
 
     ASSERT_EQ (model0, model1);
 
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
 
     /* The merged model ought to be identical.  */
@@ -8983,7 +9002,7 @@ test_state_merging ()
      it after self-merger.  */
   {
     test_region_model_context ctxt;
-    region_model model0 (&mgr);
+    region_model model0 (node_mgr);
     placeholder_svalue placeholder_sval (mgr.alloc_node_id (),
                                         integer_type_node, "test");
     model0.set_value (model0.get_lvalue (x, &ctxt),
@@ -8992,7 +9011,7 @@ test_state_merging ()
     region_model model1 (model0);
 
     /* They should be mergeable, and the result should be the same.  */
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
     ASSERT_EQ (model0, merged);
 
@@ -9002,23 +9021,23 @@ test_state_merging ()
   }
 
   {
-    region_model model0 (&mgr);
-    region_model model1 (&mgr);
+    region_model model0 (node_mgr);
+    region_model model1 (node_mgr);
     test_region_model_context ctxt;
     model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
     model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
   }
 
   {
-    region_model model0 (&mgr);
-    region_model model1 (&mgr);
+    region_model model0 (node_mgr);
+    region_model model1 (node_mgr);
     test_region_model_context ctxt;
     model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
     model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
     model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
   }
 
@@ -9034,7 +9053,7 @@ test_state_merging ()
   /* Views.  */
   {
     test_region_model_context ctxt;
-    region_model model0 (&mgr);
+    region_model model0 (node_mgr);
 
     const region *x_reg = model0.get_lvalue (x, &ctxt);
     const region *x_as_ptr = mgr.get_cast_region (x_reg, ptr_type_node);
@@ -9044,14 +9063,14 @@ test_state_merging ()
     ASSERT_EQ (model1, model0);
 
     /* They should be mergeable, and the result should be the same.  */
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
   }
 
   /* Verify that we can merge a model in which a local in an older stack
      frame points to a local in a more recent stack frame.  */
   {
-    region_model model0 (&mgr);
+    region_model model0 (node_mgr);
     model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
                       nullptr, nullptr, nullptr);
     const region *q_in_first_frame = model0.get_lvalue (q, nullptr);
@@ -9077,7 +9096,7 @@ test_state_merging ()
 
     /* They should be mergeable, and the result should be the same
        (after canonicalization, at least).  */
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
     merged.canonicalize ();
     ASSERT_EQ (model0, merged);
@@ -9085,7 +9104,7 @@ test_state_merging ()
 
   /* Verify that we can merge a model in which a local points to a global.  */
   {
-    region_model model0 (&mgr);
+    region_model model0 (node_mgr);
     model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
                       nullptr, nullptr, nullptr);
     model0.set_value (model0.get_lvalue (q, nullptr),
@@ -9096,7 +9115,7 @@ test_state_merging ()
 
     /* They should be mergeable, and the result should be the same
        (after canonicalization, at least).  */
-    region_model merged (&mgr);
+    region_model merged (node_mgr);
     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
     ASSERT_EQ (model0, merged);
   }
@@ -9115,17 +9134,18 @@ test_constraint_merging ()
   tree z = build_global_decl ("z", integer_type_node);
   tree n = build_global_decl ("n", integer_type_node);
 
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   test_region_model_context ctxt;
 
   /* model0: 0 <= (x == y) < n.  */
-  region_model model0 (&mgr);
+  region_model model0 (node_mgr);
   model0.add_constraint (x, EQ_EXPR, y, &ctxt);
   model0.add_constraint (x, GE_EXPR, int_0, nullptr);
   model0.add_constraint (x, LT_EXPR, n, nullptr);
 
   /* model1: z != 5 && (0 <= x < n).  */
-  region_model model1 (&mgr);
+  region_model model1 (node_mgr);
   model1.add_constraint (z, NE_EXPR, int_5, nullptr);
   model1.add_constraint (x, GE_EXPR, int_0, nullptr);
   model1.add_constraint (x, LT_EXPR, n, nullptr);
@@ -9133,7 +9153,7 @@ test_constraint_merging ()
   /* They should be mergeable; the merged constraints should
      be: (0 <= x < n).  */
   program_point point (program_point::origin (mgr));
-  region_model merged (&mgr);
+  region_model merged (node_mgr);
   ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
 
   ASSERT_EQ (merged.eval_condition (x, GE_EXPR, int_0, &ctxt),
@@ -9153,7 +9173,8 @@ test_constraint_merging ()
 static void
 test_widening_constraints ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   const supernode *snode = nullptr;
   tree int_0 = integer_zero_node;
   tree int_m1 = build_int_cst (integer_type_node, -1);
@@ -9268,7 +9289,8 @@ test_widening_constraints ()
 static void
 test_iteration_1 ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   program_point point (program_point::origin (mgr));
 
   tree int_0 = integer_zero_node;
@@ -9279,15 +9301,15 @@ test_iteration_1 ()
   test_region_model_context ctxt;
 
   /* model0: i: 0.  */
-  region_model model0 (&mgr);
+  region_model model0 (node_mgr);
   model0.set_value (i, int_0, &ctxt);
 
   /* model1: i: 1.  */
-  region_model model1 (&mgr);
+  region_model model1 (node_mgr);
   model1.set_value (i, int_1, &ctxt);
 
   /* Should merge "i" to a widened value.  */
-  region_model model2 (&mgr);
+  region_model model2 (node_mgr);
   ASSERT_TRUE (model1.can_merge_with_p (model0, point, &model2));
   const svalue *merged_i = model2.get_rvalue (i, &ctxt);
   ASSERT_EQ (merged_i->get_kind (), SK_WIDENING);
@@ -9302,7 +9324,7 @@ test_iteration_1 ()
             tristate (tristate::TS_TRUE));
 
   /* Try merging with the initial state.  */
-  region_model model3 (&mgr);
+  region_model model3 (node_mgr);
   ASSERT_TRUE (model2.can_merge_with_p (model0, point, &model3));
   /* Merging the merged value with the initial value should be idempotent,
      so that the analysis converges.  */
@@ -9323,7 +9345,7 @@ test_iteration_1 ()
   ASSERT_EQ (plus_one->get_kind (), SK_BINOP);
 
   /* Try merging with the "i: 1" state.  */
-  region_model model5 (&mgr);
+  region_model model5 (node_mgr);
   ASSERT_TRUE (model4.can_merge_with_p (model1, point, &model5));
   ASSERT_EQ (model5.get_rvalue (i, &ctxt), plus_one);
   ASSERT_EQ (model5, model4);
@@ -9331,7 +9353,7 @@ test_iteration_1 ()
   /* "i_11 = PHI();" merge with state at phi above.
      For i, we should have a merger of WIDENING with WIDENING + 1,
      and this should be WIDENING again.  */
-  region_model model6 (&mgr);
+  region_model model6 (node_mgr);
   ASSERT_TRUE (model5.can_merge_with_p (model2, point, &model6));
   const svalue *merged_widening = model6.get_rvalue (i, &ctxt);
   ASSERT_EQ (merged_widening->get_kind (), SK_WIDENING);
@@ -9343,8 +9365,9 @@ test_iteration_1 ()
 static void
 test_malloc_constraints ()
 {
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+  region_model model (node_mgr);
   tree p = build_global_decl ("p", ptr_type_node);
   tree char_star = build_pointer_type (char_type_node);
   tree q = build_global_decl ("q", char_star);
@@ -9382,8 +9405,9 @@ test_var ()
   tree int_17 = build_int_cst (integer_type_node, 17);
   tree int_m3 = build_int_cst (integer_type_node, -3);
 
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+  region_model model (node_mgr);
 
   const region *i_reg = model.get_lvalue (i, nullptr);
   ASSERT_EQ (i_reg->get_kind (), RK_DECL);
@@ -9439,8 +9463,9 @@ test_array_2 ()
   tree int_42 = build_int_cst (integer_type_node, 42);
   tree int_m3 = build_int_cst (integer_type_node, -3);
 
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+  region_model model (node_mgr);
   /* "arr[0] = 17;".  */
   model.set_value (arr_0, int_17, nullptr);
   /* "arr[1] = -3;".  */
@@ -9515,8 +9540,8 @@ test_mem_ref ()
   tree offset_0 = build_int_cst (ptype, 0);
   tree star_p = build2 (MEM_REF, integer_type_node, p, offset_0);
 
-  region_model_manager mgr;
-  region_model model (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model model (node_mgr);
 
   /* "x = 17;".  */
   model.set_value (x, int_17, nullptr);
@@ -9566,8 +9591,8 @@ test_POINTER_PLUS_EXPR_then_MEM_REF ()
   tree offset_0 = build_int_cst (ptype, 0);
   tree mem_ref = build2 (MEM_REF, integer_type_node,
                         pointer_plus_expr, offset_0);
-  region_model_manager mgr;
-  region_model m (&mgr);
+  symbolic::node_manager node_mgr;
+  region_model m (node_mgr);
 
   tree int_42 = build_int_cst (integer_type_node, 42);
   m.set_value (mem_ref, int_42, nullptr);
@@ -9585,14 +9610,15 @@ test_malloc ()
   tree n_times_4 = build2 (MULT_EXPR, size_type_node,
                           n, build_int_cst (size_type_node, 4));
 
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
   test_region_model_context ctxt;
-  region_model model (&mgr);
+  region_model model (node_mgr);
 
   /* "p = malloc (n * 4);".  */
   const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
   const region *reg
     = model.get_or_create_region_for_heap_alloc (size_sval, &ctxt);
+  auto &mgr = node_mgr.get_region_model_manager ();
   const svalue *ptr = mgr.get_ptr_svalue (int_star, reg);
   model.set_value (model.get_lvalue (p, &ctxt), ptr, &ctxt);
   ASSERT_EQ (model.get_capacity (reg), size_sval);
@@ -9616,9 +9642,10 @@ test_alloca ()
   tree n_times_4 = build2 (MULT_EXPR, size_type_node,
                           n, build_int_cst (size_type_node, 4));
 
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
   test_region_model_context ctxt;
-  region_model model (&mgr);
+  region_model model (node_mgr);
 
   /* Push stack frame.  */
   const region *frame_reg
@@ -9643,13 +9670,15 @@ test_alloca ()
 static void
 test_involves_p ()
 {
-  region_model_manager mgr;
+  symbolic::node_manager node_mgr;
+  auto &mgr = node_mgr.get_region_model_manager ();
+
   tree int_star = build_pointer_type (integer_type_node);
   tree p = build_global_decl ("p", int_star);
   tree q = build_global_decl ("q", int_star);
 
   test_region_model_context ctxt;
-  region_model model (&mgr);
+  region_model model (node_mgr);
   const svalue *p_init = model.get_rvalue (p, &ctxt);
   const svalue *q_init = model.get_rvalue (q, &ctxt);
 
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 90aed12d076..097758c6860 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -295,7 +295,7 @@ class region_model
  public:
   typedef region_to_value_map dynamic_extents_t;
 
-  region_model (region_model_manager *mgr);
+  region_model (symbolic::node_manager &node_mgr);
   region_model (const region_model &other);
   ~region_model ();
   region_model &operator= (const region_model &other);
@@ -491,10 +491,11 @@ class region_model
                            region_model_context *ctxt);
   void unset_dynamic_extents (const region *reg);
 
+  symbolic::node_manager &get_node_manager () const { return m_node_mgr; }
   region_model_manager *get_manager () const { return m_mgr; }
   bounded_ranges_manager *get_range_manager () const
   {
-    return m_mgr->get_range_manager ();
+    return get_manager ()->get_range_manager ();
   }
 
   void unbind_region_and_descendents (const region *reg,
@@ -724,6 +725,9 @@ private:
                                    region_model_context *ctxt);
 
   /* Storing this here to avoid passing it around everywhere.  */
+  symbolic::node_manager &m_node_mgr;
+
+  // TODO: eliminate this copy (kept here to minimize churn)
   region_model_manager *const m_mgr;
 
   store m_store;
@@ -1326,19 +1330,31 @@ private:
 class engine
 {
 public:
-  engine (region_model_manager &mgr,
+  engine (symbolic::node_manager &node_mgr,
          const supergraph *sg = nullptr);
   const supergraph *get_supergraph () { return m_sg; }
-  region_model_manager *get_model_manager () { return &m_mgr; }
+
+  symbolic::node_manager &
+  get_node_manager ()
+  {
+    return m_node_mgr;
+  }
+
+  region_model_manager *
+  get_model_manager ()
+  {
+    return &m_node_mgr.get_region_model_manager ();
+  }
+
   known_function_manager *get_known_function_manager ()
   {
-    return m_mgr.get_known_function_manager ();
+    return get_model_manager ()->get_known_function_manager ();
   }
 
   void log_stats (logger *logger) const;
 
 private:
-  region_model_manager &m_mgr;
+  symbolic::node_manager &m_node_mgr;
   const supergraph *m_sg;
 };
 
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 4bb96119c93..974094d7251 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -1913,7 +1913,7 @@ decl_region::get_svalue_for_initializer 
(region_model_manager *mgr) const
     return get_svalue_for_constructor (init, mgr);
 
   /* Reuse the get_rvalue logic from region_model.  */
-  region_model m (mgr);
+  region_model m (mgr->get_node_manager ());
   return m.get_rvalue (path_var (init, 0), nullptr);
 }
 
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index 08a0a2ad5eb..b4ebcc99051 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -194,7 +194,7 @@ update_model_for_signal_handler (region_model *model,
 {
   gcc_assert (model);
   /* Purge all state within MODEL.  */
-  *model = region_model (model->get_manager ());
+  *model = region_model (model->get_node_manager ());
   model->push_frame (handler_fun, nullptr, nullptr, nullptr);
 }
 
diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc
index 6b2f7996de5..e5c7593eaf9 100644
--- a/gcc/analyzer/state-purge.cc
+++ b/gcc/analyzer/state-purge.cc
@@ -538,7 +538,7 @@ state_purge_per_decl::process_worklists (const 
state_purge_map &map,
     for (auto iter : m_snodes_needing_decl)
       worklist.safe_push (iter);
 
-    region_model model (mgr);
+    region_model model (mgr->get_node_manager ());
     model.push_frame (get_function (), nullptr, nullptr, nullptr);
 
     /* Process worklist by walking backwards until we reach a stmt
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index 66cfd3ddddf..ce6797664b5 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -1325,7 +1325,7 @@ static const svalue *
 get_svalue_for_ctor_val (tree val, region_model_manager *mgr)
 {
   /* Reuse the get_rvalue logic from region_model.  */
-  region_model m (mgr);
+  region_model m (mgr->get_node_manager ());
   return m.get_rvalue (path_var (val, 0), nullptr);
 }
 
@@ -4403,7 +4403,8 @@ test_binding_key_overlap ()
 static void
 test_binding_map_ops ()
 {
-  region_model_manager region_mgr;
+  symbolic::node_manager node_mgr;
+  auto &region_mgr = node_mgr.get_region_model_manager ();
   store_manager store_mgr (&region_mgr);
 
   /* Assignment of empty.  */
diff --git a/gcc/analyzer/symbolic-nodes.cc b/gcc/analyzer/symbolic-nodes.cc
index 2c45feb5144..1c17a8d08d3 100644
--- a/gcc/analyzer/symbolic-nodes.cc
+++ b/gcc/analyzer/symbolic-nodes.cc
@@ -21,6 +21,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "analyzer/common.h"
 
 #include "analyzer/symbolic-nodes.h"
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/region-model.h"
+#include "analyzer/region-model-manager.h"
 
 #if ENABLE_ANALYZER
 
@@ -34,6 +37,27 @@ symbolic::node::cmp_ids (const symbolic::node *n1, const 
symbolic::node *n2)
   return (long)n1->get_id () - (long)n2->get_id ();
 }
 
+// class node_manager
+
+symbolic::node_manager::node_manager ()
+: m_next_node_id (0),
+  m_rmm (std::make_unique<region_model_manager> (*this))
+{
+}
+
+symbolic::node_manager::~node_manager () = default;
+
+/* Dump the various managers to LOGGER.
+   If SHOW_OBJS is true, also dump the objects themselves.  */
+
+void
+symbolic::node_manager::log_stats (logger *logger, bool show_objs) const
+{
+  LOG_SCOPE (logger);
+
+  m_rmm->log_stats (logger, show_objs);
+}
+
 } // namespace ana
 
 #endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/symbolic-nodes.h b/gcc/analyzer/symbolic-nodes.h
index 990d7c6cb6a..20e0ccaa877 100644
--- a/gcc/analyzer/symbolic-nodes.h
+++ b/gcc/analyzer/symbolic-nodes.h
@@ -26,6 +26,41 @@ along with GCC; see the file COPYING3.  If not see
 namespace ana {
 namespace symbolic {
 
+/* A central hub for managing symbolic::node instances
+   - Provides a central authority for handing out IDs for new nodes.
+   - Owns the various managers of symbolic::node subclasses and provides
+   a central place for them to find each other.
+
+   We use pointers to the managers to minimize compile-time dependencies.
+
+   This is effectively a singleton during analysis (but each unit test
+   gets its own instance).  */
+
+class node_manager
+{
+public:
+  node_manager ();
+  ~node_manager ();
+
+  node_manager (const node_manager &) = delete;
+
+  unsigned get_num_nodes () const { return m_next_node_id; }
+  unsigned alloc_node_id () { return m_next_node_id++; }
+
+  region_model_manager &
+  get_region_model_manager () const { return *m_rmm; }
+
+  region_model_manager &
+  get_svalue_manager () const { return *m_rmm; }
+
+  void log_stats (logger *logger, bool show_objs) const;
+
+private:
+  unsigned m_next_node_id;
+
+  std::unique_ptr<region_model_manager> m_rmm;
+};
+
 /* Abstract base class for the various tree-like purely-functional
    data structures we use during symbolic execution.
 
-- 
2.56.0

Reply via email to