: 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));
}
}
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;
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)
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:
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;
}
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);
}
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. */
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. */
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))
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,
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);
}
}
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);
}
}
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 ())
logger->end_log_line ();
}
- binding_map result (*store_mgr);
+ concrete_binding_map result;
while (1)
{
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;
{
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,
= 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
{
/* 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
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)
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. */
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
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
if (iter != m_concrete.end ())
(*iter).second = sval;
else
- m_concrete.insert ({bits, sval});
+ m_concrete.insert (bits, sval);
}
}
/* 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
}
}
-
-/* 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. */
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);
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);
= 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)
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;
}
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);
(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;
}
}
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);
}
}
}
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);
}
}
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;
= 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)
{
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))
{
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
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
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)
#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"
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
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
bool empty_p () const
{
- return m_concrete.empty () && m_symbolic.empty ();
+ return m_concrete.empty_p () && m_symbolic.empty ();
}
const_iterator_t begin () const;
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,
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;
{
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:
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
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. */
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. */
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. */
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)
{}
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
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 (); }
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