Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2229947/?format=api
{ "id": 2229947, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229947/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260428232805.1953949-1-dmalcolm@redhat.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/1.1/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null }, "msgid": "<20260428232805.1953949-1-dmalcolm@redhat.com>", "date": "2026-04-28T23:28:05", "name": "[pushed:,r17-182] analyzer: use concrete_binding_map for compound_svalue (PR analyzer/123145)", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "931482d1f46077c8224d30c2c17810bdcc0a8352", "submitter": { "id": 24465, "url": "http://patchwork.ozlabs.org/api/1.1/people/24465/?format=api", "name": "David Malcolm", "email": "dmalcolm@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260428232805.1953949-1-dmalcolm@redhat.com/mbox/", "series": [ { "id": 501956, "url": "http://patchwork.ozlabs.org/api/1.1/series/501956/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=501956", "date": "2026-04-28T23:28:05", "name": "[pushed:,r17-182] analyzer: use concrete_binding_map for compound_svalue (PR analyzer/123145)", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501956/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2229947/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2229947/checks/", "tags": {}, "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=PX00ErC0;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=PX00ErC0", "sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com", "sourceware.org; spf=pass smtp.mailfrom=redhat.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.129.124" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4xVb0Mppz1yHv\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 09:29:59 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 358824BBC0EA\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 23:29:57 +0000 (GMT)", "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id D9DB34BBC0E2\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:28:12 +0000 (GMT)", "from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-571-MW-D5uDSM8u83vgYvoCR2Q-1; Tue,\n 28 Apr 2026 19:28:09 -0400", "from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id F25A21956052\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:28:08 +0000 (UTC)", "from t14s.localdomain.com (unknown [10.22.65.168])\n by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 3467B195608E; Tue, 28 Apr 2026 23:28:07 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 358824BBC0EA", "OpenDKIM Filter v2.11.0 sourceware.org D9DB34BBC0E2" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org D9DB34BBC0E2", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org D9DB34BBC0E2", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777418893; cv=none;\n b=JvsiaeD/btzWA4QiVtCADXZZ0dao65miV5FHZXTwPBLb71KJW7XJiF3+rakSvI+brg3Je4U09gjzDiTxuPuQHPpm3E5wHS5V1ZP4xeBZ/656DLWt0hXVvZa3rlaz4QCov59/feWCAGedzy1Tzm216sDQr2h0eFqg+/TMuzzMg84=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777418893; c=relaxed/simple;\n bh=Ql3RT8Z2YQosyT35duhQ5nIG6tdYBnog34KQMDWAoes=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=k5X861s8rbh5BckaR6xRBKbOeGEpXP7JJ97Ng0jSJObDOyXCNa/fjpjBDc9B/GQ76MAM55U8g4fIwvreJcBFuA+z+vBtCLpC4hDhij/7dcunhKxdCf8ubRyG952QT4TZE1BXNZOkg/7VrvLrxBJG3uFevW/1n9u5tYem1jV4m3k=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1777418892;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=6kXxJOwbdYIckRiRrWuzLxrfiYtWv7plabCXuZcFyKQ=;\n b=PX00ErC0UBu+SmMadlyvciarWmGiRSVeAkMDzX5ZCGI2V7yBfWgYxO1kqXgntcDymQ8D5j\n p4GSVRv2Ifev74HaNAoO3/eGTMC5tYAbFVX2APttk8sSQsWX91gW6Su+imKXzy2PKuzhu7\n oaQ51VfCIvyOQbxkHPjBCCmngEsX5jM=", "X-MC-Unique": "MW-D5uDSM8u83vgYvoCR2Q-1", "X-Mimecast-MFC-AGG-ID": "MW-D5uDSM8u83vgYvoCR2Q_1777418889", "From": "David Malcolm <dmalcolm@redhat.com>", "To": "gcc-patches@gcc.gnu.org", "Cc": "David Malcolm <dmalcolm@redhat.com>", "Subject": "[pushed: r17-182] analyzer: use concrete_binding_map for\n compound_svalue (PR analyzer/123145)", "Date": "Tue, 28 Apr 2026 19:28:05 -0400", "Message-ID": "<20260428232805.1953949-1-dmalcolm@redhat.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.0 on 10.30.177.17", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "j_GueS2nv0CPzQJHcSEe95Fg-zj38c3Mz2UMhgQlXQM_1777418889", "X-Mimecast-Originator": "redhat.com", "Content-Transfer-Encoding": "8bit", "content-type": "text/plain; charset=\"US-ASCII\"; x-default=true", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "A compound_svalue can only have concrete bindings. Capture this in the\ntype system by splitting out the concrete parts of class binding_map\ninto a new class concrete_binding_map, and use the latter for\ncompound_svalue. This also allows some simplifications and\noptimizations, where we can use bit_range rather than binding keys.\n\nNo functional change intended.\n\nSuccessfully bootstrapped & regrtested on powerpc64le-unknown-linux-gnu\n(albeit without ada,cobol,d, and possibly missing some optional test dependencies)\nPushed to trunk as r17-182-g3a8301ae70cb7a.\n\ngcc/analyzer/ChangeLog:\n\tPR analyzer/123145\n\t* access-diagram.cc\n\t(compound_svalue_spatial_item::compound_svalue_spatial_item):\n\tUpdate for compound_svalue using concrete_binding_map rather than\n\tbinding_map.\n\t* bounds-checking.cc (strip_types): Likewise.\n\t* call-summary.cc\n\t(call_summary_replay::convert_svalue_from_summary_1): Update for\n\treimplementation of class binding_map.\n\t(call_summary_replay::convert_svalue_from_summary_1): Likewise.\n\t* infinite-recursion.cc (contains_unknown_p): Update for\n\tcompound_svalue using concrete_binding_map rather than\n\tbinding_map.\n\t* program-state.cc (sm_state_map::impl_set_state): Likewise.\n\t* region-model-manager.cc (maybe_undo_optimize_bit_field_compare):\n\tLikewise.\n\t(maybe_undo_optimize_bit_field_compare): Avoid building a\n\tconcrete_binding key by using get_any_exact_binding.\n\t(region_model_manager::get_or_create_compound_svalue): New\n\toverload, consuming a concrete_binding_map &&.\n\t* region-model-manager.h\n\t(region_model_manager::get_or_create_compound_svalue): New decl\n\tfor the above.\n\t* region-model-reachability.cc (reachable_regions::handle_sval):\n\tUpdate for compound_svalue using concrete_binding_map rather than\n\tbinding_map.\n\t(reachable_regions::handle_parm): Likewise.\n\t* region-model.cc (region_model::scan_for_null_terminator_1): Port\n\tfrom binding_map to concrete_binding_map.\n\t(exposure_through_uninit_copy::calc_num_uninit_bits): Update for\n\tcompound_svalue using concrete_binding_map rather than\n\tbinding_map.\n\t(contains_uninit_p): Likewise.\n\t* region.cc (decl_region::calc_svalue_for_constructor): Port from\n\tbinding_map to concrete_binding_map.\n\t(decl_region::get_svalue_for_initializer): Update call to\n\tget_or_create_compound_svalue.\n\t* store.cc (concrete_binding_map::dump_to_pp): New.\n\t(concrete_binding_map::dump): New.\n\t(concrete_binding_map::add_to_tree_widget): New.\n\t(concrete_binding_map::validate): New.\n\t(binding_map::cmp): Convert to...\n\t(concrete_binding_map::cmp): ...this.\n\t(concrete_binding_map::get_any_exact_binding): New.\n\t(concrete_binding_map::calc_complexity): New.\n\t(concrete_binding_map::remove_overlapping_binding): New.\n\t(concrete_binding_map::remove_overlapping_bindings): New.\n\t(concrete_binding_map::get_overlapping_bindings): New.\n\t(binding_map::put): Update for change to m_concrete.\n\t(binding_map::validate): Likewise.\n\t(binding_map::apply_ctor_to_region): Convert to...\n\t(concrete_binding_map::apply_ctor_to_region): ...this.\n\t(binding_map::apply_ctor_val_to_range): Convert to...\n\t(concrete_binding_map::apply_ctor_val_to_range): ...this.\n\t(binding_map::apply_ctor_pair_to_child_region): Convert to...\n\t(concrete_binding_map::apply_ctor_pair_to_child_region): ...this.\n\t(binding_map::remove_overlapping_bindings): Move part of\n\timplementation to\n\tconcrete_binding_map::remove_overlapping_binding.\n\t(binding_cluster::bind_compound_sval): Simplify using\n\tconcrete_binding_map.\n\t(binding_cluster::maybe_get_compound_binding): Likewise.\n\t(store::replay_call_summary_cluster): Update for change\n\tto compound_svalue.\n\t* store.h: Include \"analyzer/complexity.h\".\n\t(class concrete_binding_map): New, based on\n\tbinding_map::concrete_bindings_t.\n\t(binding_map::concrete_bindings_t): Use concrete_binding_map.\n\t(binding_map::empty_p): Update for above.\n\t(binding_map::apply_ctor_to_region): Drop decl.\n\t(binding_map::cmp): Likewise.\n\t(binding_map::apply_ctor_val_to_range): Likewise.\n\t(binding_map::apply_ctor_pair_to_child_region): Likewise.\n\t* svalue.cc (svalue::cmp_ptr): Update for change to\n\tcompound_svalue.\n\t(compound_svalue::compound_svalue): Port from binding_map to\n\tconcrete_binding_map.\n\t(compound_svalue::accept): Likewise.\n\t(compound_svalue::calc_complexity): Drop.\n\t(compound_svalue::maybe_fold_bits_within): Port from binding_map\n\tto concrete_binding_map.\n\t* svalue.h (class compound_svalue): Update leading comment. Port\n\tfrom binding_map to concrete_binding_map.\n\nSigned-off-by: David Malcolm <dmalcolm@redhat.com>\n---\n gcc/analyzer/access-diagram.cc | 23 +-\n gcc/analyzer/bounds-checking.cc | 13 +-\n gcc/analyzer/call-summary.cc | 42 +--\n gcc/analyzer/infinite-recursion.cc | 2 +-\n gcc/analyzer/program-state.cc | 2 +-\n gcc/analyzer/region-model-manager.cc | 33 +-\n gcc/analyzer/region-model-manager.h | 4 +-\n gcc/analyzer/region-model-reachability.cc | 4 +-\n gcc/analyzer/region-model.cc | 15 +-\n gcc/analyzer/region.cc | 8 +-\n gcc/analyzer/store.cc | 419 ++++++++++++++--------\n gcc/analyzer/store.h | 131 ++++++-\n gcc/analyzer/svalue.cc | 150 ++++----\n gcc/analyzer/svalue.h | 28 +-\n 14 files changed, 538 insertions(+), 336 deletions(-)", "diff": "diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc\nindex 9f412b5ec76..6a3ad635f0c 100644\n--- a/gcc/analyzer/access-diagram.cc\n+++ b/gcc/analyzer/access-diagram.cc\n@@ -1212,23 +1212,18 @@ public:\n : svalue_spatial_item (sval, bits, kind),\n m_compound_sval (sval)\n {\n- const binding_map &map = m_compound_sval.get_map ();\n+ const concrete_binding_map &map = m_compound_sval.get_concrete_bindings ();\n auto_vec <const binding_key *> binding_keys;\n for (auto iter : map)\n {\n-\tconst binding_key *key = iter.m_key;\n-\tconst svalue *bound_sval = iter.m_sval;\n-\tif (const concrete_binding *concrete_key\n-\t = key->dyn_cast_concrete_binding ())\n-\t {\n-\t access_range range (nullptr,\n-\t\t\t\tconcrete_key->get_bit_range ());\n-\t if (std::unique_ptr<spatial_item> child\n-\t\t = make_existing_svalue_spatial_item (bound_sval,\n-\t\t\t\t\t\t range,\n-\t\t\t\t\t\t theme))\n-\t m_children.push_back (std::move (child));\n-\t }\n+\tconst bit_range &key = iter.first;\n+\tconst svalue *bound_sval = iter.second;\n+\taccess_range range (nullptr, key);\n+\tif (std::unique_ptr<spatial_item> child\n+\t = make_existing_svalue_spatial_item (bound_sval,\n+\t\t\t\t\t\t range,\n+\t\t\t\t\t\t theme))\n+\t m_children.push_back (std::move (child));\n }\n }\n \ndiff --git a/gcc/analyzer/bounds-checking.cc b/gcc/analyzer/bounds-checking.cc\nindex 8d78581a3df..f9b5165a7cb 100644\n--- a/gcc/analyzer/bounds-checking.cc\n+++ b/gcc/analyzer/bounds-checking.cc\n@@ -1334,14 +1334,15 @@ strip_types (const svalue *sval,\n case SK_COMPOUND:\n {\n \tconst compound_svalue *compound_sval = (const compound_svalue *)sval;\n-\tbinding_map typeless_map (*mgr.get_store_manager ());\n-\tfor (auto iter : compound_sval->get_map ())\n+\tconcrete_binding_map typeless_map;\n+\tfor (auto iter : compound_sval->get_concrete_bindings ())\n \t {\n-\t const binding_key *key = iter.m_key;\n-\t const svalue *bound_sval = iter.m_sval;\n-\t typeless_map.put (key, strip_types (bound_sval, mgr));\n+\t const bit_range &bits = iter.first;\n+\t const svalue *bound_sval = iter.second;\n+\t typeless_map.insert (bits, strip_types (bound_sval, mgr));\n \t }\n-\treturn mgr.get_or_create_compound_svalue (NULL_TREE, typeless_map);\n+\treturn mgr.get_or_create_compound_svalue (NULL_TREE,\n+\t\t\t\t\t\t std::move (typeless_map));\n }\n case SK_CONJURED:\n return sval;\ndiff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc\nindex 7a3d4aac7c6..9220958afca 100644\n--- a/gcc/analyzer/call-summary.cc\n+++ b/gcc/analyzer/call-summary.cc\n@@ -421,19 +421,12 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)\n \tconst compound_svalue *compound_summary_sval\n \t = as_a <const compound_svalue *> (summary_sval);\n \tregion_model_manager *mgr = get_manager ();\n-\tstore_manager *store_mgr = mgr->get_store_manager ();\n-\tbinding_map caller_map (*store_mgr);\n-\tauto_vec <const binding_key *> summary_keys;\n-\tfor (auto kv : *compound_summary_sval)\n-\t summary_keys.safe_push (kv.m_key);\n-\tsummary_keys.qsort (binding_key::cmp_ptrs);\n-\tfor (auto key : summary_keys)\n+\tconcrete_binding_map caller_map;\n+\tfor (auto iter_summary : *compound_summary_sval)\n \t {\n-\t gcc_assert (key->concrete_p ());\n \t /* No remapping is needed for concrete binding keys. */\n-\n-\t const svalue *bound_summary_sval\n-\t = compound_summary_sval->get_map ().get (key);\n+\t const bit_range &summary_bits = iter_summary.first;\n+\t const svalue *bound_summary_sval = iter_summary.second;\n \t const svalue *caller_sval\n \t = convert_svalue_from_summary (bound_summary_sval);\n \t if (!caller_sval)\n@@ -442,31 +435,26 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)\n \t if (const compound_svalue *inner_compound_sval\n \t\t= caller_sval->dyn_cast_compound_svalue ())\n \t {\n-\t\tconst concrete_binding *outer_key\n-\t\t = as_a <const concrete_binding *> (key);\n+\t\tconst bit_range &outer_key = summary_bits;\n \t\tfor (auto inner_kv : *inner_compound_sval)\n \t\t {\n \t\t // These should already be mapped to the caller.\n-\t\t const binding_key *inner_key = inner_kv.m_key;\n-\t\t const svalue *inner_sval = inner_kv.m_sval;\n-\t\t gcc_assert (inner_key->concrete_p ());\n-\t\t const concrete_binding *concrete_key\n-\t\t = as_a <const concrete_binding *> (inner_key);\n+\t\t const bit_range &inner_key = inner_kv.first;\n+\t\t const svalue *inner_sval = inner_kv.second;\n \t\t bit_offset_t effective_start\n-\t\t = (concrete_key->get_start_bit_offset ()\n-\t\t\t + outer_key->get_start_bit_offset ());\n-\t\t const concrete_binding *effective_concrete_key\n-\t\t = store_mgr->get_concrete_binding\n-\t\t\t (effective_start,\n-\t\t\t concrete_key->get_size_in_bits ());\n-\t\t caller_map.put (effective_concrete_key, inner_sval);\n+\t\t = (inner_key.get_start_bit_offset ()\n+\t\t\t + outer_key.get_start_bit_offset ());\n+\t\t const bit_range effective_concrete_key\n+\t\t (effective_start,\n+\t\t summary_bits.m_size_in_bits);\n+\t\t caller_map.insert (effective_concrete_key, inner_sval);\n \t\t }\n \t }\n \t else\n-\t caller_map.put (key, caller_sval);\n+\t caller_map.insert (summary_bits, caller_sval);\n \t }\n \treturn mgr->get_or_create_compound_svalue (summary_sval->get_type (),\n-\t\t\t\t\t\t caller_map);\n+\t\t\t\t\t\t std::move (caller_map));\n }\n break;\n case SK_CONJURED:\ndiff --git a/gcc/analyzer/infinite-recursion.cc b/gcc/analyzer/infinite-recursion.cc\nindex 64eeb95de66..c1dc6e49b9b 100644\n--- a/gcc/analyzer/infinite-recursion.cc\n+++ b/gcc/analyzer/infinite-recursion.cc\n@@ -396,7 +396,7 @@ contains_unknown_p (const svalue *sval)\n if (const compound_svalue *compound_sval\n \t= sval->dyn_cast_compound_svalue ())\n for (auto iter : *compound_sval)\n- if (iter.m_sval->get_kind () == SK_UNKNOWN)\n+ if (iter.second->get_kind () == SK_UNKNOWN)\n \treturn true;\n return false;\n }\ndiff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc\nindex 08d6b559950..5ebaafb2661 100644\n--- a/gcc/analyzer/program-state.cc\n+++ b/gcc/analyzer/program-state.cc\n@@ -565,7 +565,7 @@ sm_state_map::impl_set_state (const svalue *sval,\n \tfor (auto iter = compound_sval->begin ();\n \t iter != compound_sval->end (); ++iter)\n \t {\n-\t const svalue *inner_sval = iter.get_svalue ();\n+\t const svalue *inner_sval = iter->second;\n \t if (inner_sval->can_have_associated_state_p ())\n \t impl_set_state (inner_sval, state, origin, ext_state);\n \t }\ndiff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc\nindex c4f91ecd688..ba7f9db507b 100644\n--- a/gcc/analyzer/region-model-manager.cc\n+++ b/gcc/analyzer/region-model-manager.cc\n@@ -639,7 +639,7 @@ maybe_undo_optimize_bit_field_compare (tree type,\n if (!INTEGRAL_TYPE_P (type))\n return nullptr;\n \n- const binding_map &map = compound_sval->get_map ();\n+ const concrete_binding_map &map = compound_sval->get_concrete_bindings ();\n unsigned HOST_WIDE_INT mask = TREE_INT_CST_LOW (cst);\n /* If \"mask\" is a contiguous range of set bits, see if the\n compound_sval has a value for those bits. */\n@@ -651,11 +651,13 @@ maybe_undo_optimize_bit_field_compare (tree type,\n if (BYTES_BIG_ENDIAN)\n bound_bits = bit_range (BITS_PER_UNIT - bits.get_next_bit_offset (),\n \t\t\t bits.m_size_in_bits);\n- const concrete_binding *conc\n- = get_store_manager ()->get_concrete_binding (bound_bits);\n- const svalue *sval = map.get (conc);\n+ const svalue *sval = map.get_any_exact_binding (bound_bits);\n if (!sval)\n- return nullptr;\n+ {\n+ /* In theory we could also look for bindings that straddle the\n+\t bit range. For simplicity, bail out on this case. */\n+ return nullptr;\n+ }\n \n /* We have a value;\n shift it by the correct number of bits. */\n@@ -1406,7 +1408,26 @@ get_or_create_widening_svalue (tree type,\n \n const svalue *\n region_model_manager::get_or_create_compound_svalue (tree type,\n-\t\t\t\t\t\t const binding_map &map)\n+\t\t\t\t\t\t concrete_binding_map &&map)\n+{\n+ compound_svalue::key_t tmp_key (type, &map);\n+ if (compound_svalue **slot = m_compound_values_map.get (tmp_key))\n+ return *slot;\n+ compound_svalue *compound_sval\n+ = new compound_svalue (alloc_symbol_id (), type, std::move (map));\n+ RETURN_UNKNOWN_IF_TOO_COMPLEX (compound_sval);\n+ /* Use make_key rather than reusing the key, so that we use a\n+ ptr to compound_sval's binding_map, rather than the MAP param. */\n+ m_compound_values_map.put (compound_sval->make_key (), compound_sval);\n+ return compound_sval;\n+}\n+\n+/* Return the svalue * of type TYPE for the compound values in MAP,\n+ creating it if necessary. */\n+\n+const svalue *\n+region_model_manager::get_or_create_compound_svalue (tree type,\n+\t\t\t\t\t\t const concrete_binding_map &map)\n {\n compound_svalue::key_t tmp_key (type, &map);\n if (compound_svalue **slot = m_compound_values_map.get (tmp_key))\ndiff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h\nindex 44122ec05f6..02b5125c435 100644\n--- a/gcc/analyzer/region-model-manager.h\n+++ b/gcc/analyzer/region-model-manager.h\n@@ -77,7 +77,9 @@ public:\n \t\t\t\t\t const svalue *base_svalue,\n \t\t\t\t\t const svalue *iter_svalue);\n const svalue *get_or_create_compound_svalue (tree type,\n-\t\t\t\t\t const binding_map &map);\n+\t\t\t\t\t concrete_binding_map &&map);\n+ const svalue *get_or_create_compound_svalue (tree type,\n+\t\t\t\t\t const concrete_binding_map &map);\n const svalue *get_or_create_conjured_svalue (tree type, const gimple *stmt,\n \t\t\t\t\t const region *id_reg,\n \t\t\t\t\t const conjured_purge &p,\ndiff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc\nindex 19b96b98280..e9e8edfcc1a 100644\n--- a/gcc/analyzer/region-model-reachability.cc\n+++ b/gcc/analyzer/region-model-reachability.cc\n@@ -172,7 +172,7 @@ reachable_regions::handle_sval (const svalue *sval)\n for (auto iter = compound_sval->begin ();\n \t iter != compound_sval->end (); ++iter)\n \t{\n-\t const svalue *iter_sval = iter.get_svalue ();\n+\t const svalue *iter_sval = iter->second;\n \t handle_sval (iter_sval);\n \t}\n }\n@@ -238,7 +238,7 @@ reachable_regions::handle_parm (const svalue *sval, tree param_type)\n for (auto iter = compound_sval->begin ();\n \t iter != compound_sval->end (); ++iter)\n \t{\n-\t const svalue *iter_sval = iter.get_svalue ();\n+\t const svalue *iter_sval = iter->second;\n \t handle_sval (iter_sval);\n \t}\n }\ndiff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc\nindex d46b130b00d..6e25029d9d2 100644\n--- a/gcc/analyzer/region-model.cc\n+++ b/gcc/analyzer/region-model.cc\n@@ -4701,7 +4701,6 @@ region_model::scan_for_null_terminator_1 (const region *reg,\n \t\t\t\t\t region_model_context *ctxt) const\n {\n logger *logger = ctxt ? ctxt->get_logger () : nullptr;\n- store_manager *store_mgr = m_mgr->get_store_manager ();\n \n region_offset offset = reg->get_offset (m_mgr);\n if (offset.symbolic_p ())\n@@ -4764,7 +4763,7 @@ region_model::scan_for_null_terminator_1 (const region *reg,\n logger->end_log_line ();\n }\n \n- binding_map result (*store_mgr);\n+ concrete_binding_map result;\n \n while (1)\n {\n@@ -4809,9 +4808,7 @@ region_model::scan_for_null_terminator_1 (const region *reg,\n \t if (out_sval)\n \t {\n \t byte_range bytes_to_write (dst_byte_offset, fragment_bytes_read);\n-\t const binding_key *key\n-\t\t= store_mgr->get_concrete_binding (bytes_to_write);\n-\t result.put (key, sval);\n+\t result.insert (bytes_to_write, sval);\n \t }\n \n \t src_byte_offset += fragment_bytes_read;\n@@ -4821,7 +4818,7 @@ region_model::scan_for_null_terminator_1 (const region *reg,\n \t {\n \t if (out_sval)\n \t\t*out_sval = m_mgr->get_or_create_compound_svalue (NULL_TREE,\n-\t\t\t\t\t\t\t\t result);\n+\t\t\t\t\t\t\t\t std::move (result));\n \t if (logger)\n \t\tlogger->log (\"got terminator\");\n \t return m_mgr->get_or_create_int_cst (size_type_node,\n@@ -7203,7 +7200,7 @@ private:\n \t = as_a <const compound_svalue *> (m_copied_sval);\n \t bit_size_t result = 0;\n \t /* Find keys for uninit svals. */\n-\t for (auto iter : compound_sval->get_map ().get_concrete_bindings ())\n+\t for (auto iter : compound_sval->get_concrete_bindings ())\n \t {\n \t const svalue *sval = iter.second;\n \t if (const poisoned_svalue *psval\n@@ -7252,7 +7249,7 @@ private:\n {\n \t/* Find keys for uninit svals. */\n \tauto_vec<bit_range> uninit_bit_ranges;\n-\tfor (auto iter : compound_sval->get_map ().get_concrete_bindings ())\n+\tfor (auto iter : compound_sval->get_concrete_bindings ())\n \t {\n \t const svalue *sval = iter.second;\n \t if (const poisoned_svalue *psval\n@@ -7462,7 +7459,7 @@ contains_uninit_p (const svalue *sval)\n \tfor (auto iter = compound_sval->begin ();\n \t iter != compound_sval->end (); ++iter)\n \t {\n-\t const svalue *inner_sval = iter.get_svalue ();\n+\t const svalue *inner_sval = iter->second;\n \t if (const poisoned_svalue *psval\n \t\t= inner_sval->dyn_cast_poisoned_svalue ())\n \t if (psval->get_poison_kind () == poison_kind::uninit)\ndiff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc\nindex 5631c4e87e0..b03c79ffa72 100644\n--- a/gcc/analyzer/region.cc\n+++ b/gcc/analyzer/region.cc\n@@ -1713,15 +1713,15 @@ const svalue *\n decl_region::calc_svalue_for_constructor (tree ctor,\n \t\t\t\t\t region_model_manager *mgr) const\n {\n- /* Create a binding map, applying ctor to it, using this\n+ /* Create a concrete_binding_map, applying ctor to it, using this\n decl_region as the base region when building child regions\n for offset calculations. */\n- binding_map map (*mgr->get_store_manager ());\n+ concrete_binding_map map;\n if (!map.apply_ctor_to_region (this, ctor, mgr))\n return mgr->get_or_create_unknown_svalue (get_type ());\n \n /* Return a compound svalue for the map we built. */\n- return mgr->get_or_create_compound_svalue (get_type (), map);\n+ return mgr->get_or_create_compound_svalue (get_type (), std::move (map));\n }\n \n /* Get an svalue for CTOR, a CONSTRUCTOR for this region's decl. */\n@@ -1778,7 +1778,7 @@ decl_region::get_svalue_for_initializer (region_model_manager *mgr) const\n binding_cluster c (*mgr->get_store_manager (), this);\n c.zero_fill_region (mgr->get_store_manager (), this);\n return mgr->get_or_create_compound_svalue (TREE_TYPE (m_decl),\n-\t\t\t\t\t\t c.get_map ());\n+\t\t\t\t\t\t c.get_map ().get_concrete_bindings ());\n }\n \n /* LTO can write out error_mark_node as the DECL_INITIAL for simple scalar\ndiff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc\nindex 878536eb42b..d198aec9d2b 100644\n--- a/gcc/analyzer/store.cc\n+++ b/gcc/analyzer/store.cc\n@@ -618,6 +618,234 @@ simplify_for_binding (const svalue *sval)\n return sval;\n }\n \n+/* class concrete_binding_map. */\n+\n+/* Dump a representation of this concrete_binding_map to PP.\n+ SIMPLE controls how values and regions are to be printed.\n+ If MULTILINE, then split the dump over multiple lines and\n+ use whitespace for readability, otherwise put all on one line. */\n+\n+void\n+concrete_binding_map::dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const\n+{\n+ bool first = true;\n+ for (auto iter : *this)\n+ {\n+ const bit_range &bits = iter.first;\n+ const svalue *value = iter.second;\n+ if (multiline)\n+\t{\n+\t pp_string (pp, \" bits: {\");\n+\t bits.dump_to_pp (pp);\n+\t pp_string (pp, \"}\");\n+\t pp_newline (pp);\n+\t pp_string (pp, \" value: \");\n+\t if (tree t = value->get_type ())\n+\t dump_quoted_tree (pp, t);\n+\t pp_string (pp, \" {\");\n+\t value->dump_to_pp (pp, simple);\n+\t pp_string (pp, \"}\");\n+\t pp_newline (pp);\n+\t}\n+ else\n+\t{\n+\t if (first)\n+\t first = false;\n+\t else\n+\t pp_string (pp, \", \");\n+\t pp_string (pp, \"bits: {\");\n+\t bits.dump_to_pp (pp);\n+\t pp_string (pp, \"}, value: {\");\n+\t value->dump_to_pp (pp, simple);\n+\t pp_string (pp, \"}\");\n+\t}\n+ }\n+}\n+\n+void\n+concrete_binding_map::dump (bool simple) const\n+{\n+ tree_dump_pretty_printer pp (stderr);\n+ dump_to_pp (&pp, simple, true);\n+ pp_newline (&pp);\n+}\n+\n+void\n+concrete_binding_map::add_to_tree_widget (text_art::tree_widget &parent_widget,\n+\t\t\t\t\t const text_art::dump_widget_info &dwi) const\n+{\n+ for (auto iter : *this)\n+ {\n+ const bit_range &bits = iter.first;\n+ const svalue *sval = iter.second;\n+\n+ pretty_printer the_pp;\n+ pretty_printer * const pp = &the_pp;\n+ pp_format_decoder (pp) = default_tree_printer;\n+ pp_show_color (pp) = true;\n+ const bool simple = true;\n+\n+ bits.dump_to_pp (pp);\n+ pp_string (pp, \": \");\n+ if (tree t = sval->get_type ())\n+\tdump_quoted_tree (pp, t);\n+ pp_string (pp, \" {\");\n+ sval->dump_to_pp (pp, simple);\n+ pp_string (pp, \"}\");\n+\n+ parent_widget.add_child (text_art::tree_widget::make (dwi, pp));\n+ }\n+}\n+\n+void\n+concrete_binding_map::validate () const\n+{\n+ for (auto iter = m_map.begin (); iter != m_map.end (); ++iter)\n+ {\n+ /* Ensure we don't nest compound svalues\n+\t within concrete_binding_map instances. */\n+ const svalue *sval = iter->second;\n+ gcc_assert (sval->get_kind () != SK_COMPOUND);\n+\n+ /* Check for overlapping concrete bindings. */\n+ auto next (iter);\n+ ++next;\n+ if (next != m_map.end ())\n+\t{\n+\t /* Verify they are in order, and do not overlap. */\n+\t const bit_range &iter_bits = iter->first;\n+\t const bit_range &next_bits = next->first;\n+\t gcc_assert (iter_bits.get_start_bit_offset ()\n+\t\t < next_bits.get_start_bit_offset ());\n+\t gcc_assert (iter_bits.get_last_bit_offset ()\n+\t\t < next_bits.get_start_bit_offset ());\n+\t gcc_assert (iter_bits.get_next_bit_offset ()\n+\t\t <= next_bits.get_start_bit_offset ());\n+\t}\n+ }\n+}\n+\n+/* Comparator for imposing an order on concrete_binding_map instances. */\n+\n+int\n+concrete_binding_map::cmp (const concrete_binding_map &map1,\n+\t\t\t const concrete_binding_map &map2)\n+{\n+ if (int size_cmp = map1.size () - map2.size ())\n+ return size_cmp;\n+\n+ auto iter1 = map1.begin ();\n+ auto iter2 = map2.begin ();\n+ while (iter1 != map1.end ())\n+ {\n+ gcc_assert (iter2 != map2.end ());\n+ if (int bit_cmp = bit_range::cmp (iter1->first, iter2->first))\n+\treturn bit_cmp;\n+ if (int sval_cmp = svalue::cmp_ptr (iter1->second, iter2->second))\n+\treturn sval_cmp;\n+ ++iter1;\n+ ++iter2;\n+ }\n+ return 0;\n+}\n+\n+/* Get the svalue bound precisely to BITS, if any, otherwise\n+ return nullptr. */\n+\n+const svalue *\n+concrete_binding_map::get_any_exact_binding (const bit_range &bits) const\n+{\n+ auto iter = m_map.find (bits);\n+ if (iter == m_map.end ())\n+ return nullptr;\n+ return iter->second;\n+}\n+\n+/* Calculate what the complexity of a compound_svalue instance for this\n+ map will be, based on the bound svalues. */\n+\n+complexity\n+concrete_binding_map::calc_complexity () const\n+{\n+ unsigned num_child_nodes = 0;\n+ unsigned max_child_depth = 0;\n+ for (auto iter : m_map)\n+ {\n+ const complexity &sval_c = iter.second->get_complexity ();\n+ num_child_nodes += sval_c.m_num_nodes;\n+ max_child_depth = MAX (max_child_depth, sval_c.m_max_depth);\n+ }\n+ return complexity (num_child_nodes + 1, max_child_depth + 1);\n+}\n+\n+void\n+concrete_binding_map::\n+remove_overlapping_binding (store_manager *mgr,\n+\t\t\t const bit_range &bits_to_drop,\n+\t\t\t const bit_range &affected_bound_bits,\n+\t\t\t const svalue &old_sval)\n+{\n+ gcc_assert (bits_to_drop.intersects_p (affected_bound_bits));\n+\n+ /* Remove existing binding. */\n+ erase (affected_bound_bits);\n+\n+ if (affected_bound_bits.get_start_bit_offset ()\n+ < bits_to_drop.get_start_bit_offset ())\n+ {\n+ /* We have a truncated prefix. */\n+ bit_range prefix_bits (affected_bound_bits.get_start_bit_offset (),\n+\t\t\t (bits_to_drop.get_start_bit_offset ()\n+\t\t\t - affected_bound_bits.get_start_bit_offset ()));\n+ bit_range rel_prefix (0, prefix_bits.m_size_in_bits);\n+ const svalue *prefix_sval\n+\t= old_sval.extract_bit_range (NULL_TREE,\n+\t\t\t\t rel_prefix,\n+\t\t\t\t mgr->get_svalue_manager ());\n+ insert (prefix_bits, prefix_sval);\n+ }\n+\n+ if (affected_bound_bits.get_next_bit_offset ()\n+ > bits_to_drop.get_next_bit_offset ())\n+ {\n+ /* We have a truncated suffix. */\n+ bit_range suffix_bits (bits_to_drop.get_next_bit_offset (),\n+\t\t\t (affected_bound_bits.get_next_bit_offset ()\n+\t\t\t - bits_to_drop.get_next_bit_offset ()));\n+ bit_range rel_suffix (bits_to_drop.get_next_bit_offset ()\n+\t\t\t - affected_bound_bits.get_start_bit_offset (),\n+\t\t\t suffix_bits.m_size_in_bits);\n+ const svalue *suffix_sval\n+\t= old_sval.extract_bit_range (NULL_TREE,\n+\t\t\t\t rel_suffix,\n+\t\t\t\t mgr->get_svalue_manager ());\n+ insert (suffix_bits, suffix_sval);\n+ }\n+}\n+\n+void\n+concrete_binding_map::\n+remove_overlapping_bindings (store_manager *mgr,\n+\t\t\t const bit_range &bits_to_drop)\n+{\n+ auto bindings = get_overlapping_bindings (bits_to_drop);\n+ for (auto iter : bindings)\n+ remove_overlapping_binding (mgr, bits_to_drop, iter.first, iter.second);\n+}\n+\n+std::vector<std::pair<bit_range, const svalue &>>\n+concrete_binding_map::get_overlapping_bindings (const bit_range &bits)\n+{\n+ std::vector<std::pair<bit_range, const svalue &>> result;\n+ for (auto iter : m_map)\n+ if (iter.first.intersects_p (bits))\n+ {\n+\tgcc_assert (iter.second);\n+\tresult.push_back ({iter.first, *iter.second});\n+ }\n+ return result;\n+}\n+\n /* class binding_map::const_iterator. */\n \n bool\n@@ -838,7 +1066,7 @@ binding_map::put (const binding_key *key, const svalue *sval)\n if (iter != m_concrete.end ())\n \t(*iter).second = sval;\n else\n-\tm_concrete.insert ({bits, sval});\n+\tm_concrete.insert (bits, sval);\n }\n }\n \n@@ -974,24 +1202,7 @@ binding_map::validate () const\n /* We can't have both concrete and symbolic keys. */\n gcc_assert (num_concrete == 0 || num_symbolic == 0);\n \n- /* Check for overlapping concrete bindings. */\n- for (auto iter = m_concrete.begin (); iter != m_concrete.end (); ++iter)\n- {\n- auto next (iter);\n- ++next;\n- if (next != m_concrete.end ())\n-\t{\n-\t /* Verify they are in order, and do not overlap. */\n-\t const bit_range &iter_bits = iter->first;\n-\t const bit_range &next_bits = next->first;\n-\t gcc_assert (iter_bits.get_start_bit_offset ()\n-\t\t < next_bits.get_start_bit_offset ());\n-\t gcc_assert (iter_bits.get_last_bit_offset ()\n-\t\t < next_bits.get_start_bit_offset ());\n-\t gcc_assert (iter_bits.get_next_bit_offset ()\n-\t\t <= next_bits.get_start_bit_offset ());\n-\t}\n- }\n+ m_concrete.validate ();\n }\n \n /* Return a new json::object of the form\n@@ -1052,39 +1263,6 @@ binding_map::add_to_tree_widget (text_art::tree_widget &parent_widget,\n }\n }\n \n-\n-/* Comparator for imposing an order on binding_maps. */\n-\n-int\n-binding_map::cmp (const binding_map &map1, const binding_map &map2)\n-{\n- if (int count_cmp = map1.elements () - map2.elements ())\n- return count_cmp;\n-\n- auto_vec <const binding_key *> keys1 (map1.elements ());\n- for (auto iter : map1)\n- keys1.quick_push (iter.m_key);\n- keys1.qsort (binding_key::cmp_ptrs);\n-\n- auto_vec <const binding_key *> keys2 (map2.elements ());\n- for (auto iter : map2)\n- keys2.quick_push (iter.m_key);\n- keys2.qsort (binding_key::cmp_ptrs);\n-\n- for (size_t i = 0; i < keys1.length (); i++)\n- {\n- const binding_key *k1 = keys1[i];\n- const binding_key *k2 = keys2[i];\n- if (int key_cmp = binding_key::cmp (k1, k2))\n-\treturn key_cmp;\n- gcc_assert (k1 == k2);\n- if (int sval_cmp = svalue::cmp_ptr (map1.get (k1), map2.get (k2)))\n-\treturn sval_cmp;\n- }\n-\n- return 0;\n-}\n-\n /* Get the child region of PARENT_REG based upon INDEX within a\n CONSTRUCTOR. */\n \n@@ -1157,8 +1335,8 @@ get_svalue_for_ctor_val (tree val, region_model_manager *mgr)\n to hitting a complexity limit). */\n \n bool\n-binding_map::apply_ctor_to_region (const region *parent_reg, tree ctor,\n-\t\t\t\t region_model_manager *mgr)\n+concrete_binding_map::apply_ctor_to_region (const region *parent_reg, tree ctor,\n+\t\t\t\t\t region_model_manager *mgr)\n {\n gcc_assert (parent_reg);\n gcc_assert (TREE_CODE (ctor) == CONSTRUCTOR);\n@@ -1218,10 +1396,10 @@ binding_map::apply_ctor_to_region (const region *parent_reg, tree ctor,\n to hitting a complexity limit). */\n \n bool\n-binding_map::apply_ctor_val_to_range (const region *parent_reg,\n-\t\t\t\t region_model_manager *mgr,\n-\t\t\t\t tree min_index, tree max_index,\n-\t\t\t\t tree val)\n+concrete_binding_map::apply_ctor_val_to_range (const region *parent_reg,\n+\t\t\t\t\t region_model_manager *mgr,\n+\t\t\t\t\t tree min_index, tree max_index,\n+\t\t\t\t\t tree val)\n {\n gcc_assert (TREE_CODE (min_index) == INTEGER_CST);\n gcc_assert (TREE_CODE (max_index) == INTEGER_CST);\n@@ -1245,10 +1423,6 @@ binding_map::apply_ctor_val_to_range (const region *parent_reg,\n = max_element_key->dyn_cast_concrete_binding ();\n bit_size_t range_size_in_bits\n = max_element_ckey->get_next_bit_offset () - start_bit_offset;\n- const concrete_binding *range_key\n- = smgr->get_concrete_binding (start_bit_offset, range_size_in_bits);\n- if (range_key->symbolic_p ())\n- return false;\n \n /* Get the value. */\n if (TREE_CODE (val) == CONSTRUCTOR)\n@@ -1256,7 +1430,8 @@ binding_map::apply_ctor_val_to_range (const region *parent_reg,\n const svalue *sval = get_svalue_for_ctor_val (val, mgr);\n \n /* Bind the value to the range. */\n- put (range_key, sval);\n+ const bit_range affected_bits (start_bit_offset, range_size_in_bits);\n+ insert (affected_bits, sval);\n return true;\n }\n \n@@ -1266,9 +1441,9 @@ binding_map::apply_ctor_val_to_range (const region *parent_reg,\n to hitting a complexity limit). */\n \n bool\n-binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,\n-\t\t\t\t\t region_model_manager *mgr,\n-\t\t\t\t\t tree index, tree val)\n+concrete_binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,\n+\t\t\t\t\t\t region_model_manager *mgr,\n+\t\t\t\t\t\t tree index, tree val)\n {\n const region *child_reg\n = get_subregion_within_ctor_for_ctor_pair (parent_reg, index, val, mgr);\n@@ -1309,7 +1484,8 @@ binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,\n \t (child_parent_offset, sval_bit_size);\n \t}\n gcc_assert (k->concrete_p ());\n- put (k, sval);\n+ auto conc_key = as_a <const concrete_binding *> (k);\n+ insert (conc_key->get_bit_range (), sval);\n return true;\n }\n }\n@@ -1477,42 +1653,9 @@ binding_map::remove_overlapping_bindings (store_manager *mgr,\n \n \t const bit_range &drop_bits = drop_ckey->get_bit_range ();\n \t const bit_range &iter_bits = iter_ckey->get_bit_range ();\n-\n-\t if (iter_bits.get_start_bit_offset ()\n-\t\t < drop_bits.get_start_bit_offset ())\n-\t {\n-\t\t/* We have a truncated prefix. */\n-\t\tbit_range prefix_bits (iter_bits.get_start_bit_offset (),\n-\t\t\t\t (drop_bits.get_start_bit_offset ()\n-\t\t\t\t\t- iter_bits.get_start_bit_offset ()));\n-\t\tconst concrete_binding *prefix_key\n-\t\t = mgr->get_concrete_binding (prefix_bits);\n-\t\tbit_range rel_prefix (0, prefix_bits.m_size_in_bits);\n-\t\tconst svalue *prefix_sval\n-\t\t = old_sval->extract_bit_range (NULL_TREE,\n-\t\t\t\t\t\t rel_prefix,\n-\t\t\t\t\t\t mgr->get_svalue_manager ());\n-\t\tput (prefix_key, prefix_sval);\n-\t }\n-\n-\t if (iter_bits.get_next_bit_offset ()\n-\t\t > drop_bits.get_next_bit_offset ())\n-\t {\n-\t\t/* We have a truncated suffix. */\n-\t\tbit_range suffix_bits (drop_bits.get_next_bit_offset (),\n-\t\t\t\t (iter_bits.get_next_bit_offset ()\n-\t\t\t\t\t- drop_bits.get_next_bit_offset ()));\n-\t\tconst concrete_binding *suffix_key\n-\t\t = mgr->get_concrete_binding (suffix_bits);\n-\t\tbit_range rel_suffix (drop_bits.get_next_bit_offset ()\n-\t\t\t\t\t- iter_bits.get_start_bit_offset (),\n-\t\t\t\t suffix_bits.m_size_in_bits);\n-\t\tconst svalue *suffix_sval\n-\t\t = old_sval->extract_bit_range (NULL_TREE,\n-\t\t\t\t\t\t rel_suffix,\n-\t\t\t\t\t\t mgr->get_svalue_manager ());\n-\t\tput (suffix_key, suffix_sval);\n-\t }\n+\t gcc_assert (old_sval);\n+\t m_concrete.remove_overlapping_binding (mgr, drop_bits, iter_bits,\n+\t\t\t\t\t\t *old_sval);\n \t }\n }\n }\n@@ -1753,22 +1896,15 @@ binding_cluster::bind_compound_sval (store_manager *mgr,\n \n for (auto iter : *compound_sval)\n {\n- const binding_key *iter_key = iter.m_key;\n- const svalue *iter_sval = iter.m_sval;\n-\n- if (const concrete_binding *concrete_key\n-\t = iter_key->dyn_cast_concrete_binding ())\n-\t{\n-\t bit_offset_t effective_start\n-\t = (concrete_key->get_start_bit_offset ()\n-\t + reg_offset.get_bit_offset ());\n-\t const concrete_binding *effective_concrete_key\n-\t = mgr->get_concrete_binding (effective_start,\n-\t\t\t\t\t concrete_key->get_size_in_bits ());\n-\t bind_key (effective_concrete_key, iter_sval);\n-\t}\n- else\n-\tgcc_unreachable ();\n+ const bit_range &iter_bits = iter.first;\n+ const svalue *iter_sval = iter.second;\n+\n+ bit_offset_t effective_start\n+\t= (iter_bits.get_start_bit_offset ()\n+\t + reg_offset.get_bit_offset ());\n+ const bit_range affected_bits (effective_start,\n+\t\t\t\t iter_bits.m_size_in_bits);\n+ bind_key (mgr->get_concrete_binding (affected_bits), iter_sval);\n }\n }\n \n@@ -2060,8 +2196,8 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,\n perhaps we should have a spatial-organized data structure for\n concrete keys, though. */\n \n- binding_map result_map (*mgr);\n- binding_map default_map (*mgr);\n+ concrete_binding_map result_map;\n+ concrete_binding_map default_map;\n \n /* Set up default values in default_map. */\n const svalue *default_sval;\n@@ -2077,10 +2213,10 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,\n = default_key->dyn_cast_concrete_binding ();\n if (!concrete_default_key)\n return nullptr;\n- const concrete_binding *default_key_relative_to_reg\n- = mgr->get_concrete_binding (0, concrete_default_key->get_size_in_bits ());\n+ const bit_range default_key_relative_to_reg\n+ (0, concrete_default_key->get_size_in_bits ());\n \n- default_map.put (default_key_relative_to_reg, default_sval);\n+ default_map.insert (default_key_relative_to_reg, default_sval);\n \n for (auto iter : m_map)\n {\n@@ -2111,19 +2247,12 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,\n \t if (reg_range.contains_p (bound_range, &subrange))\n \t {\n \t /* We have a bound range fully within REG.\n-\t\t Add it to map, offsetting accordingly. */\n-\n-\t /* Get offset of KEY relative to REG, rather than to\n-\t\t the cluster. */\n-\t const concrete_binding *offset_concrete_key\n-\t\t= mgr->get_concrete_binding (subrange);\n-\t result_map.put (offset_concrete_key, sval);\n+\t\t Add it to result_map, offsetting accordingly. */\n+\t result_map.insert (subrange, sval);\n \n \t /* Clobber default_map, removing/trimming/spliting where\n \t\t it overlaps with offset_concrete_key. */\n-\t default_map.remove_overlapping_bindings (mgr,\n-\t\t\t\t\t\t offset_concrete_key,\n-\t\t\t\t\t\t nullptr, nullptr, false);\n+\t default_map.remove_overlapping_bindings (mgr, subrange);\n \t }\n \t else if (bound_range.contains_p (reg_range, &subrange))\n \t {\n@@ -2148,16 +2277,11 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,\n \t\t\t\t\t bound_subrange,\n \t\t\t\t\t mgr->get_svalue_manager ());\n \n-\t /* Get key for overlap, relative to the REG. */\n-\t const concrete_binding *overlap_concrete_key\n-\t\t= mgr->get_concrete_binding (reg_subrange);\n-\t result_map.put (overlap_concrete_key, overlap_sval);\n+\t result_map.insert (reg_subrange, overlap_sval);\n \n \t /* Clobber default_map, removing/trimming/spliting where\n \t\t it overlaps with overlap_concrete_key. */\n-\t default_map.remove_overlapping_bindings (mgr,\n-\t\t\t\t\t\t overlap_concrete_key,\n-\t\t\t\t\t\t nullptr, nullptr, false);\n+\t default_map.remove_overlapping_bindings (mgr, reg_subrange);\n \t }\n \t}\n else\n@@ -2165,18 +2289,19 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,\n \treturn nullptr;\n }\n \n- if (result_map.elements () == 0)\n+ if (result_map.size () == 0)\n return nullptr;\n \n /* Merge any bindings from default_map into result_map. */\n for (auto iter : default_map)\n {\n- const binding_key *key = iter.m_key;\n- const svalue *sval = iter.m_sval;\n- result_map.put (key, sval);\n+ const bit_range &key = iter.first;\n+ const svalue *sval = iter.second;\n+ result_map.insert (key, sval);\n }\n \n- return sval_mgr->get_or_create_compound_svalue (reg->get_type (), result_map);\n+ return sval_mgr->get_or_create_compound_svalue (reg->get_type (),\n+\t\t\t\t\t\t std::move (result_map));\n }\n \n /* Remove, truncate, and/or split any bindings within this map that\n@@ -3845,7 +3970,7 @@ store::replay_call_summary_cluster (call_summary_replay &r,\n \tif (!summary_sval)\n \t summary_sval = reg_mgr->get_or_create_compound_svalue\n \t (summary_base_reg->get_type (),\n-\t summary_cluster->get_map ());\n+\t summary_cluster->get_map ().get_concrete_bindings ());\n \tconst svalue *caller_sval\n \t = r.convert_svalue_from_summary (summary_sval);\n \tif (!caller_sval)\ndiff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h\nindex e562e5479ed..021a438222f 100644\n--- a/gcc/analyzer/store.h\n+++ b/gcc/analyzer/store.h\n@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see\n #define GCC_ANALYZER_STORE_H\n \n #include \"text-art/tree-widget.h\"\n+#include \"analyzer/complexity.h\"\n \n /* Implementation of the region-based ternary model described in:\n \"A Memory Model for Static Analysis of C Programs\"\n@@ -513,11 +514,115 @@ template <> struct default_hash_traits<ana::symbolic_binding>\n \n namespace ana {\n \n-/* A mapping from binding_keys to svalues, for use by binding_cluster\n- and compound_svalue.\n- We store a map from concrete keys to svalues, which is ordered by\n- the start offset.\n- We also store a vector of (symbolic key, svalue) pairs, but for now\n+/* A mapping from concrete bit_ranges to svalues, for use by\n+ binding_cluster and compound_svalue.\n+ The keys are ordered by the start offset, and must not overlap\n+ The bound svalues may not be compound_svalues, so that we don't\n+ nest these (for canonicalization). */\n+\n+class concrete_binding_map\n+{\n+public:\n+ using map_t = std::map<bit_range, const svalue *>;\n+ using const_iterator = map_t::const_iterator;\n+ using iterator = map_t::iterator;\n+\n+ void clear () { m_map.clear (); }\n+ bool empty_p () const { return m_map.empty (); }\n+\n+ bool\n+ operator== (const concrete_binding_map &other) const\n+ {\n+ return m_map == other.m_map;\n+ }\n+ bool\n+ operator!= (const concrete_binding_map &other) const\n+ {\n+ return m_map != other.m_map;\n+ }\n+\n+ const_iterator begin () const { return m_map.begin (); }\n+ const_iterator end () const { return m_map.end (); }\n+ iterator begin () { return m_map.begin (); }\n+ iterator end () { return m_map.end (); }\n+\n+ size_t size () const { return m_map.size (); }\n+\n+ void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;\n+ void dump (bool simple) const;\n+\n+ void add_to_tree_widget (text_art::tree_widget &parent_widget,\n+\t\t\t const text_art::dump_widget_info &dwi) const;\n+\n+ void validate () const;\n+\n+ static int\n+ cmp (const concrete_binding_map &map1,\n+ const concrete_binding_map &map2);\n+\n+ void\n+ insert (const bit_range &bits, const svalue *sval)\n+ {\n+ m_map.insert ({bits, sval});\n+ }\n+\n+ void\n+ insert (const byte_range &bytes, const svalue *sval)\n+ {\n+ m_map.insert ({bytes.as_bit_range (), sval});\n+ }\n+\n+ void\n+ erase (const bit_range &bits)\n+ {\n+ m_map.erase (bits);\n+ }\n+\n+ const svalue *\n+ get_any_exact_binding (const bit_range &bits) const;\n+\n+ const_iterator\n+ find (const bit_range &bits) const\n+ {\n+ return m_map.find (bits);\n+ }\n+ iterator\n+ find (const bit_range &bits)\n+ {\n+ return m_map.find (bits);\n+ }\n+\n+ complexity calc_complexity () const;\n+\n+ bool apply_ctor_to_region (const region *parent_reg, tree ctor,\n+\t\t\t region_model_manager *mgr);\n+\n+ void remove_overlapping_binding (store_manager *mgr,\n+\t\t\t\t const bit_range &bits_to_drop,\n+\t\t\t\t const bit_range &affected_bound_bits,\n+\t\t\t\t const svalue &old_sval);\n+\n+ void remove_overlapping_bindings (store_manager *mgr,\n+\t\t\t\t const bit_range &bits);\n+\n+private:\n+ std::vector<std::pair<bit_range, const svalue &>>\n+ get_overlapping_bindings (const bit_range &bits);\n+\n+ bool apply_ctor_val_to_range (const region *parent_reg,\n+\t\t\t\tregion_model_manager *mgr,\n+\t\t\t\ttree min_index, tree max_index,\n+\t\t\t\ttree val);\n+ bool apply_ctor_pair_to_child_region (const region *parent_reg,\n+\t\t\t\t\tregion_model_manager *mgr,\n+\t\t\t\t\ttree index, tree val);\n+\n+ map_t m_map;\n+};\n+\n+/* A mapping from binding_keys to svalues, for use by binding_cluster.\n+ We store bindings at concrete bit ranges via a concrete_binding_map,\n+ along with a vector of (symbolic key, svalue) pairs, but for now\n this has maximum length of 1. */\n \n class binding_map\n@@ -534,7 +639,7 @@ public:\n const region *m_region;\n const svalue *m_sval;\n };\n- using concrete_bindings_t = std::map<bit_range, const svalue *>;\n+ using concrete_bindings_t = concrete_binding_map;\n using symbolic_bindings_t = std::vector<symbolic_binding>;\n \n struct binding_pair\n@@ -632,7 +737,7 @@ public:\n \n bool empty_p () const\n {\n- return m_concrete.empty () && m_symbolic.empty ();\n+ return m_concrete.empty_p () && m_symbolic.empty ();\n }\n \n const_iterator_t begin () const;\n@@ -651,11 +756,6 @@ public:\n void add_to_tree_widget (text_art::tree_widget &parent_widget,\n \t\t\t const text_art::dump_widget_info &dwi) const;\n \n- bool apply_ctor_to_region (const region *parent_reg, tree ctor,\n-\t\t\t region_model_manager *mgr);\n-\n- static int cmp (const binding_map &map1, const binding_map &map2);\n-\n void remove_overlapping_bindings (store_manager *mgr,\n \t\t\t\t const binding_key *drop_key,\n \t\t\t\t uncertainty_t *uncertainty,\n@@ -671,13 +771,6 @@ public:\n private:\n void get_overlapping_bindings (const binding_key *key,\n \t\t\t\t auto_vec<const binding_key *> *out);\n- bool apply_ctor_val_to_range (const region *parent_reg,\n-\t\t\t\tregion_model_manager *mgr,\n-\t\t\t\ttree min_index, tree max_index,\n-\t\t\t\ttree val);\n- bool apply_ctor_pair_to_child_region (const region *parent_reg,\n-\t\t\t\t\tregion_model_manager *mgr,\n-\t\t\t\t\ttree index, tree val);\n \n store_manager &m_store_mgr;\n concrete_bindings_t m_concrete;\ndiff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc\nindex 74c2c0dbd4a..52e853fdc8a 100644\n--- a/gcc/analyzer/svalue.cc\n+++ b/gcc/analyzer/svalue.cc\n@@ -678,8 +678,9 @@ svalue::cmp_ptr (const svalue *sval1, const svalue *sval2)\n {\n \tconst compound_svalue *compound_sval1 = (const compound_svalue *)sval1;\n \tconst compound_svalue *compound_sval2 = (const compound_svalue *)sval2;\n-\treturn binding_map::cmp (compound_sval1->get_map (),\n-\t\t\t\t compound_sval2->get_map ());\n+\treturn concrete_binding_map::cmp\n+\t (compound_sval1->get_concrete_bindings (),\n+\t compound_sval2->get_concrete_bindings ());\n }\n break;\n case SK_CONJURED:\n@@ -2349,19 +2350,29 @@ unmergeable_svalue::implicitly_live_p (const svalue_set *live_svalues,\n \n compound_svalue::compound_svalue (symbol::id_t id,\n \t\t\t\t tree type,\n-\t\t\t\t const binding_map &map)\n-: svalue (calc_complexity (map), id, type), m_map (map)\n+\t\t\t\t concrete_binding_map &&map)\n+: svalue (map.calc_complexity (), id, type), m_map (std::move (map))\n {\n #if CHECKING_P\n for (auto iter : *this)\n {\n- /* All keys within the underlying binding_map are required to be concrete,\n-\t not symbolic. */\n- const binding_key *key = iter.m_key;\n- gcc_assert (key->concrete_p ());\n+ /* We don't nest compound svalues. */\n+ const svalue *sval = iter.second;\n+ gcc_assert (sval->get_kind () != SK_COMPOUND);\n+ }\n+#endif\n+}\n \n+compound_svalue::compound_svalue (symbol::id_t id,\n+\t\t\t\t tree type,\n+\t\t\t\t const concrete_binding_map &map)\n+: svalue (map.calc_complexity (), id, type), m_map (map)\n+{\n+#if CHECKING_P\n+ for (auto iter : *this)\n+ {\n /* We don't nest compound svalues. */\n- const svalue *sval = iter.m_sval;\n+ const svalue *sval = iter.second;\n gcc_assert (sval->get_kind () != SK_COMPOUND);\n }\n #endif\n@@ -2424,30 +2435,10 @@ void\n compound_svalue::accept (visitor *v) const\n {\n for (auto iter : m_map)\n- {\n- //iter.first.accept (v);\n- iter.m_sval->accept (v);\n- }\n+ iter.second->accept (v);\n v->visit_compound_svalue (this);\n }\n \n-/* Calculate what the complexity of a compound_svalue instance for MAP\n- will be, based on the svalues bound within MAP. */\n-\n-complexity\n-compound_svalue::calc_complexity (const binding_map &map)\n-{\n- unsigned num_child_nodes = 0;\n- unsigned max_child_depth = 0;\n- for (auto iter : map)\n- {\n- const complexity &sval_c = iter.m_sval->get_complexity ();\n- num_child_nodes += sval_c.m_num_nodes;\n- max_child_depth = MAX (max_child_depth, sval_c.m_max_depth);\n- }\n- return complexity (num_child_nodes + 1, max_child_depth + 1);\n-}\n-\n /* Implementation of svalue::maybe_fold_bits_within vfunc\n for compound_svalue. */\n \n@@ -2456,65 +2447,56 @@ compound_svalue::maybe_fold_bits_within (tree type,\n \t\t\t\t\t const bit_range &bits,\n \t\t\t\t\t region_model_manager *mgr) const\n {\n- binding_map result_map (*mgr->get_store_manager ());\n+ concrete_binding_map result_map;\n for (auto iter : m_map)\n {\n- const binding_key *key = iter.m_key;\n- if (const concrete_binding *conc_key\n-\t = key->dyn_cast_concrete_binding ())\n+ const bit_range &iter_bits = iter.first;\n+\n+ /* Ignore concrete bindings outside BITS. */\n+ if (!iter_bits.intersects_p (bits))\n+\tcontinue;\n+\n+ const svalue *sval = iter.second;\n+ /* Get the position of iter_bits relative to BITS. */\n+ bit_range result_location (iter_bits.get_start_bit_offset ()\n+\t\t\t\t - bits.get_start_bit_offset (),\n+\t\t\t\t iter_bits.m_size_in_bits);\n+ /* If iter_bits starts after BITS, trim off leading bits\n+\t from the svalue and adjust binding location. */\n+ if (result_location.m_start_bit_offset < 0)\n \t{\n-\t /* Ignore concrete bindings outside BITS. */\n-\t if (!conc_key->get_bit_range ().intersects_p (bits))\n-\t continue;\n-\n-\t const svalue *sval = iter.m_sval;\n-\t /* Get the position of conc_key relative to BITS. */\n-\t bit_range result_location (conc_key->get_start_bit_offset ()\n-\t\t\t\t - bits.get_start_bit_offset (),\n-\t\t\t\t conc_key->get_size_in_bits ());\n-\t /* If conc_key starts after BITS, trim off leading bits\n-\t from the svalue and adjust binding location. */\n-\t if (result_location.m_start_bit_offset < 0)\n-\t {\n-\t bit_size_t leading_bits_to_drop\n-\t\t= -result_location.m_start_bit_offset;\n-\t result_location = bit_range\n-\t\t(0, result_location.m_size_in_bits - leading_bits_to_drop);\n-\t bit_range bits_within_sval (leading_bits_to_drop,\n-\t\t\t\t\t result_location.m_size_in_bits);\n-\t /* Trim off leading bits from iter_sval. */\n-\t sval = mgr->get_or_create_bits_within (NULL_TREE,\n-\t\t\t\t\t\t bits_within_sval,\n-\t\t\t\t\t\t sval);\n-\t }\n-\t /* If conc_key finishes after BITS, trim off trailing bits\n-\t from the svalue and adjust binding location. */\n-\t if (conc_key->get_next_bit_offset ()\n-\t > bits.get_next_bit_offset ())\n-\t {\n-\t bit_size_t trailing_bits_to_drop\n-\t\t= (conc_key->get_next_bit_offset ()\n-\t\t - bits.get_next_bit_offset ());\n-\t result_location = bit_range\n-\t\t(result_location.m_start_bit_offset,\n-\t\t result_location.m_size_in_bits - trailing_bits_to_drop);\n-\t bit_range bits_within_sval (0,\n-\t\t\t\t\t result_location.m_size_in_bits);\n-\t /* Trim off leading bits from iter_sval. */\n-\t sval = mgr->get_or_create_bits_within (NULL_TREE,\n-\t\t\t\t\t\t bits_within_sval,\n-\t\t\t\t\t\t sval);\n-\t }\n-\t const concrete_binding *offset_conc_key\n-\t = mgr->get_store_manager ()->get_concrete_binding\n-\t\t(result_location);\n-\t result_map.put (offset_conc_key, sval);\n+\t bit_size_t leading_bits_to_drop\n+\t = -result_location.m_start_bit_offset;\n+\t result_location = bit_range\n+\t (0, result_location.m_size_in_bits - leading_bits_to_drop);\n+\t bit_range bits_within_sval (leading_bits_to_drop,\n+\t\t\t\t result_location.m_size_in_bits);\n+\t /* Trim off leading bits from iter_sval. */\n+\t sval = mgr->get_or_create_bits_within (NULL_TREE,\n+\t\t\t\t\t\t bits_within_sval,\n+\t\t\t\t\t\t sval);\n \t}\n- else\n-\t/* If we have any symbolic keys we can't get it as bits. */\n-\treturn nullptr;\n+ /* If iter_bits finishes after BITS, trim off trailing bits\n+\t from the svalue and adjust binding location. */\n+ if (iter_bits.get_next_bit_offset ()\n+\t > bits.get_next_bit_offset ())\n+\t{\n+\t bit_size_t trailing_bits_to_drop\n+\t = (iter_bits.get_next_bit_offset ()\n+\t - bits.get_next_bit_offset ());\n+\t result_location = bit_range\n+\t (result_location.m_start_bit_offset,\n+\t result_location.m_size_in_bits - trailing_bits_to_drop);\n+\t bit_range bits_within_sval (0,\n+\t\t\t\t result_location.m_size_in_bits);\n+\t /* Trim off leading bits from iter_sval. */\n+\t sval = mgr->get_or_create_bits_within (NULL_TREE,\n+\t\t\t\t\t\t bits_within_sval,\n+\t\t\t\t\t\t sval);\n+\t}\n+ result_map.insert (result_location, sval);\n }\n- return mgr->get_or_create_compound_svalue (type, result_map);\n+ return mgr->get_or_create_compound_svalue (type, std::move (result_map));\n }\n \n /* class conjured_svalue : public svalue. */\ndiff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h\nindex 72b1542d730..a3fc41056c4 100644\n--- a/gcc/analyzer/svalue.h\n+++ b/gcc/analyzer/svalue.h\n@@ -1402,15 +1402,13 @@ template <> struct default_hash_traits<widening_svalue::key_t>\n namespace ana {\n \n /* Concrete subclass of svalue representing a mapping of bit-ranges\n- to svalues, analogous to a cluster within the store.\n+ to svalues, analogous to a cluster within the store, but without\n+ symbolic keys.\n \n This is for use in places where we want to represent a store-like\n mapping, but are required to use an svalue, such as when handling\n compound assignments and compound return values.\n \n- All keys within the underlying binding_map are required to be concrete,\n- not symbolic.\n-\n Instances of this class shouldn't be bound as-is into the store;\n instead they should be unpacked. Similarly, they should not be\n nested. */\n@@ -1418,15 +1416,15 @@ namespace ana {\n class compound_svalue : public svalue\n {\n public:\n- typedef binding_map::const_iterator_t const_iterator_t;\n- typedef binding_map::iterator_t iterator_t;\n+ typedef concrete_binding_map::const_iterator const_iterator_t;\n+ typedef concrete_binding_map::iterator iterator_t;\n \n /* A support class for uniquifying instances of compound_svalue.\n- Note that to avoid copies, keys store pointers to binding_maps,\n- rather than the maps themselves. */\n+ Note that to avoid copies, keys store pointers to\n+ concrete_binding_map, rather than the maps themselves. */\n struct key_t\n {\n- key_t (tree type, const binding_map *map_ptr)\n+ key_t (tree type, const concrete_binding_map *map_ptr)\n : m_type (type), m_map_ptr (map_ptr)\n {}\n \n@@ -1450,10 +1448,11 @@ public:\n bool is_empty () const { return m_type == reinterpret_cast<tree> (2); }\n \n tree m_type;\n- const binding_map *m_map_ptr;\n+ const concrete_binding_map *m_map_ptr;\n };\n \n- compound_svalue (symbol::id_t id, tree type, const binding_map &map);\n+ compound_svalue (symbol::id_t id, tree type, concrete_binding_map &&map);\n+ compound_svalue (symbol::id_t id, tree type, const concrete_binding_map &map);\n \n enum svalue_kind get_kind () const final override { return SK_COMPOUND; }\n const compound_svalue *dyn_cast_compound_svalue () const final override\n@@ -1471,7 +1470,8 @@ public:\n \n void accept (visitor *v) const final override;\n \n- const binding_map &get_map () const { return m_map; }\n+ const concrete_binding_map &\n+ get_concrete_bindings () const { return m_map; }\n \n const_iterator_t begin () const { return m_map.begin (); }\n const_iterator_t end () const { return m_map.end (); }\n@@ -1489,9 +1489,7 @@ public:\n \t\t\t region_model_manager *mgr) const final override;\n \n private:\n- static complexity calc_complexity (const binding_map &map);\n-\n- binding_map m_map;\n+ concrete_binding_map m_map;\n };\n \n } // namespace ana\n", "prefixes": [ "pushed:", "r17-182" ] }