]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
analyzer: use concrete_binding_map for compound_svalue (PR analyzer/123145)
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 15 Jan 2026 19:17:08 +0000 (14:17 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Tue, 28 Apr 2026 23:11:28 +0000 (19:11 -0400)
A compound_svalue can only have concrete bindings.  Capture this in the
type system by splitting out the concrete parts of class binding_map
into a new class concrete_binding_map, and use the latter for
compound_svalue.  This also allows some simplifications and
optimizations, where we can use bit_range rather than binding keys.

No functional change intended.

gcc/analyzer/ChangeLog:
PR analyzer/123145
* access-diagram.cc
(compound_svalue_spatial_item::compound_svalue_spatial_item):
Update for compound_svalue using concrete_binding_map rather than
binding_map.
* bounds-checking.cc (strip_types): Likewise.
* call-summary.cc
(call_summary_replay::convert_svalue_from_summary_1): Update for
reimplementation of class binding_map.
(call_summary_replay::convert_svalue_from_summary_1): Likewise.
* infinite-recursion.cc (contains_unknown_p): Update for
compound_svalue using concrete_binding_map rather than
binding_map.
* program-state.cc (sm_state_map::impl_set_state): Likewise.
* region-model-manager.cc (maybe_undo_optimize_bit_field_compare):
Likewise.
(maybe_undo_optimize_bit_field_compare): Avoid building a
concrete_binding key by using get_any_exact_binding.
(region_model_manager::get_or_create_compound_svalue): New
overload, consuming a concrete_binding_map &&.
* region-model-manager.h
(region_model_manager::get_or_create_compound_svalue): New decl
for the above.
* region-model-reachability.cc (reachable_regions::handle_sval):
Update for compound_svalue using concrete_binding_map rather than
binding_map.
(reachable_regions::handle_parm): Likewise.
* region-model.cc (region_model::scan_for_null_terminator_1): Port
from binding_map to concrete_binding_map.
(exposure_through_uninit_copy::calc_num_uninit_bits): Update for
compound_svalue using concrete_binding_map rather than
binding_map.
(contains_uninit_p): Likewise.
* region.cc (decl_region::calc_svalue_for_constructor): Port from
binding_map to concrete_binding_map.
(decl_region::get_svalue_for_initializer): Update call to
get_or_create_compound_svalue.
* store.cc (concrete_binding_map::dump_to_pp): New.
(concrete_binding_map::dump): New.
(concrete_binding_map::add_to_tree_widget): New.
(concrete_binding_map::validate): New.
(binding_map::cmp): Convert to...
(concrete_binding_map::cmp): ...this.
(concrete_binding_map::get_any_exact_binding): New.
(concrete_binding_map::calc_complexity): New.
(concrete_binding_map::remove_overlapping_binding): New.
(concrete_binding_map::remove_overlapping_bindings): New.
(concrete_binding_map::get_overlapping_bindings): New.
(binding_map::put): Update for change to m_concrete.
(binding_map::validate): Likewise.
(binding_map::apply_ctor_to_region): Convert to...
(concrete_binding_map::apply_ctor_to_region): ...this.
(binding_map::apply_ctor_val_to_range): Convert to...
(concrete_binding_map::apply_ctor_val_to_range): ...this.
(binding_map::apply_ctor_pair_to_child_region): Convert to...
(concrete_binding_map::apply_ctor_pair_to_child_region): ...this.
(binding_map::remove_overlapping_bindings): Move part of
implementation to
concrete_binding_map::remove_overlapping_binding.
(binding_cluster::bind_compound_sval): Simplify using
concrete_binding_map.
(binding_cluster::maybe_get_compound_binding): Likewise.
(store::replay_call_summary_cluster): Update for change
to compound_svalue.
* store.h: Include "analyzer/complexity.h".
(class concrete_binding_map): New, based on
binding_map::concrete_bindings_t.
(binding_map::concrete_bindings_t): Use concrete_binding_map.
(binding_map::empty_p): Update for above.
(binding_map::apply_ctor_to_region): Drop decl.
(binding_map::cmp): Likewise.
(binding_map::apply_ctor_val_to_range): Likewise.
(binding_map::apply_ctor_pair_to_child_region): Likewise.
* svalue.cc (svalue::cmp_ptr): Update for change to
compound_svalue.
(compound_svalue::compound_svalue): Port from binding_map to
concrete_binding_map.
(compound_svalue::accept): Likewise.
(compound_svalue::calc_complexity): Drop.
(compound_svalue::maybe_fold_bits_within): Port from binding_map
to concrete_binding_map.
* svalue.h (class compound_svalue): Update leading comment.  Port
from binding_map to concrete_binding_map.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
14 files changed:
gcc/analyzer/access-diagram.cc
gcc/analyzer/bounds-checking.cc
gcc/analyzer/call-summary.cc
gcc/analyzer/infinite-recursion.cc
gcc/analyzer/program-state.cc
gcc/analyzer/region-model-manager.cc
gcc/analyzer/region-model-manager.h
gcc/analyzer/region-model-reachability.cc
gcc/analyzer/region-model.cc
gcc/analyzer/region.cc
gcc/analyzer/store.cc
gcc/analyzer/store.h
gcc/analyzer/svalue.cc
gcc/analyzer/svalue.h

index 9f412b5ec76c9c34e5a1aba5f9057ec1a477eb94..6a3ad635f0c0cc83cafc30d49f7f9be2d4d54a18 100644 (file)
@@ -1212,23 +1212,18 @@ public:
   : svalue_spatial_item (sval, bits, kind),
     m_compound_sval (sval)
   {
-    const binding_map &map = m_compound_sval.get_map ();
+    const concrete_binding_map &map = m_compound_sval.get_concrete_bindings ();
     auto_vec <const binding_key *> binding_keys;
     for (auto iter : map)
       {
-       const binding_key *key = iter.m_key;
-       const svalue *bound_sval = iter.m_sval;
-       if (const concrete_binding *concrete_key
-             = key->dyn_cast_concrete_binding ())
-         {
-           access_range range (nullptr,
-                               concrete_key->get_bit_range ());
-           if (std::unique_ptr<spatial_item> child
-                 = make_existing_svalue_spatial_item (bound_sval,
-                                                      range,
-                                                      theme))
-             m_children.push_back (std::move (child));
-         }
+       const bit_range &key = iter.first;
+       const svalue *bound_sval = iter.second;
+       access_range range (nullptr, key);
+       if (std::unique_ptr<spatial_item> child
+           = make_existing_svalue_spatial_item (bound_sval,
+                                                range,
+                                                theme))
+         m_children.push_back (std::move (child));
       }
   }
 
index 8d78581a3df98ef6bad2fb8c771a071cf6c441ff..f9b5165a7cbccc373ee96d3df01d4c08ce7bbc9c 100644 (file)
@@ -1334,14 +1334,15 @@ strip_types (const svalue *sval,
     case SK_COMPOUND:
       {
        const compound_svalue *compound_sval = (const compound_svalue *)sval;
-       binding_map typeless_map (*mgr.get_store_manager ());
-       for (auto iter : compound_sval->get_map ())
+       concrete_binding_map typeless_map;
+       for (auto iter : compound_sval->get_concrete_bindings ())
          {
-           const binding_key *key = iter.m_key;
-           const svalue *bound_sval = iter.m_sval;
-           typeless_map.put (key, strip_types (bound_sval, mgr));
+           const bit_range &bits = iter.first;
+           const svalue *bound_sval = iter.second;
+           typeless_map.insert (bits, strip_types (bound_sval, mgr));
          }
-       return mgr.get_or_create_compound_svalue (NULL_TREE, typeless_map);
+       return mgr.get_or_create_compound_svalue (NULL_TREE,
+                                                 std::move (typeless_map));
       }
     case SK_CONJURED:
       return sval;
index 7a3d4aac7c68af979d058b3454a744210b5898d6..9220958afcaa8a8e02fd76a829284971c789b81f 100644 (file)
@@ -421,19 +421,12 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)
        const compound_svalue *compound_summary_sval
          = as_a <const compound_svalue *> (summary_sval);
        region_model_manager *mgr = get_manager ();
-       store_manager *store_mgr = mgr->get_store_manager ();
-       binding_map caller_map (*store_mgr);
-       auto_vec <const binding_key *> summary_keys;
-       for (auto kv : *compound_summary_sval)
-         summary_keys.safe_push (kv.m_key);
-       summary_keys.qsort (binding_key::cmp_ptrs);
-       for (auto key : summary_keys)
+       concrete_binding_map caller_map;
+       for (auto iter_summary : *compound_summary_sval)
          {
-           gcc_assert (key->concrete_p ());
            /* No remapping is needed for concrete binding keys.  */
-
-           const svalue *bound_summary_sval
-             = compound_summary_sval->get_map ().get (key);
+           const bit_range &summary_bits = iter_summary.first;
+           const svalue *bound_summary_sval = iter_summary.second;
            const svalue *caller_sval
              = convert_svalue_from_summary (bound_summary_sval);
            if (!caller_sval)
@@ -442,31 +435,26 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)
            if (const compound_svalue *inner_compound_sval
                = caller_sval->dyn_cast_compound_svalue ())
              {
-               const concrete_binding *outer_key
-                 = as_a <const concrete_binding *> (key);
+               const bit_range &outer_key = summary_bits;
                for (auto inner_kv : *inner_compound_sval)
                  {
                    // These should already be mapped to the caller.
-                   const binding_key *inner_key = inner_kv.m_key;
-                   const svalue *inner_sval = inner_kv.m_sval;
-                   gcc_assert (inner_key->concrete_p ());
-                   const concrete_binding *concrete_key
-                     = as_a <const concrete_binding *> (inner_key);
+                   const bit_range &inner_key = inner_kv.first;
+                   const svalue *inner_sval = inner_kv.second;
                    bit_offset_t effective_start
-                     = (concrete_key->get_start_bit_offset ()
-                        + outer_key->get_start_bit_offset ());
-                   const concrete_binding *effective_concrete_key
-                     = store_mgr->get_concrete_binding
-                         (effective_start,
-                          concrete_key->get_size_in_bits ());
-                   caller_map.put (effective_concrete_key, inner_sval);
+                     = (inner_key.get_start_bit_offset ()
+                        + outer_key.get_start_bit_offset ());
+                   const bit_range effective_concrete_key
+                     (effective_start,
+                      summary_bits.m_size_in_bits);
+                   caller_map.insert (effective_concrete_key, inner_sval);
                  }
              }
            else
-             caller_map.put (key, caller_sval);
+             caller_map.insert (summary_bits, caller_sval);
          }
        return mgr->get_or_create_compound_svalue (summary_sval->get_type (),
-                                                  caller_map);
+                                                  std::move (caller_map));
       }
       break;
     case SK_CONJURED:
index 64eeb95de66e6c2b60898d7ee1186c556dc710ea..c1dc6e49b9b4d9c73854eaeb094708eb4f24b287 100644 (file)
@@ -396,7 +396,7 @@ contains_unknown_p (const svalue *sval)
   if (const compound_svalue *compound_sval
        = sval->dyn_cast_compound_svalue ())
     for (auto iter : *compound_sval)
-      if (iter.m_sval->get_kind () == SK_UNKNOWN)
+      if (iter.second->get_kind () == SK_UNKNOWN)
        return true;
   return false;
 }
index 08d6b5599504f5298778ce521fbb2e2dfd4b0b8a..5ebaafb2661f9a9fb2ee27f616cbdfe532387ea3 100644 (file)
@@ -565,7 +565,7 @@ sm_state_map::impl_set_state (const svalue *sval,
        for (auto iter = compound_sval->begin ();
             iter != compound_sval->end (); ++iter)
          {
-           const svalue *inner_sval = iter.get_svalue ();
+           const svalue *inner_sval = iter->second;
            if (inner_sval->can_have_associated_state_p ())
              impl_set_state (inner_sval, state, origin, ext_state);
          }
index c4f91ecd6884edace0fb6e4a451c0808fcfbe0a1..ba7f9db507b6c5c76755ba16a3c607fb9a326bfd 100644 (file)
@@ -639,7 +639,7 @@ maybe_undo_optimize_bit_field_compare (tree type,
   if (!INTEGRAL_TYPE_P (type))
     return nullptr;
 
-  const binding_map &map = compound_sval->get_map ();
+  const concrete_binding_map &map = compound_sval->get_concrete_bindings ();
   unsigned HOST_WIDE_INT mask = TREE_INT_CST_LOW (cst);
   /* If "mask" is a contiguous range of set bits, see if the
      compound_sval has a value for those bits.  */
@@ -651,11 +651,13 @@ maybe_undo_optimize_bit_field_compare (tree type,
   if (BYTES_BIG_ENDIAN)
     bound_bits = bit_range (BITS_PER_UNIT - bits.get_next_bit_offset (),
                            bits.m_size_in_bits);
-  const concrete_binding *conc
-    = get_store_manager ()->get_concrete_binding (bound_bits);
-  const svalue *sval = map.get (conc);
+  const svalue *sval = map.get_any_exact_binding (bound_bits);
   if (!sval)
-    return nullptr;
+    {
+      /* In theory we could also look for bindings that straddle the
+        bit range.  For simplicity, bail out on this case.  */
+      return nullptr;
+    }
 
   /* We have a value;
      shift it by the correct number of bits.  */
@@ -1406,7 +1408,26 @@ get_or_create_widening_svalue (tree type,
 
 const svalue *
 region_model_manager::get_or_create_compound_svalue (tree type,
-                                                    const binding_map &map)
+                                                    concrete_binding_map &&map)
+{
+  compound_svalue::key_t tmp_key (type, &map);
+  if (compound_svalue **slot = m_compound_values_map.get (tmp_key))
+    return *slot;
+  compound_svalue *compound_sval
+    = new compound_svalue (alloc_symbol_id (), type, std::move (map));
+  RETURN_UNKNOWN_IF_TOO_COMPLEX (compound_sval);
+  /* Use make_key rather than reusing the key, so that we use a
+     ptr to compound_sval's binding_map, rather than the MAP param.  */
+  m_compound_values_map.put (compound_sval->make_key (), compound_sval);
+  return compound_sval;
+}
+
+/* Return the svalue * of type TYPE for the compound values in MAP,
+   creating it if necessary.  */
+
+const svalue *
+region_model_manager::get_or_create_compound_svalue (tree type,
+                                                    const concrete_binding_map &map)
 {
   compound_svalue::key_t tmp_key (type, &map);
   if (compound_svalue **slot = m_compound_values_map.get (tmp_key))
index 44122ec05f61621beb301917b8d3f5e2ef4891b8..02b5125c435b81d91b86e795da6659a277df5f8c 100644 (file)
@@ -77,7 +77,9 @@ public:
                                               const svalue *base_svalue,
                                               const svalue *iter_svalue);
   const svalue *get_or_create_compound_svalue (tree type,
-                                              const binding_map &map);
+                                              concrete_binding_map &&map);
+  const svalue *get_or_create_compound_svalue (tree type,
+                                              const concrete_binding_map &map);
   const svalue *get_or_create_conjured_svalue (tree type, const gimple *stmt,
                                               const region *id_reg,
                                               const conjured_purge &p,
index 19b96b982809b40dbb5c29f460bf81af5cedb970..e9e8edfcc1a715fd426c2a69d3ea7e610718584f 100644 (file)
@@ -172,7 +172,7 @@ reachable_regions::handle_sval (const svalue *sval)
       for (auto iter = compound_sval->begin ();
           iter != compound_sval->end (); ++iter)
        {
-         const svalue *iter_sval = iter.get_svalue ();
+         const svalue *iter_sval = iter->second;
          handle_sval (iter_sval);
        }
     }
@@ -238,7 +238,7 @@ reachable_regions::handle_parm (const svalue *sval, tree param_type)
       for (auto iter = compound_sval->begin ();
           iter != compound_sval->end (); ++iter)
        {
-         const svalue *iter_sval = iter.get_svalue ();
+         const svalue *iter_sval = iter->second;
          handle_sval (iter_sval);
        }
     }
index d46b130b00d966b3652f55cea411c40b8aea630f..6e25029d9d25af1e613b9ee8518b5c1c92c204d5 100644 (file)
@@ -4701,7 +4701,6 @@ region_model::scan_for_null_terminator_1 (const region *reg,
                                          region_model_context *ctxt) const
 {
   logger *logger = ctxt ? ctxt->get_logger () : nullptr;
-  store_manager *store_mgr = m_mgr->get_store_manager ();
 
   region_offset offset = reg->get_offset (m_mgr);
   if (offset.symbolic_p ())
@@ -4764,7 +4763,7 @@ region_model::scan_for_null_terminator_1 (const region *reg,
       logger->end_log_line ();
     }
 
-  binding_map result (*store_mgr);
+  concrete_binding_map result;
 
   while (1)
     {
@@ -4809,9 +4808,7 @@ region_model::scan_for_null_terminator_1 (const region *reg,
          if (out_sval)
            {
              byte_range bytes_to_write (dst_byte_offset, fragment_bytes_read);
-             const binding_key *key
-               = store_mgr->get_concrete_binding (bytes_to_write);
-             result.put (key, sval);
+             result.insert (bytes_to_write, sval);
            }
 
          src_byte_offset += fragment_bytes_read;
@@ -4821,7 +4818,7 @@ region_model::scan_for_null_terminator_1 (const region *reg,
            {
              if (out_sval)
                *out_sval = m_mgr->get_or_create_compound_svalue (NULL_TREE,
-                                                                 result);
+                                                                 std::move (result));
              if (logger)
                logger->log ("got terminator");
              return m_mgr->get_or_create_int_cst (size_type_node,
@@ -7203,7 +7200,7 @@ private:
            = as_a <const compound_svalue *> (m_copied_sval);
          bit_size_t result = 0;
          /* Find keys for uninit svals.  */
-         for (auto iter : compound_sval->get_map ().get_concrete_bindings ())
+         for (auto iter : compound_sval->get_concrete_bindings ())
            {
              const svalue *sval = iter.second;
              if (const poisoned_svalue *psval
@@ -7252,7 +7249,7 @@ private:
       {
        /* Find keys for uninit svals.  */
        auto_vec<bit_range> uninit_bit_ranges;
-       for (auto iter : compound_sval->get_map ().get_concrete_bindings ())
+       for (auto iter : compound_sval->get_concrete_bindings ())
          {
            const svalue *sval = iter.second;
            if (const poisoned_svalue *psval
@@ -7462,7 +7459,7 @@ contains_uninit_p (const svalue *sval)
        for (auto iter = compound_sval->begin ();
             iter != compound_sval->end (); ++iter)
          {
-           const svalue *inner_sval = iter.get_svalue ();
+           const svalue *inner_sval = iter->second;
            if (const poisoned_svalue *psval
                = inner_sval->dyn_cast_poisoned_svalue ())
              if (psval->get_poison_kind () == poison_kind::uninit)
index 5631c4e87e084a1b49e4754e49428041f9cfa973..b03c79ffa72c1f497f90eeda53b5726419772483 100644 (file)
@@ -1713,15 +1713,15 @@ const svalue *
 decl_region::calc_svalue_for_constructor (tree ctor,
                                          region_model_manager *mgr) const
 {
-  /* Create a binding map, applying ctor to it, using this
+  /* Create a concrete_binding_map, applying ctor to it, using this
      decl_region as the base region when building child regions
      for offset calculations.  */
-  binding_map map (*mgr->get_store_manager ());
+  concrete_binding_map map;
   if (!map.apply_ctor_to_region (this, ctor, mgr))
     return mgr->get_or_create_unknown_svalue (get_type ());
 
   /* Return a compound svalue for the map we built.  */
-  return mgr->get_or_create_compound_svalue (get_type (), map);
+  return mgr->get_or_create_compound_svalue (get_type (), std::move (map));
 }
 
 /* Get an svalue for CTOR, a CONSTRUCTOR for this region's decl.  */
@@ -1778,7 +1778,7 @@ decl_region::get_svalue_for_initializer (region_model_manager *mgr) const
       binding_cluster c (*mgr->get_store_manager (), this);
       c.zero_fill_region (mgr->get_store_manager (), this);
       return mgr->get_or_create_compound_svalue (TREE_TYPE (m_decl),
-                                                c.get_map ());
+                                                c.get_map ().get_concrete_bindings ());
     }
 
   /* LTO can write out error_mark_node as the DECL_INITIAL for simple scalar
index 878536eb42b4df3bbb2ee01d052ad7d6b9a10f69..d198aec9d2b86e9e4ead896a8370b52ea6abff68 100644 (file)
@@ -618,6 +618,234 @@ simplify_for_binding (const svalue *sval)
   return sval;
 }
 
+/* class concrete_binding_map.  */
+
+/* Dump a representation of this concrete_binding_map to PP.
+   SIMPLE controls how values and regions are to be printed.
+   If MULTILINE, then split the dump over multiple lines and
+   use whitespace for readability, otherwise put all on one line.  */
+
+void
+concrete_binding_map::dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const
+{
+  bool first = true;
+  for (auto iter : *this)
+    {
+      const bit_range &bits = iter.first;
+      const svalue *value = iter.second;
+      if (multiline)
+       {
+         pp_string (pp, "    bits:   {");
+         bits.dump_to_pp (pp);
+         pp_string (pp, "}");
+         pp_newline (pp);
+         pp_string (pp, "    value: ");
+         if (tree t = value->get_type ())
+           dump_quoted_tree (pp, t);
+         pp_string (pp, " {");
+         value->dump_to_pp (pp, simple);
+         pp_string (pp, "}");
+         pp_newline (pp);
+       }
+      else
+       {
+         if (first)
+           first = false;
+         else
+           pp_string (pp, ", ");
+         pp_string (pp, "bits: {");
+         bits.dump_to_pp (pp);
+         pp_string (pp, "}, value: {");
+         value->dump_to_pp (pp, simple);
+         pp_string (pp, "}");
+       }
+    }
+}
+
+void
+concrete_binding_map::dump (bool simple) const
+{
+  tree_dump_pretty_printer pp (stderr);
+  dump_to_pp (&pp, simple, true);
+  pp_newline (&pp);
+}
+
+void
+concrete_binding_map::add_to_tree_widget (text_art::tree_widget &parent_widget,
+                                         const text_art::dump_widget_info &dwi) const
+{
+  for (auto iter : *this)
+    {
+      const bit_range &bits = iter.first;
+      const svalue *sval = iter.second;
+
+      pretty_printer the_pp;
+      pretty_printer * const pp = &the_pp;
+      pp_format_decoder (pp) = default_tree_printer;
+      pp_show_color (pp) = true;
+      const bool simple = true;
+
+      bits.dump_to_pp (pp);
+      pp_string (pp, ": ");
+      if (tree t = sval->get_type ())
+       dump_quoted_tree (pp, t);
+      pp_string (pp, " {");
+      sval->dump_to_pp (pp, simple);
+      pp_string (pp, "}");
+
+      parent_widget.add_child (text_art::tree_widget::make (dwi, pp));
+    }
+}
+
+void
+concrete_binding_map::validate () const
+{
+  for (auto iter = m_map.begin (); iter != m_map.end (); ++iter)
+    {
+      /* Ensure we don't nest compound svalues
+        within concrete_binding_map instances.  */
+      const svalue *sval = iter->second;
+      gcc_assert (sval->get_kind () != SK_COMPOUND);
+
+      /* Check for overlapping concrete bindings.  */
+      auto next (iter);
+      ++next;
+      if (next != m_map.end ())
+       {
+         /* Verify they are in order, and do not overlap.  */
+         const bit_range &iter_bits = iter->first;
+         const bit_range &next_bits = next->first;
+         gcc_assert (iter_bits.get_start_bit_offset ()
+                     < next_bits.get_start_bit_offset ());
+         gcc_assert (iter_bits.get_last_bit_offset ()
+                     < next_bits.get_start_bit_offset ());
+         gcc_assert (iter_bits.get_next_bit_offset ()
+                     <= next_bits.get_start_bit_offset ());
+       }
+    }
+}
+
+/* Comparator for imposing an order on concrete_binding_map instances.  */
+
+int
+concrete_binding_map::cmp (const concrete_binding_map &map1,
+                          const concrete_binding_map &map2)
+{
+  if (int size_cmp = map1.size () - map2.size ())
+    return size_cmp;
+
+  auto iter1 = map1.begin ();
+  auto iter2 = map2.begin ();
+  while (iter1 != map1.end ())
+    {
+      gcc_assert (iter2 != map2.end ());
+      if (int bit_cmp = bit_range::cmp (iter1->first, iter2->first))
+       return bit_cmp;
+      if (int sval_cmp = svalue::cmp_ptr (iter1->second, iter2->second))
+       return sval_cmp;
+      ++iter1;
+      ++iter2;
+    }
+  return 0;
+}
+
+/* Get the svalue bound precisely to BITS, if any, otherwise
+   return nullptr.  */
+
+const svalue *
+concrete_binding_map::get_any_exact_binding (const bit_range &bits) const
+{
+  auto iter = m_map.find (bits);
+  if (iter == m_map.end ())
+    return nullptr;
+  return iter->second;
+}
+
+/* Calculate what the complexity of a compound_svalue instance for this
+   map will be, based on the bound svalues.  */
+
+complexity
+concrete_binding_map::calc_complexity () const
+{
+  unsigned num_child_nodes = 0;
+  unsigned max_child_depth = 0;
+  for (auto iter : m_map)
+    {
+      const complexity &sval_c = iter.second->get_complexity ();
+      num_child_nodes += sval_c.m_num_nodes;
+      max_child_depth = MAX (max_child_depth, sval_c.m_max_depth);
+    }
+  return complexity (num_child_nodes + 1, max_child_depth + 1);
+}
+
+void
+concrete_binding_map::
+remove_overlapping_binding (store_manager *mgr,
+                           const bit_range &bits_to_drop,
+                           const bit_range &affected_bound_bits,
+                           const svalue &old_sval)
+{
+  gcc_assert (bits_to_drop.intersects_p (affected_bound_bits));
+
+  /* Remove existing binding.  */
+  erase (affected_bound_bits);
+
+  if (affected_bound_bits.get_start_bit_offset ()
+      < bits_to_drop.get_start_bit_offset ())
+    {
+      /* We have a truncated prefix.  */
+      bit_range prefix_bits (affected_bound_bits.get_start_bit_offset (),
+                            (bits_to_drop.get_start_bit_offset ()
+                             - affected_bound_bits.get_start_bit_offset ()));
+      bit_range rel_prefix (0, prefix_bits.m_size_in_bits);
+      const svalue *prefix_sval
+       = old_sval.extract_bit_range (NULL_TREE,
+                                     rel_prefix,
+                                     mgr->get_svalue_manager ());
+      insert (prefix_bits, prefix_sval);
+    }
+
+  if (affected_bound_bits.get_next_bit_offset ()
+      > bits_to_drop.get_next_bit_offset ())
+    {
+      /* We have a truncated suffix.  */
+      bit_range suffix_bits (bits_to_drop.get_next_bit_offset (),
+                            (affected_bound_bits.get_next_bit_offset ()
+                             - bits_to_drop.get_next_bit_offset ()));
+      bit_range rel_suffix (bits_to_drop.get_next_bit_offset ()
+                           - affected_bound_bits.get_start_bit_offset (),
+                           suffix_bits.m_size_in_bits);
+      const svalue *suffix_sval
+       = old_sval.extract_bit_range (NULL_TREE,
+                                     rel_suffix,
+                                     mgr->get_svalue_manager ());
+      insert (suffix_bits, suffix_sval);
+    }
+}
+
+void
+concrete_binding_map::
+remove_overlapping_bindings (store_manager *mgr,
+                            const bit_range &bits_to_drop)
+{
+  auto bindings = get_overlapping_bindings (bits_to_drop);
+  for (auto iter : bindings)
+    remove_overlapping_binding (mgr, bits_to_drop, iter.first, iter.second);
+}
+
+std::vector<std::pair<bit_range, const svalue &>>
+concrete_binding_map::get_overlapping_bindings (const bit_range &bits)
+{
+  std::vector<std::pair<bit_range, const svalue &>> result;
+  for (auto iter : m_map)
+    if (iter.first.intersects_p (bits))
+      {
+       gcc_assert (iter.second);
+       result.push_back ({iter.first, *iter.second});
+      }
+  return result;
+}
+
 /* class binding_map::const_iterator.  */
 
 bool
@@ -838,7 +1066,7 @@ binding_map::put (const binding_key *key, const svalue *sval)
       if (iter != m_concrete.end ())
        (*iter).second = sval;
       else
-       m_concrete.insert ({bits, sval});
+       m_concrete.insert (bits, sval);
     }
 }
 
@@ -974,24 +1202,7 @@ binding_map::validate () const
   /* We can't have both concrete and symbolic keys.  */
   gcc_assert (num_concrete == 0 || num_symbolic == 0);
 
-  /* Check for overlapping concrete bindings.  */
-  for (auto iter = m_concrete.begin (); iter != m_concrete.end (); ++iter)
-    {
-      auto next (iter);
-      ++next;
-      if (next != m_concrete.end ())
-       {
-         /* Verify they are in order, and do not overlap.  */
-         const bit_range &iter_bits = iter->first;
-         const bit_range &next_bits = next->first;
-         gcc_assert (iter_bits.get_start_bit_offset ()
-                     < next_bits.get_start_bit_offset ());
-         gcc_assert (iter_bits.get_last_bit_offset ()
-                     < next_bits.get_start_bit_offset ());
-         gcc_assert (iter_bits.get_next_bit_offset ()
-                     <= next_bits.get_start_bit_offset ());
-       }
-    }
+  m_concrete.validate ();
 }
 
 /* Return a new json::object of the form
@@ -1052,39 +1263,6 @@ binding_map::add_to_tree_widget (text_art::tree_widget &parent_widget,
     }
 }
 
-
-/* Comparator for imposing an order on binding_maps.  */
-
-int
-binding_map::cmp (const binding_map &map1, const binding_map &map2)
-{
-  if (int count_cmp = map1.elements () - map2.elements ())
-    return count_cmp;
-
-  auto_vec <const binding_key *> keys1 (map1.elements ());
-  for (auto iter : map1)
-    keys1.quick_push (iter.m_key);
-  keys1.qsort (binding_key::cmp_ptrs);
-
-  auto_vec <const binding_key *> keys2 (map2.elements ());
-  for (auto iter : map2)
-    keys2.quick_push (iter.m_key);
-  keys2.qsort (binding_key::cmp_ptrs);
-
-  for (size_t i = 0; i < keys1.length (); i++)
-    {
-      const binding_key *k1 = keys1[i];
-      const binding_key *k2 = keys2[i];
-      if (int key_cmp = binding_key::cmp (k1, k2))
-       return key_cmp;
-      gcc_assert (k1 == k2);
-      if (int sval_cmp = svalue::cmp_ptr (map1.get (k1), map2.get (k2)))
-       return sval_cmp;
-    }
-
-  return 0;
-}
-
 /* Get the child region of PARENT_REG based upon INDEX within a
    CONSTRUCTOR.   */
 
@@ -1157,8 +1335,8 @@ get_svalue_for_ctor_val (tree val, region_model_manager *mgr)
    to hitting a complexity limit).  */
 
 bool
-binding_map::apply_ctor_to_region (const region *parent_reg, tree ctor,
-                                  region_model_manager *mgr)
+concrete_binding_map::apply_ctor_to_region (const region *parent_reg, tree ctor,
+                                           region_model_manager *mgr)
 {
   gcc_assert (parent_reg);
   gcc_assert (TREE_CODE (ctor) == CONSTRUCTOR);
@@ -1218,10 +1396,10 @@ binding_map::apply_ctor_to_region (const region *parent_reg, tree ctor,
    to hitting a complexity limit).  */
 
 bool
-binding_map::apply_ctor_val_to_range (const region *parent_reg,
-                                     region_model_manager *mgr,
-                                     tree min_index, tree max_index,
-                                     tree val)
+concrete_binding_map::apply_ctor_val_to_range (const region *parent_reg,
+                                              region_model_manager *mgr,
+                                              tree min_index, tree max_index,
+                                              tree val)
 {
   gcc_assert (TREE_CODE (min_index) == INTEGER_CST);
   gcc_assert (TREE_CODE (max_index) == INTEGER_CST);
@@ -1245,10 +1423,6 @@ binding_map::apply_ctor_val_to_range (const region *parent_reg,
     = max_element_key->dyn_cast_concrete_binding ();
   bit_size_t range_size_in_bits
     = max_element_ckey->get_next_bit_offset () - start_bit_offset;
-  const concrete_binding *range_key
-    = smgr->get_concrete_binding (start_bit_offset, range_size_in_bits);
-  if (range_key->symbolic_p ())
-    return false;
 
   /* Get the value.  */
   if (TREE_CODE (val) == CONSTRUCTOR)
@@ -1256,7 +1430,8 @@ binding_map::apply_ctor_val_to_range (const region *parent_reg,
   const svalue *sval = get_svalue_for_ctor_val (val, mgr);
 
   /* Bind the value to the range.  */
-  put (range_key, sval);
+  const bit_range affected_bits (start_bit_offset, range_size_in_bits);
+  insert (affected_bits, sval);
   return true;
 }
 
@@ -1266,9 +1441,9 @@ binding_map::apply_ctor_val_to_range (const region *parent_reg,
    to hitting a complexity limit).  */
 
 bool
-binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,
-                                             region_model_manager *mgr,
-                                             tree index, tree val)
+concrete_binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,
+                                                      region_model_manager *mgr,
+                                                      tree index, tree val)
 {
   const region *child_reg
     = get_subregion_within_ctor_for_ctor_pair (parent_reg, index, val, mgr);
@@ -1309,7 +1484,8 @@ binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,
            (child_parent_offset, sval_bit_size);
        }
       gcc_assert (k->concrete_p ());
-      put (k, sval);
+      auto conc_key = as_a <const concrete_binding *> (k);
+      insert (conc_key->get_bit_range (), sval);
       return true;
     }
 }
@@ -1477,42 +1653,9 @@ binding_map::remove_overlapping_bindings (store_manager *mgr,
 
            const bit_range &drop_bits = drop_ckey->get_bit_range ();
            const bit_range &iter_bits = iter_ckey->get_bit_range ();
-
-           if (iter_bits.get_start_bit_offset ()
-                 < drop_bits.get_start_bit_offset ())
-             {
-               /* We have a truncated prefix.  */
-               bit_range prefix_bits (iter_bits.get_start_bit_offset (),
-                                      (drop_bits.get_start_bit_offset ()
-                                       - iter_bits.get_start_bit_offset ()));
-               const concrete_binding *prefix_key
-                 = mgr->get_concrete_binding (prefix_bits);
-               bit_range rel_prefix (0, prefix_bits.m_size_in_bits);
-               const svalue *prefix_sval
-                 = old_sval->extract_bit_range (NULL_TREE,
-                                                rel_prefix,
-                                                mgr->get_svalue_manager ());
-               put (prefix_key, prefix_sval);
-             }
-
-           if (iter_bits.get_next_bit_offset ()
-                 > drop_bits.get_next_bit_offset ())
-             {
-               /* We have a truncated suffix.  */
-               bit_range suffix_bits (drop_bits.get_next_bit_offset (),
-                                      (iter_bits.get_next_bit_offset ()
-                                       - drop_bits.get_next_bit_offset ()));
-               const concrete_binding *suffix_key
-                 = mgr->get_concrete_binding (suffix_bits);
-               bit_range rel_suffix (drop_bits.get_next_bit_offset ()
-                                       - iter_bits.get_start_bit_offset (),
-                                     suffix_bits.m_size_in_bits);
-               const svalue *suffix_sval
-                 = old_sval->extract_bit_range (NULL_TREE,
-                                                rel_suffix,
-                                                mgr->get_svalue_manager ());
-               put (suffix_key, suffix_sval);
-             }
+           gcc_assert (old_sval);
+           m_concrete.remove_overlapping_binding (mgr, drop_bits, iter_bits,
+                                                  *old_sval);
          }
     }
 }
@@ -1753,22 +1896,15 @@ binding_cluster::bind_compound_sval (store_manager *mgr,
 
   for (auto iter : *compound_sval)
     {
-      const binding_key *iter_key = iter.m_key;
-      const svalue *iter_sval = iter.m_sval;
-
-      if (const concrete_binding *concrete_key
-         = iter_key->dyn_cast_concrete_binding ())
-       {
-         bit_offset_t effective_start
-           = (concrete_key->get_start_bit_offset ()
-              + reg_offset.get_bit_offset ());
-         const concrete_binding *effective_concrete_key
-           = mgr->get_concrete_binding (effective_start,
-                                        concrete_key->get_size_in_bits ());
-         bind_key (effective_concrete_key, iter_sval);
-       }
-      else
-       gcc_unreachable ();
+      const bit_range &iter_bits = iter.first;
+      const svalue *iter_sval = iter.second;
+
+      bit_offset_t effective_start
+       = (iter_bits.get_start_bit_offset ()
+          + reg_offset.get_bit_offset ());
+      const bit_range affected_bits (effective_start,
+                                    iter_bits.m_size_in_bits);
+      bind_key (mgr->get_concrete_binding (affected_bits), iter_sval);
     }
 }
 
@@ -2060,8 +2196,8 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
      perhaps we should have a spatial-organized data structure for
      concrete keys, though.  */
 
-  binding_map result_map (*mgr);
-  binding_map default_map (*mgr);
+  concrete_binding_map result_map;
+  concrete_binding_map default_map;
 
   /* Set up default values in default_map.  */
   const svalue *default_sval;
@@ -2077,10 +2213,10 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
     = default_key->dyn_cast_concrete_binding ();
   if (!concrete_default_key)
     return nullptr;
-  const concrete_binding *default_key_relative_to_reg
-     = mgr->get_concrete_binding (0, concrete_default_key->get_size_in_bits ());
+  const bit_range default_key_relative_to_reg
+     (0, concrete_default_key->get_size_in_bits ());
 
-  default_map.put (default_key_relative_to_reg, default_sval);
+  default_map.insert (default_key_relative_to_reg, default_sval);
 
   for (auto iter : m_map)
     {
@@ -2111,19 +2247,12 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
          if (reg_range.contains_p (bound_range, &subrange))
            {
              /* We have a bound range fully within REG.
-                Add it to map, offsetting accordingly.  */
-
-             /* Get offset of KEY relative to REG, rather than to
-                the cluster.  */
-             const concrete_binding *offset_concrete_key
-               = mgr->get_concrete_binding (subrange);
-             result_map.put (offset_concrete_key, sval);
+                Add it to result_map, offsetting accordingly.  */
+             result_map.insert (subrange, sval);
 
              /* Clobber default_map, removing/trimming/spliting where
                 it overlaps with offset_concrete_key.  */
-             default_map.remove_overlapping_bindings (mgr,
-                                                      offset_concrete_key,
-                                                      nullptr, nullptr, false);
+             default_map.remove_overlapping_bindings (mgr, subrange);
            }
          else if (bound_range.contains_p (reg_range, &subrange))
            {
@@ -2148,16 +2277,11 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
                                           bound_subrange,
                                           mgr->get_svalue_manager ());
 
-             /* Get key for overlap, relative to the REG.  */
-             const concrete_binding *overlap_concrete_key
-               = mgr->get_concrete_binding (reg_subrange);
-             result_map.put (overlap_concrete_key, overlap_sval);
+             result_map.insert (reg_subrange, overlap_sval);
 
              /* Clobber default_map, removing/trimming/spliting where
                 it overlaps with overlap_concrete_key.  */
-             default_map.remove_overlapping_bindings (mgr,
-                                                      overlap_concrete_key,
-                                                      nullptr, nullptr, false);
+             default_map.remove_overlapping_bindings (mgr, reg_subrange);
            }
        }
       else
@@ -2165,18 +2289,19 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
        return nullptr;
     }
 
-  if (result_map.elements () == 0)
+  if (result_map.size () == 0)
     return nullptr;
 
   /* Merge any bindings from default_map into result_map.  */
   for (auto iter : default_map)
     {
-      const binding_key *key = iter.m_key;
-      const svalue *sval = iter.m_sval;
-      result_map.put (key, sval);
+      const bit_range &key = iter.first;
+      const svalue *sval = iter.second;
+      result_map.insert (key, sval);
     }
 
-  return sval_mgr->get_or_create_compound_svalue (reg->get_type (), result_map);
+  return sval_mgr->get_or_create_compound_svalue (reg->get_type (),
+                                                 std::move (result_map));
 }
 
 /* Remove, truncate, and/or split any bindings within this map that
@@ -3845,7 +3970,7 @@ store::replay_call_summary_cluster (call_summary_replay &r,
        if (!summary_sval)
          summary_sval = reg_mgr->get_or_create_compound_svalue
            (summary_base_reg->get_type (),
-            summary_cluster->get_map ());
+            summary_cluster->get_map ().get_concrete_bindings ());
        const svalue *caller_sval
          = r.convert_svalue_from_summary (summary_sval);
        if (!caller_sval)
index e562e5479ed03a00141fdfe19d3883c3674123c4..021a438222fd18b0861d4b44e3a30be3e1b1de02 100644 (file)
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_ANALYZER_STORE_H
 
 #include "text-art/tree-widget.h"
+#include "analyzer/complexity.h"
 
 /* Implementation of the region-based ternary model described in:
      "A Memory Model for Static Analysis of C Programs"
@@ -513,11 +514,115 @@ template <> struct default_hash_traits<ana::symbolic_binding>
 
 namespace ana {
 
-/* A mapping from binding_keys to svalues, for use by binding_cluster
-   and compound_svalue.
-   We store a map from concrete keys to svalues, which is ordered by
-   the start offset.
-   We also store a vector of (symbolic key, svalue) pairs, but for now
+/* A mapping from concrete bit_ranges to svalues, for use by
+   binding_cluster and compound_svalue.
+   The keys are ordered by the start offset, and must not overlap
+   The bound svalues may not be compound_svalues, so that we don't
+   nest these (for canonicalization).  */
+
+class concrete_binding_map
+{
+public:
+  using map_t = std::map<bit_range, const svalue *>;
+  using const_iterator = map_t::const_iterator;
+  using iterator = map_t::iterator;
+
+  void clear () { m_map.clear (); }
+  bool empty_p () const { return m_map.empty (); }
+
+  bool
+  operator== (const concrete_binding_map &other) const
+  {
+    return m_map == other.m_map;
+  }
+  bool
+  operator!= (const concrete_binding_map &other) const
+  {
+    return m_map != other.m_map;
+  }
+
+  const_iterator begin () const { return m_map.begin (); }
+  const_iterator end () const { return m_map.end (); }
+  iterator begin () { return m_map.begin (); }
+  iterator end () { return m_map.end (); }
+
+  size_t size () const { return m_map.size (); }
+
+  void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
+  void dump (bool simple) const;
+
+  void add_to_tree_widget (text_art::tree_widget &parent_widget,
+                          const text_art::dump_widget_info &dwi) const;
+
+  void validate () const;
+
+  static int
+  cmp (const concrete_binding_map &map1,
+       const concrete_binding_map &map2);
+
+  void
+  insert (const bit_range &bits, const svalue *sval)
+  {
+    m_map.insert ({bits, sval});
+  }
+
+  void
+  insert (const byte_range &bytes, const svalue *sval)
+  {
+    m_map.insert ({bytes.as_bit_range (), sval});
+  }
+
+  void
+  erase (const bit_range &bits)
+  {
+    m_map.erase (bits);
+  }
+
+  const svalue *
+  get_any_exact_binding (const bit_range &bits) const;
+
+  const_iterator
+  find (const bit_range &bits) const
+  {
+    return m_map.find (bits);
+  }
+  iterator
+  find (const bit_range &bits)
+  {
+    return m_map.find (bits);
+  }
+
+  complexity calc_complexity () const;
+
+  bool apply_ctor_to_region (const region *parent_reg, tree ctor,
+                            region_model_manager *mgr);
+
+  void remove_overlapping_binding (store_manager *mgr,
+                                  const bit_range &bits_to_drop,
+                                  const bit_range &affected_bound_bits,
+                                  const svalue &old_sval);
+
+  void remove_overlapping_bindings (store_manager *mgr,
+                                   const bit_range &bits);
+
+private:
+  std::vector<std::pair<bit_range, const svalue &>>
+  get_overlapping_bindings (const bit_range &bits);
+
+  bool apply_ctor_val_to_range (const region *parent_reg,
+                               region_model_manager *mgr,
+                               tree min_index, tree max_index,
+                               tree val);
+  bool apply_ctor_pair_to_child_region (const region *parent_reg,
+                                       region_model_manager *mgr,
+                                       tree index, tree val);
+
+  map_t m_map;
+};
+
+/* A mapping from binding_keys to svalues, for use by binding_cluster.
+   We store bindings at concrete bit ranges via a concrete_binding_map,
+   along with a vector of (symbolic key, svalue) pairs, but for now
    this has maximum length of 1.  */
 
 class binding_map
@@ -534,7 +639,7 @@ public:
     const region *m_region;
     const svalue *m_sval;
   };
-  using concrete_bindings_t = std::map<bit_range, const svalue *>;
+  using concrete_bindings_t = concrete_binding_map;
   using symbolic_bindings_t = std::vector<symbolic_binding>;
 
   struct binding_pair
@@ -632,7 +737,7 @@ public:
 
   bool empty_p () const
   {
-    return m_concrete.empty () && m_symbolic.empty ();
+    return m_concrete.empty_p () && m_symbolic.empty ();
   }
 
   const_iterator_t begin () const;
@@ -651,11 +756,6 @@ public:
   void add_to_tree_widget (text_art::tree_widget &parent_widget,
                           const text_art::dump_widget_info &dwi) const;
 
-  bool apply_ctor_to_region (const region *parent_reg, tree ctor,
-                            region_model_manager *mgr);
-
-  static int cmp (const binding_map &map1, const binding_map &map2);
-
   void remove_overlapping_bindings (store_manager *mgr,
                                    const binding_key *drop_key,
                                    uncertainty_t *uncertainty,
@@ -671,13 +771,6 @@ public:
 private:
   void get_overlapping_bindings (const binding_key *key,
                                 auto_vec<const binding_key *> *out);
-  bool apply_ctor_val_to_range (const region *parent_reg,
-                               region_model_manager *mgr,
-                               tree min_index, tree max_index,
-                               tree val);
-  bool apply_ctor_pair_to_child_region (const region *parent_reg,
-                                       region_model_manager *mgr,
-                                       tree index, tree val);
 
   store_manager &m_store_mgr;
   concrete_bindings_t m_concrete;
index 74c2c0dbd4a37fc46f5267e7eaf04cfceb558ac2..52e853fdc8a9a2c15df950da6b372e993bd83076 100644 (file)
@@ -678,8 +678,9 @@ svalue::cmp_ptr (const svalue *sval1, const svalue *sval2)
       {
        const compound_svalue *compound_sval1 = (const compound_svalue *)sval1;
        const compound_svalue *compound_sval2 = (const compound_svalue *)sval2;
-       return binding_map::cmp (compound_sval1->get_map (),
-                                compound_sval2->get_map ());
+       return concrete_binding_map::cmp
+         (compound_sval1->get_concrete_bindings (),
+          compound_sval2->get_concrete_bindings ());
       }
       break;
     case SK_CONJURED:
@@ -2349,19 +2350,29 @@ unmergeable_svalue::implicitly_live_p (const svalue_set *live_svalues,
 
 compound_svalue::compound_svalue (symbol::id_t id,
                                  tree type,
-                                 const binding_map &map)
-: svalue (calc_complexity (map), id, type), m_map (map)
+                                 concrete_binding_map &&map)
+: svalue (map.calc_complexity (), id, type), m_map (std::move (map))
 {
 #if CHECKING_P
   for (auto iter : *this)
     {
-      /* All keys within the underlying binding_map are required to be concrete,
-        not symbolic.  */
-      const binding_key *key = iter.m_key;
-      gcc_assert (key->concrete_p ());
+      /* We don't nest compound svalues.  */
+      const svalue *sval = iter.second;
+      gcc_assert (sval->get_kind () != SK_COMPOUND);
+    }
+#endif
+}
 
+compound_svalue::compound_svalue (symbol::id_t id,
+                                 tree type,
+                                 const concrete_binding_map &map)
+: svalue (map.calc_complexity (), id, type), m_map (map)
+{
+#if CHECKING_P
+  for (auto iter : *this)
+    {
       /* We don't nest compound svalues.  */
-      const svalue *sval = iter.m_sval;
+      const svalue *sval = iter.second;
       gcc_assert (sval->get_kind () != SK_COMPOUND);
     }
 #endif
@@ -2424,30 +2435,10 @@ void
 compound_svalue::accept (visitor *v) const
 {
   for (auto iter : m_map)
-    {
-      //iter.first.accept (v);
-      iter.m_sval->accept (v);
-    }
+    iter.second->accept (v);
   v->visit_compound_svalue (this);
 }
 
-/* Calculate what the complexity of a compound_svalue instance for MAP
-   will be, based on the svalues bound within MAP.  */
-
-complexity
-compound_svalue::calc_complexity (const binding_map &map)
-{
-  unsigned num_child_nodes = 0;
-  unsigned max_child_depth = 0;
-  for (auto iter : map)
-    {
-      const complexity &sval_c = iter.m_sval->get_complexity ();
-      num_child_nodes += sval_c.m_num_nodes;
-      max_child_depth = MAX (max_child_depth, sval_c.m_max_depth);
-    }
-  return complexity (num_child_nodes + 1, max_child_depth + 1);
-}
-
 /* Implementation of svalue::maybe_fold_bits_within vfunc
    for compound_svalue.  */
 
@@ -2456,65 +2447,56 @@ compound_svalue::maybe_fold_bits_within (tree type,
                                         const bit_range &bits,
                                         region_model_manager *mgr) const
 {
-  binding_map result_map (*mgr->get_store_manager ());
+  concrete_binding_map result_map;
   for (auto iter : m_map)
     {
-      const binding_key *key = iter.m_key;
-      if (const concrete_binding *conc_key
-         = key->dyn_cast_concrete_binding ())
+      const bit_range &iter_bits = iter.first;
+
+      /* Ignore concrete bindings outside BITS.  */
+      if (!iter_bits.intersects_p (bits))
+       continue;
+
+      const svalue *sval = iter.second;
+      /* Get the position of iter_bits relative to BITS.  */
+      bit_range result_location (iter_bits.get_start_bit_offset ()
+                                - bits.get_start_bit_offset (),
+                                iter_bits.m_size_in_bits);
+      /* If iter_bits starts after BITS, trim off leading bits
+        from the svalue and adjust binding location.  */
+      if (result_location.m_start_bit_offset < 0)
        {
-         /* Ignore concrete bindings outside BITS.  */
-         if (!conc_key->get_bit_range ().intersects_p (bits))
-           continue;
-
-         const svalue *sval = iter.m_sval;
-         /* Get the position of conc_key relative to BITS.  */
-         bit_range result_location (conc_key->get_start_bit_offset ()
-                                    - bits.get_start_bit_offset (),
-                                    conc_key->get_size_in_bits ());
-         /* If conc_key starts after BITS, trim off leading bits
-            from the svalue and adjust binding location.  */
-         if (result_location.m_start_bit_offset < 0)
-           {
-             bit_size_t leading_bits_to_drop
-               = -result_location.m_start_bit_offset;
-             result_location = bit_range
-               (0, result_location.m_size_in_bits - leading_bits_to_drop);
-             bit_range bits_within_sval (leading_bits_to_drop,
-                                         result_location.m_size_in_bits);
-             /* Trim off leading bits from iter_sval.  */
-             sval = mgr->get_or_create_bits_within (NULL_TREE,
-                                                    bits_within_sval,
-                                                    sval);
-           }
-         /* If conc_key finishes after BITS, trim off trailing bits
-            from the svalue and adjust binding location.  */
-         if (conc_key->get_next_bit_offset ()
-             > bits.get_next_bit_offset ())
-           {
-             bit_size_t trailing_bits_to_drop
-               = (conc_key->get_next_bit_offset ()
-                  - bits.get_next_bit_offset ());
-             result_location = bit_range
-               (result_location.m_start_bit_offset,
-                result_location.m_size_in_bits - trailing_bits_to_drop);
-             bit_range bits_within_sval (0,
-                                         result_location.m_size_in_bits);
-             /* Trim off leading bits from iter_sval.  */
-             sval = mgr->get_or_create_bits_within (NULL_TREE,
-                                                    bits_within_sval,
-                                                    sval);
-           }
-         const concrete_binding *offset_conc_key
-           = mgr->get_store_manager ()->get_concrete_binding
-               (result_location);
-         result_map.put (offset_conc_key, sval);
+         bit_size_t leading_bits_to_drop
+           = -result_location.m_start_bit_offset;
+         result_location = bit_range
+           (0, result_location.m_size_in_bits - leading_bits_to_drop);
+         bit_range bits_within_sval (leading_bits_to_drop,
+                                     result_location.m_size_in_bits);
+         /* Trim off leading bits from iter_sval.  */
+         sval = mgr->get_or_create_bits_within (NULL_TREE,
+                                                bits_within_sval,
+                                                sval);
        }
-      else
-       /* If we have any symbolic keys we can't get it as bits.  */
-       return nullptr;
+      /* If iter_bits finishes after BITS, trim off trailing bits
+        from the svalue and adjust binding location.  */
+      if (iter_bits.get_next_bit_offset ()
+         > bits.get_next_bit_offset ())
+       {
+         bit_size_t trailing_bits_to_drop
+           = (iter_bits.get_next_bit_offset ()
+              - bits.get_next_bit_offset ());
+         result_location = bit_range
+           (result_location.m_start_bit_offset,
+            result_location.m_size_in_bits - trailing_bits_to_drop);
+         bit_range bits_within_sval (0,
+                                     result_location.m_size_in_bits);
+         /* Trim off leading bits from iter_sval.  */
+         sval = mgr->get_or_create_bits_within (NULL_TREE,
+                                                bits_within_sval,
+                                                sval);
+       }
+      result_map.insert (result_location, sval);
     }
-  return mgr->get_or_create_compound_svalue (type, result_map);
+  return mgr->get_or_create_compound_svalue (type, std::move (result_map));
 }
 
 /* class conjured_svalue : public svalue.  */
index 72b1542d730ed6e4dd18a0b994ad2640a5ae505b..a3fc41056c451806efeed3d91108b360c082b78b 100644 (file)
@@ -1402,15 +1402,13 @@ template <> struct default_hash_traits<widening_svalue::key_t>
 namespace ana {
 
 /* Concrete subclass of svalue representing a mapping of bit-ranges
-   to svalues, analogous to a cluster within the store.
+   to svalues, analogous to a cluster within the store, but without
+   symbolic keys.
 
    This is for use in places where we want to represent a store-like
    mapping, but are required to use an svalue, such as when handling
    compound assignments and compound return values.
 
-   All keys within the underlying binding_map are required to be concrete,
-   not symbolic.
-
    Instances of this class shouldn't be bound as-is into the store;
    instead they should be unpacked.  Similarly, they should not be
    nested.  */
@@ -1418,15 +1416,15 @@ namespace ana {
 class compound_svalue : public svalue
 {
 public:
-  typedef binding_map::const_iterator_t const_iterator_t;
-  typedef binding_map::iterator_t iterator_t;
+  typedef concrete_binding_map::const_iterator const_iterator_t;
+  typedef concrete_binding_map::iterator iterator_t;
 
   /* A support class for uniquifying instances of compound_svalue.
-     Note that to avoid copies, keys store pointers to binding_maps,
-     rather than the maps themselves.  */
+     Note that to avoid copies, keys store pointers to
+     concrete_binding_map, rather than the maps themselves.  */
   struct key_t
   {
-    key_t (tree type, const binding_map *map_ptr)
+    key_t (tree type, const concrete_binding_map *map_ptr)
     : m_type (type), m_map_ptr (map_ptr)
     {}
 
@@ -1450,10 +1448,11 @@ public:
     bool is_empty () const { return m_type == reinterpret_cast<tree> (2); }
 
     tree m_type;
-    const binding_map *m_map_ptr;
+    const concrete_binding_map *m_map_ptr;
   };
 
-  compound_svalue (symbol::id_t id, tree type, const binding_map &map);
+  compound_svalue (symbol::id_t id, tree type, concrete_binding_map &&map);
+  compound_svalue (symbol::id_t id, tree type, const concrete_binding_map &map);
 
   enum svalue_kind get_kind () const final override { return SK_COMPOUND; }
   const compound_svalue *dyn_cast_compound_svalue () const final override
@@ -1471,7 +1470,8 @@ public:
 
   void accept (visitor *v) const final override;
 
-  const binding_map &get_map () const { return m_map; }
+  const concrete_binding_map &
+  get_concrete_bindings () const { return m_map; }
 
   const_iterator_t begin () const { return m_map.begin (); }
   const_iterator_t end () const { return m_map.end (); }
@@ -1489,9 +1489,7 @@ public:
                          region_model_manager *mgr) const final override;
 
  private:
-  static complexity calc_complexity (const binding_map &map);
-
-  binding_map m_map;
+  concrete_binding_map m_map;
 };
 
 } // namespace ana