From c64117d0e0845e1abfa66d49a1189fa659288576 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Tue, 13 Jan 2026 17:44:38 -0500 Subject: [PATCH] Make IdTag typesafe (#6574) The IdTag knows the type of the Id its tagging and the type of the Id being used as the tag. This prevents mixing up tagged and untagged ids, and avoids having to work with untyped integers. Adds an Untagged marker struct that's used as the tag type in IdTag when no tag is desired. The complexity of ConstantIds and TypeIds became a bit visible: TypeIds are concrete ConstantIds. And ConstantIds have two different tagging schemes, one for concrete and one for symbolic ids. And ConstantIds are actually re-cast InstIds with the same index. The LoweredTypeStore needs to work with tagged TypeIds, but the tags actually come from an InstId store in ConstantValueStore. Now this is expressed in the type system by getting the tags for TypeIds from the ConstantValueStore. ValueStores without an TagId type parameter are now visibly untagged. IdTag is now only default constructible when it does not have a tag, which means ValueStore is only default constructible when the TagId is untagged. This forces tagged value stores to be constructed correctly with a tag at compile time, and untagged ones to be constructed without. FixedSizeValueStore has overloads for dealing with tagged and untagged Ids, since it can't default-construct ValueStore for tagged ids, and no longer requires passing in default-constructed tags when there is no tag in the ids. --- toolchain/base/BUILD | 2 + toolchain/base/block_value_store.h | 21 ++- toolchain/base/canonical_value_store.h | 33 ++-- toolchain/base/fixed_size_value_store.h | 71 ++++++-- toolchain/base/id_tag.h | 171 +++++++++++------- toolchain/base/relational_value_store.h | 9 +- toolchain/base/value_store.h | 42 +++-- toolchain/check/check_unit.cpp | 10 +- toolchain/check/check_unit.h | 12 +- toolchain/check/context.cpp | 5 +- toolchain/check/context.h | 9 +- .../basics/raw_sem_ir/one_file.carbon | 134 +++++++------- toolchain/driver/compile_subcommand.cpp | 8 +- toolchain/language_server/context.cpp | 2 +- toolchain/lower/file_context.cpp | 8 +- toolchain/lower/file_context.h | 24 ++- toolchain/lower/specific_coalescer.h | 15 +- toolchain/sem_ir/associated_constant.h | 2 +- toolchain/sem_ir/clang_decl.h | 2 +- toolchain/sem_ir/class.h | 2 +- toolchain/sem_ir/constant.h | 34 +++- toolchain/sem_ir/cpp_global_var.h | 4 +- toolchain/sem_ir/cpp_overload_set.h | 3 +- toolchain/sem_ir/entity_name.h | 3 +- toolchain/sem_ir/facet_type_info.h | 3 +- toolchain/sem_ir/file.cpp | 8 +- toolchain/sem_ir/file.h | 9 +- toolchain/sem_ir/formatter.cpp | 2 +- toolchain/sem_ir/formatter.h | 2 +- toolchain/sem_ir/function.h | 2 +- toolchain/sem_ir/generic.cpp | 5 +- toolchain/sem_ir/generic.h | 8 +- toolchain/sem_ir/ids.h | 5 + toolchain/sem_ir/impl.h | 4 +- toolchain/sem_ir/import_ir.h | 2 +- toolchain/sem_ir/inst.h | 14 +- toolchain/sem_ir/inst_fingerprinter.cpp | 7 +- toolchain/sem_ir/inst_fingerprinter.h | 6 +- toolchain/sem_ir/interface.h | 2 +- toolchain/sem_ir/name_scope.cpp | 2 +- toolchain/sem_ir/name_scope.h | 2 +- toolchain/sem_ir/named_constraint.h | 3 +- toolchain/sem_ir/require_impls.h | 5 +- toolchain/sem_ir/specific_interface.h | 2 +- toolchain/sem_ir/struct_type_field.h | 2 +- toolchain/sem_ir/vtable.h | 2 +- 46 files changed, 442 insertions(+), 281 deletions(-) diff --git a/toolchain/base/BUILD b/toolchain/base/BUILD index 61eb65e7afcb..5b0c0fb1fd21 100644 --- a/toolchain/base/BUILD +++ b/toolchain/base/BUILD @@ -12,6 +12,7 @@ cc_library( name = "block_value_store", hdrs = ["block_value_store.h"], deps = [ + ":id_tag", ":mem_usage", ":value_store", ":yaml", @@ -88,6 +89,7 @@ cc_library( hdrs = ["id_tag.h"], deps = [ "//common:check", + "//common:ostream", "@llvm-project//llvm:Support", ], ) diff --git a/toolchain/base/block_value_store.h b/toolchain/base/block_value_store.h index 27d7969d2119..7f8d6e96b75e 100644 --- a/toolchain/base/block_value_store.h +++ b/toolchain/base/block_value_store.h @@ -10,6 +10,7 @@ #include "common/check.h" #include "common/set.h" #include "llvm/Support/Allocator.h" +#include "toolchain/base/id_tag.h" #include "toolchain/base/mem_usage.h" #include "toolchain/base/value_store.h" #include "toolchain/base/yaml.h" @@ -22,17 +23,21 @@ namespace Carbon::SemIR { // // BlockValueStore is used as-is, but there are also children that expose the // protected members for type-specific functionality. -template -class BlockValueStore : public Yaml::Printable> { +template +class BlockValueStore + : public Yaml::Printable> { public: using IdType = IdT; + using IdTagType = IdTag; using ElementType = ElementT; using RefType = llvm::MutableArrayRef; using ConstRefType = llvm::ArrayRef; explicit BlockValueStore(llvm::BumpPtrAllocator& allocator, - IdTag tag = IdTag()) - : allocator_(&allocator), values_(tag) { + IdTagType::TagIdType tag_id, + int32_t initial_reserved_ids = 0) + requires(!IdTagIsUntagged) + : allocator_(&allocator), values_(tag_id, initial_reserved_ids) { auto empty = RefType(); auto empty_val = canonical_blocks_.Insert( empty, [&] { return values_.Add(empty); }, KeyContext(this)); @@ -129,18 +134,18 @@ class BlockValueStore : public Yaml::Printable> { } // Allow children to have more complex value handling. - auto values() -> ValueStore& { return values_; } + auto values() -> ValueStore& { return values_; } private: class KeyContext; llvm::BumpPtrAllocator* allocator_; - ValueStore values_; + ValueStore values_; Set canonical_blocks_; }; -template -class BlockValueStore::KeyContext +template +class BlockValueStore::KeyContext : public TranslatingKeyContext { public: explicit KeyContext(const BlockValueStore* store) : store_(store) {} diff --git a/toolchain/base/canonical_value_store.h b/toolchain/base/canonical_value_store.h index 61531002adec..fb5c3976657a 100644 --- a/toolchain/base/canonical_value_store.h +++ b/toolchain/base/canonical_value_store.h @@ -22,10 +22,12 @@ namespace Carbon { // `KeyT` can optionally be different from `ValueT`, and if so is used for the // argument to `Lookup`. In this case, `ValueT` must provide a `GetAsKey` member // function that returns the corresponding key. -template +template class CanonicalValueStore { public: using IdType = IdT; + using IdTagType = IdTag; using KeyType = std::remove_cvref_t; using ValueType = ValueStoreTypes::ValueType; using RefType = ValueStoreTypes::RefType; @@ -56,7 +58,7 @@ class CanonicalValueStore { } auto values() const [[clang::lifetimebound]] - -> ValueStore::Range { + -> ValueStore::Range { return values_.values(); } auto size() const -> size_t { return values_.size(); } @@ -71,7 +73,7 @@ class CanonicalValueStore { auto GetRawIndex(IdT id) const -> int32_t { return values_.GetRawIndex(id); } - auto GetIdTag() const -> IdTag { return values_.GetIdTag(); } + auto GetIdTag() const -> IdTagType { return values_.GetIdTag(); } private: class KeyContext; @@ -87,15 +89,15 @@ class CanonicalValueStore { return value.GetAsKey(); } - ValueStore values_; + ValueStore values_; Set set_; }; -template -class CanonicalValueStore::KeyContext +template +class CanonicalValueStore::KeyContext : public TranslatingKeyContext { public: - explicit KeyContext(const ValueStore* values) + explicit KeyContext(const ValueStore* values) : values_(values) {} // Note that it is safe to return a reference here as the underlying object's @@ -106,25 +108,28 @@ class CanonicalValueStore::KeyContext } private: - const ValueStore* values_; + const ValueStore* values_; }; -template -auto CanonicalValueStore::Add(ValueType value) -> IdT { +template +auto CanonicalValueStore::Add(ValueType value) + -> IdT { auto make_key = [&] { return IdT(values_.Add(std::move(value))); }; return set_.Insert(GetAsKey(value), make_key, KeyContext(&values_)).key(); } -template -auto CanonicalValueStore::Lookup(KeyType key) const -> IdT { +template +auto CanonicalValueStore::Lookup(KeyType key) const + -> IdT { if (auto result = set_.Lookup(key, KeyContext(&values_))) { return result.key(); } return IdT::None; } -template -auto CanonicalValueStore::Reserve(size_t size) -> void { +template +auto CanonicalValueStore::Reserve(size_t size) + -> void { // Compute the resulting new insert count using the size of values -- the // set doesn't have a fast to compute current size. if (size > values_.size()) { diff --git a/toolchain/base/fixed_size_value_store.h b/toolchain/base/fixed_size_value_store.h index 62a7c75268d4..bdf240050230 100644 --- a/toolchain/base/fixed_size_value_store.h +++ b/toolchain/base/fixed_size_value_store.h @@ -19,18 +19,32 @@ namespace Carbon { // A value store with a predetermined size. -template +template class FixedSizeValueStore { public: using IdType = IdT; + using IdTagType = IdTag; using ValueType = ValueStoreTypes::ValueType; using RefType = ValueStoreTypes::RefType; using ConstRefType = ValueStoreTypes::ConstRefType; // Makes a ValueStore of the specified size, but without initializing values. // Entries must be set before reading. + static auto MakeForOverwriteWithExplicitSize(size_t size, + IdTagType::TagIdType tag_id, + int32_t initial_reserved_ids = 0) + -> FixedSizeValueStore + requires(!IdTagIsUntagged) + { + FixedSizeValueStore store(IdTagType(tag_id, initial_reserved_ids)); + store.values_.resize_for_overwrite(size); + return store; + } + static auto MakeForOverwriteWithExplicitSize(size_t size) - -> FixedSizeValueStore { + -> FixedSizeValueStore + requires(IdTagIsUntagged) + { FixedSizeValueStore store; store.values_.resize_for_overwrite(size); return store; @@ -39,7 +53,8 @@ class FixedSizeValueStore { // Makes a ValueStore of the same size as a source `ValueStoreT`, but without // initializing values. Entries must be set before reading. template - requires std::same_as + requires(std::same_as && + !IdTagIsUntagged) static auto MakeForOverwrite(const ValueStoreT& size_source) -> FixedSizeValueStore { FixedSizeValueStore store(size_source.GetIdTag()); @@ -48,11 +63,21 @@ class FixedSizeValueStore { } // Makes a ValueStore of the specified size, initialized to a default. - static auto MakeWithExplicitSize(IdTag tag, size_t size, + static auto MakeWithExplicitSize(size_t size, IdTagType tag, ConstRefType default_value) - -> FixedSizeValueStore { + -> FixedSizeValueStore + requires(!IdTagIsUntagged) + { + FixedSizeValueStore store(tag); + store.values_.resize(size, default_value); + return store; + } + + static auto MakeWithExplicitSize(size_t size, ConstRefType default_value) + -> FixedSizeValueStore + requires(IdTagIsUntagged) + { FixedSizeValueStore store; - store.tag_ = tag; store.values_.resize(size, default_value); return store; } @@ -74,19 +99,29 @@ class FixedSizeValueStore { // the safest constructor to use, since it ensures everything's initialized to // a default, and verifies a matching `IdT` for the size. template - requires std::same_as + requires(std::same_as && + !IdTagIsUntagged && !IdTagIsUntagged) explicit FixedSizeValueStore(const ValueStoreT& size_source, ConstRefType default_value) : tag_(size_source.GetIdTag()) { values_.resize(size_source.size(), default_value); } - explicit FixedSizeValueStore(IdTag tag) : tag_(tag) {} + template + requires(std::same_as && + IdTagIsUntagged && IdTagIsUntagged) + explicit FixedSizeValueStore(const ValueStoreT& size_source, + ConstRefType default_value) { + values_.resize(size_source.size(), default_value); + } + + explicit FixedSizeValueStore(IdTagType tag) : tag_(tag) {} // Makes a ValueStore using a mapped range of `source`. The `factory_fn` // receives each enumerated entry for construction of `ValueType`. template - requires std::same_as + requires(std::same_as && + !IdTagIsUntagged && !IdTagIsUntagged) explicit FixedSizeValueStore( const ValueStoreT& source, llvm::function_ref< @@ -95,6 +130,16 @@ class FixedSizeValueStore { : values_(llvm::map_range(source.enumerate(), factory_fn)), tag_(GetIdTag(source)) {} + template + requires(std::same_as && + IdTagIsUntagged && IdTagIsUntagged) + explicit FixedSizeValueStore( + const ValueStoreT& source, + llvm::function_ref< + auto(IdT, typename ValueStoreT::ConstRefType)->ValueType> + factory_fn) + : values_(llvm::map_range(source.enumerate(), factory_fn)) {} + // Move-only. FixedSizeValueStore(FixedSizeValueStore&&) noexcept = default; auto operator=(FixedSizeValueStore&&) noexcept @@ -103,21 +148,21 @@ class FixedSizeValueStore { // Sets the value for an ID. auto Set(IdT id, ValueType value) -> void { CARBON_DCHECK(id.index >= 0, "{0}", id); - auto index = tag_.Remove(id.index); + auto index = tag_.Remove(id); values_[index] = value; } // Returns a mutable value for an ID. auto Get(IdT id) -> RefType { CARBON_DCHECK(id.index >= 0, "{0}", id); - auto index = tag_.Remove(id.index); + auto index = tag_.Remove(id); return values_[index]; } // Returns the value for an ID. auto Get(IdT id) const -> ConstRefType { CARBON_DCHECK(id.index >= 0, "{0}", id); - auto index = tag_.Remove(id.index); + auto index = tag_.Remove(id); return values_[index]; } @@ -146,7 +191,7 @@ class FixedSizeValueStore { // Storage for the `ValueT` objects, indexed by the id. llvm::SmallVector values_; - IdTag tag_; + IdTagType tag_; }; } // namespace Carbon diff --git a/toolchain/base/id_tag.h b/toolchain/base/id_tag.h index 712f1f188fb0..a8c84456ba52 100644 --- a/toolchain/base/id_tag.h +++ b/toolchain/base/id_tag.h @@ -10,17 +10,52 @@ #include #include "common/check.h" +#include "common/ostream.h" #include "llvm/Support/MathExtras.h" namespace Carbon { -// A tagged Id. It is used to add a tag into the unused bits of the id, in order -// to verify ids are used in the correct context. The tag should look like an -// Id, which is a non-negative number. -struct IdTag { - IdTag() = default; +// A sentinel type to construct an IdTag without tagging. +struct Untagged : Printable { + auto Print(llvm::raw_ostream& out) const -> void { out << ""; } +}; - explicit IdTag(int32_t tag, int32_t initial_reserved_ids) +// A wrapper type used as the template argument to IdTag, in order to mark the +// tag type as such. +template +struct Tag {}; + +template +struct GetTagIdType { + static_assert(false, "IdTag with TagT that is neither Untagged nor Tag"); +}; +template <> +struct GetTagIdType { + using TagIdType = Untagged; +}; +template +struct GetTagIdType> { + using TagIdType = TagIdT; +}; + +// Tests if an `IdTag` type is untagged. +template +concept IdTagIsUntagged = std::same_as; + +// A tagged Id. It is used to add a tag into the unused bits of the id, in order +// to verify ids are used in the correct context. The tag type must be `Tag` or +// `Untagged`. +template +struct IdTag { + using IdType = IdT; + using TagIdType = GetTagIdType::TagIdType; + + IdTag() + requires(IdTagIsUntagged) + = default; + + IdTag(TagIdType tag, int32_t initial_reserved_ids) + requires(!IdTagIsUntagged) : // Shift down by 1 to get out of the high bit to avoid using any // negative ids, since they have special uses. Shift down by another 1 // to free up the second highest bit for a marker to indicate whether @@ -28,43 +63,43 @@ struct IdTag { // index so it's not zero-based, to make it a bit less likely this // doesn't collide with anything else (though with the // second-highest-bit-tagging this might not be needed). - id_tag_(llvm::reverseBits((((tag + 1) << 1) | 1) << 1)), - initial_reserved_ids_(initial_reserved_ids) { - CARBON_CHECK( - tag != -1, - "IdTag should be default constructed if no tagging id is available."); - } + tag_(llvm::reverseBits((((tag.index + 1) << 1) | 1) << 1)), + initial_reserved_ids_(initial_reserved_ids) {} - auto Apply(int32_t index) const -> int32_t { + auto Apply(int32_t index) const -> IdT { CARBON_DCHECK(index >= 0, "{0}", index); if (index < initial_reserved_ids_) { - return index; + return IdT(index); } - // TODO: Assert that id_tag_ doesn't have the second highest bit set. - auto tagged_index = index ^ id_tag_; + // TODO: Assert that tag_ doesn't have the second highest bit set. + auto tagged_index = index ^ tag_; CARBON_DCHECK(tagged_index >= 0, "{0}", tagged_index); - return tagged_index; + return IdT(tagged_index); } - auto Remove(int32_t tagged_index) const -> int32_t { - CARBON_DCHECK(tagged_index >= 0, "{0}", tagged_index); - if (!HasTag(tagged_index)) { - CARBON_DCHECK(tagged_index < initial_reserved_ids_, + auto Remove(IdT id) const -> int32_t { + CARBON_DCHECK(id.index >= 0, "{0}", id); + if (!HasTag(id.index)) { + CARBON_DCHECK(id.index < initial_reserved_ids_, "This untagged index is outside the initial reserved ids " "and should have been tagged."); - return tagged_index; + return id.index; } - auto index = tagged_index ^ id_tag_; - CARBON_DCHECK(index >= initial_reserved_ids_, + auto untagged_index = id.index ^ tag_; + CARBON_DCHECK(untagged_index >= initial_reserved_ids_, "When removing tagging bits, found an index that " "shouldn't've been tagged in the first place."); - return index; + return untagged_index; } // Gets the value unique to this IdTag instance that is added to indices in // Apply, and removed in Remove. - auto GetContainerTag() const -> int32_t { - return (llvm::reverseBits(id_tag_) >> 2) - 1; + auto GetContainerTag() const -> TagIdType { + if constexpr (IdTagIsUntagged) { + return TagIdType(); + } else { + return TagIdType((llvm::reverseBits(tag_) >> 2) - 1); + } } // Returns whether `tagged_index` has an IdTag applied to it, from this IdTag @@ -73,56 +108,60 @@ struct IdTag { return (llvm::reverseBits(2) & tagged_index) != 0; } - template struct TagAndIndex { - int32_t tag; + TagIdType tag; int32_t index; }; - template - static auto DecomposeWithBestEffort(int32_t tagged_index) - -> TagAndIndex { - if (tagged_index < 0) { - // TODO: This should return TagT::None, but we need a fallback TagT other - // than `int32_t`. - return {TagT{-1}, tagged_index}; - } - if (!HasTag(tagged_index)) { - // TODO: This should return TagT::None, but we need a fallback TagT other - // than `int32_t`. - return {TagT{-1}, tagged_index}; - } - int length = 0; - int location = 0; - for (int i = 0; i != 32; ++i) { - int current_run = 0; - int location_of_current_run = i; - while (i != 32 && (tagged_index & (1 << i)) == 0) { - ++current_run; - ++i; + static auto DecomposeWithBestEffort(IdT id) -> TagAndIndex { + if constexpr (IdTagIsUntagged) { + return {TagIdType(), id.index}; + } else { + if (!id.has_value()) { + return {TagIdType::None, id.index}; } - if (current_run != 0) { - --i; + if (!HasTag(id.index)) { + return {TagIdType::None, id.index}; } - if (current_run > length) { - length = current_run; - location = location_of_current_run; + int length = 0; + int location = 0; + for (int i = 0; i != 32; ++i) { + int current_run = 0; + int location_of_current_run = i; + while (i != 32 && (id.index & (1 << i)) == 0) { + ++current_run; + ++i; + } + if (current_run != 0) { + --i; + } + if (current_run > length) { + length = current_run; + location = location_of_current_run; + } } + if (length < 8) { + return {TagIdType::None, id.index}; + } + auto index_mask = llvm::maskTrailingOnes(location); + auto tag = (llvm::reverseBits(id.index & ~index_mask) >> 2) - 1; + auto index = id.index & index_mask; + return {.tag = TagIdType(static_cast(tag)), + .index = static_cast(index)}; } - if (length < 8) { - // TODO: This should return TagT::None, but we need a fallback TagT other - // than `int32_t`. - return {TagT{-1}, tagged_index}; - } - auto index_mask = llvm::maskTrailingOnes(location); - auto tag = (llvm::reverseBits(tagged_index & ~index_mask) >> 2) - 1; - auto index = tagged_index & index_mask; - return {.tag = TagT{static_cast(tag)}, - .index = static_cast(index)}; + } + + // Converts an IdTag to be used for a different ID type. This is only valid + // when the id indices are interchangeable, as they will have the same tag and + // the same reserved ids. + template + requires(!IdTagIsUntagged) + auto ToEquivalentIdType() -> IdTag> { + return {GetContainerTag(), initial_reserved_ids_}; } private: - int32_t id_tag_ = 0; + int32_t tag_ = 0; int32_t initial_reserved_ids_ = std::numeric_limits::max(); }; diff --git a/toolchain/base/relational_value_store.h b/toolchain/base/relational_value_store.h index bbb7d8254d01..41b6bb530daa 100644 --- a/toolchain/base/relational_value_store.h +++ b/toolchain/base/relational_value_store.h @@ -35,6 +35,8 @@ template class RelationalValueStore { public: using RelatedIdType = RelatedStoreT::IdType; + using RelatedIdTagType = RelatedStoreT::IdTagType; + using RelatedTagIdType = RelatedIdTagType::TagIdType; using ValueType = ValueStoreTypes::ValueType; using ConstRefType = ValueStoreTypes::ConstRefType; @@ -50,7 +52,7 @@ class RelationalValueStore { CARBON_CHECK(!opt.has_value(), "Add with `related_id` that was already added to the store"); opt.emplace(std::move(value)); - return IdT(related_store_->GetIdTag().Apply(related_index)); + return IdT(related_store_->GetIdTag().Apply(related_index).index); } // Returns the ID of a value in the store if the `related_id` was previously @@ -64,7 +66,7 @@ class RelationalValueStore { if (!opt.has_value()) { return IdT::None; } - return IdT(related_store_->GetIdTag().Apply(related_index)); + return IdT(related_store_->GetIdTag().Apply(related_index).index); } // Returns a value for an ID. @@ -73,7 +75,8 @@ class RelationalValueStore { } private: - ValueStore> values_; + ValueStore, Tag> + values_; const RelatedStoreT* related_store_; }; diff --git a/toolchain/base/value_store.h b/toolchain/base/value_store.h index 6865c5979e2e..1810c7aeacc7 100644 --- a/toolchain/base/value_store.h +++ b/toolchain/base/value_store.h @@ -35,13 +35,14 @@ class ValueStoreNotPrintable {}; // A simple wrapper for accumulating values, providing IDs to later retrieve the // value. This does not do deduplication. -template +template class ValueStore : public std::conditional, ValueT>, - Yaml::Printable>, + Yaml::Printable>, Internal::ValueStoreNotPrintable> { public: using IdType = IdT; + using IdTagType = IdTag; using ValueType = ValueStoreTypes::ValueType; using RefType = ValueStoreTypes::RefType; using ConstRefType = ValueStoreTypes::ConstRefType; @@ -75,11 +76,21 @@ class ValueStore FlattenedRangeType flattened_range_; }; - ValueStore() = default; - explicit ValueStore(IdTag tag) : tag_(tag) {} - template - explicit ValueStore(Id id, int32_t initial_reserved_ids = 0) - : tag_(id.index, initial_reserved_ids) {} + // Default constructor, only valid when the IdTag's tag type is Untagged. + ValueStore() + requires(IdTagIsUntagged) + = default; + + // Construct a ValueStore sharing the IdTag from another ValueStore. Useful + // for when two ValueStores are sharing the same ID types. + explicit ValueStore(IdTagType tag) + requires(!IdTagIsUntagged) + : tag_(tag) {} + + // Construct a ValueStore with a given tag and set of untagged (reserved) ids. + explicit ValueStore(IdTagType::TagIdType id, int32_t initial_reserved_ids = 0) + requires(!IdTagIsUntagged) + : tag_(id, initial_reserved_ids) {} // Stores the value and returns an ID to reference it. auto Add(ValueType value) -> IdType { @@ -88,7 +99,7 @@ class ValueStore // tracking down issues easier. CARBON_DCHECK(size_ < std::numeric_limits::max(), "Id overflow"); - IdType id(tag_.Apply(size_)); + IdType id = tag_.Apply(size_); auto [chunk_index, pos] = RawIndexToChunkIndices(size_); ++size_; @@ -123,7 +134,7 @@ class ValueStore ConstRefType default_value [[clang::lifetimebound]]) const -> ConstRefType { CARBON_DCHECK(id.index >= 0, "{0}", id); - auto index = tag_.Remove(id.index); + auto index = tag_.Remove(id); if (index >= size_) { return default_value; } @@ -192,7 +203,7 @@ class ValueStore // Makes an iterable range over references to all values in the ValueStore. auto values() [[clang::lifetimebound]] -> auto { return llvm::map_range(llvm::seq(size_), [&](int32_t i) -> RefType { - return Get(IdType(tag_.Apply(i))); + return Get(tag_.Apply(i)); }); } auto values() const [[clang::lifetimebound]] -> Range { return Range(*this); } @@ -211,7 +222,7 @@ class ValueStore // `mapped_iterator` incorrectly infers the pointer type for `PointerProxy`. // NOLINTNEXTLINE(readability-const-return-type) auto index_to_id = [&](int32_t i) -> const std::pair { - IdType id(tag_.Apply(i)); + IdType id = tag_.Apply(i); return std::pair(id, Get(id)); }; // Because indices into `ValueStore` are all sequential values from 0, we @@ -219,10 +230,10 @@ class ValueStore return llvm::map_range(llvm::seq(size_), index_to_id); } - auto GetIdTag() const -> IdTag { return tag_; } + auto GetIdTag() const -> IdTagType { return tag_; } auto GetRawIndex(IdT id) const -> int32_t { CARBON_DCHECK(id.index >= 0, "{0}", index); - auto index = tag_.Remove(id.index); + auto index = tag_.Remove(id); #ifndef NDEBUG if (index >= size_) { // Attempt to decompose id.index to include extra detail in the check @@ -230,8 +241,7 @@ class ValueStore // // TODO: Teach ValueStore the type of the tag id with a template, then we // can print it with proper formatting instead of just as an integer. - auto [id_tag, id_untagged_index] = - IdTag::DecomposeWithBestEffort(id.index); + auto [id_tag, id_untagged_index] = IdTagType::DecomposeWithBestEffort(id); CARBON_DCHECK( index < size_, "Untagged index was outside of container range. Tagged index {0}. " @@ -390,7 +400,7 @@ class ValueStore // fits in an `int32_t`, which is checked in non-optimized builds in Add(). int32_t size_ = 0; - IdTag tag_; + IdTagType tag_; // Storage for the `ValueType` objects, indexed by the id. We use a vector of // chunks of `ValueType` instead of just a vector of `ValueType` so that diff --git a/toolchain/check/check_unit.cpp b/toolchain/check/check_unit.cpp index b4768d4b2041..412ea12cf8ac 100644 --- a/toolchain/check/check_unit.cpp +++ b/toolchain/check/check_unit.cpp @@ -169,9 +169,8 @@ auto CheckUnit::InitPackageScopeAndImports() -> void { auto CheckUnit::CollectDirectImports( llvm::SmallVector& results, - FixedSizeValueStore& ir_to_result_index, - SemIR::InstId import_decl_id, const PackageImports& imports, bool is_local) - -> void { + CheckIRIdToIntStore& ir_to_result_index, SemIR::InstId import_decl_id, + const PackageImports& imports, bool is_local) -> void { for (const auto& import : imports.imports) { const auto& direct_ir = *import.unit_info->unit->sem_ir; auto& index = ir_to_result_index.Get(direct_ir.check_ir_id()); @@ -198,9 +197,8 @@ auto CheckUnit::CollectTransitiveImports(SemIR::InstId import_decl_id, // Track whether an IR was imported in full, including `export import`. This // distinguishes from IRs that are indirectly added without all names being // exported to this IR. - auto ir_to_result_index = - FixedSizeValueStore::MakeWithExplicitSize( - IdTag(), unit_and_imports_->unit->total_ir_count, -1); + auto ir_to_result_index = CheckIRIdToIntStore::MakeWithExplicitSize( + unit_and_imports_->unit->total_ir_count, -1); // First add direct imports. This means that if an entity is imported both // directly and indirectly, the import path will reflect the direct import. diff --git a/toolchain/check/check_unit.h b/toolchain/check/check_unit.h index e3c4ed483e12..f9c6ec727312 100644 --- a/toolchain/check/check_unit.h +++ b/toolchain/check/check_unit.h @@ -134,15 +134,17 @@ class CheckUnit { auto Run() -> void; private: + using CheckIRIdToIntStore = FixedSizeValueStore; + // Add imports to the root block. auto InitPackageScopeAndImports() -> void; // Collects direct imports, for CollectTransitiveImports. - auto CollectDirectImports( - llvm::SmallVector& results, - FixedSizeValueStore& ir_to_result_index, - SemIR::InstId import_decl_id, const PackageImports& imports, - bool is_local) -> void; + auto CollectDirectImports(llvm::SmallVector& results, + CheckIRIdToIntStore& ir_to_result_index, + SemIR::InstId import_decl_id, + const PackageImports& imports, bool is_local) + -> void; // Collects transitive imports, handling deduplication. These will be unified // between local_imports and api_imports. diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 60ecab399e20..2ea44663a898 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -32,9 +32,8 @@ Context::Context(DiagnosticEmitterBase* emitter, scope_stack_(sem_ir_), deferred_definition_worklist_(vlog_stream), vtable_stack_("vtable_stack_", *sem_ir, vlog_stream), - check_ir_map_(FixedSizeValueStore:: - MakeWithExplicitSize(IdTag(), total_ir_count_, - SemIR::ImportIRId::None)), + check_ir_map_(CheckIRToImpportIRStore::MakeWithExplicitSize( + total_ir_count_, SemIR::ImportIRId::None)), global_init_(this), region_stack_([this](SemIR::LocId loc_id, std::string label) { TODO(loc_id, label); diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 4b20b70c7d0d..52ba28186b6b 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -158,10 +158,9 @@ class Context { auto exports() -> llvm::SmallVector& { return exports_; } - auto check_ir_map() - -> FixedSizeValueStore& { - return check_ir_map_; - } + using CheckIRToImpportIRStore = + FixedSizeValueStore; + auto check_ir_map() -> CheckIRToImpportIRStore& { return check_ir_map_; } auto import_ir_constant_values() -> llvm::SmallVector& { @@ -445,7 +444,7 @@ class Context { llvm::SmallVector exports_; // Maps CheckIRId to ImportIRId. - FixedSizeValueStore check_ir_map_; + CheckIRToImpportIRStore check_ir_map_; // Per-import constant values. These refer to the main IR and mainly serve as // a lookup table for quick access. diff --git a/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon b/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon index f5d134dea3ea..da3b0cbca6d8 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon @@ -378,18 +378,18 @@ fn Foo[T:! type](p: T*) -> (T*, ()) { // CHECK:STDOUT: value_repr: {kind: pointer, type: type(inst6000002C)} // CHECK:STDOUT: 'type(inst6000003D)': // CHECK:STDOUT: value_repr: {kind: none, type: type(inst60000025)} -// CHECK:STDOUT: 'type(symbolic_constant3)': -// CHECK:STDOUT: value_repr: {kind: copy, type: type(symbolic_constant3)} -// CHECK:STDOUT: 'type(symbolic_constantF)': -// CHECK:STDOUT: value_repr: {kind: copy, type: type(symbolic_constantF)} -// CHECK:STDOUT: 'type(symbolic_constant9)': -// CHECK:STDOUT: value_repr: {kind: pointer, type: type(symbolic_constantF)} +// CHECK:STDOUT: 'type(symbolic_constant60000003)': +// CHECK:STDOUT: value_repr: {kind: copy, type: type(symbolic_constant60000003)} +// CHECK:STDOUT: 'type(symbolic_constant6000000F)': +// CHECK:STDOUT: value_repr: {kind: copy, type: type(symbolic_constant6000000F)} +// CHECK:STDOUT: 'type(symbolic_constant60000009)': +// CHECK:STDOUT: value_repr: {kind: pointer, type: type(symbolic_constant6000000F)} // CHECK:STDOUT: 'type(inst(WitnessType))': // CHECK:STDOUT: value_repr: {kind: copy, type: type(inst(WitnessType))} -// CHECK:STDOUT: 'type(symbolic_constant4)': -// CHECK:STDOUT: value_repr: {kind: copy, type: type(symbolic_constant4)} -// CHECK:STDOUT: 'type(symbolic_constantA)': -// CHECK:STDOUT: value_repr: {kind: pointer, type: type(symbolic_constantF)} +// CHECK:STDOUT: 'type(symbolic_constant60000004)': +// CHECK:STDOUT: value_repr: {kind: copy, type: type(symbolic_constant60000004)} +// CHECK:STDOUT: 'type(symbolic_constant6000000A)': +// CHECK:STDOUT: value_repr: {kind: pointer, type: type(symbolic_constant6000000F)} // CHECK:STDOUT: 'type(inst(InstType))': // CHECK:STDOUT: value_repr: {kind: none, type: type(inst60000025)} // CHECK:STDOUT: 'type(inst6000004F)': @@ -420,11 +420,11 @@ fn Foo[T:! type](p: T*) -> (T*, ()) { // CHECK:STDOUT: inst6000001B: {kind: PointerType, arg0: inst6000001A, type: type(TypeType)} // CHECK:STDOUT: inst6000001C: {kind: PointerType, arg0: inst60000016, type: type(TypeType)} // CHECK:STDOUT: inst6000001D: {kind: PointerType, arg0: inst60000017, type: type(TypeType)} -// CHECK:STDOUT: inst6000001E: {kind: ValueBinding, arg0: entity_name60000002, arg1: inst60000038, type: type(symbolic_constant4)} +// CHECK:STDOUT: inst6000001E: {kind: ValueBinding, arg0: entity_name60000002, arg1: inst60000038, type: type(symbolic_constant60000004)} // CHECK:STDOUT: inst6000001F: {kind: PatternType, arg0: inst6000001C, type: type(TypeType)} -// CHECK:STDOUT: inst60000020: {kind: ValueBindingPattern, arg0: entity_name60000002, type: type(symbolic_constant6)} +// CHECK:STDOUT: inst60000020: {kind: ValueBindingPattern, arg0: entity_name60000002, type: type(symbolic_constant60000006)} // CHECK:STDOUT: inst60000021: {kind: PatternType, arg0: inst6000001D, type: type(TypeType)} -// CHECK:STDOUT: inst60000022: {kind: ValueParamPattern, arg0: inst60000020, arg1: call_param0, type: type(symbolic_constant6)} +// CHECK:STDOUT: inst60000022: {kind: ValueParamPattern, arg0: inst60000020, arg1: call_param0, type: type(symbolic_constant60000006)} // CHECK:STDOUT: inst60000023: {kind: NameRef, arg0: name1, arg1: inst60000015, type: type(TypeType)} // CHECK:STDOUT: inst60000024: {kind: PointerType, arg0: inst60000023, type: type(TypeType)} // CHECK:STDOUT: inst60000025: {kind: TupleType, arg0: inst_block_empty, type: type(TypeType)} @@ -443,13 +443,13 @@ fn Foo[T:! type](p: T*) -> (T*, ()) { // CHECK:STDOUT: inst60000032: {kind: InitForm, arg0: inst6000002E, arg1: call_param1, type: type(inst(FormType))} // CHECK:STDOUT: inst60000033: {kind: InitForm, arg0: inst60000030, arg1: call_param1, type: type(inst(FormType))} // CHECK:STDOUT: inst60000034: {kind: PatternType, arg0: inst6000002E, type: type(TypeType)} -// CHECK:STDOUT: inst60000035: {kind: ReturnSlotPattern, arg0: inst6000002F, type: type(symbolic_constantE)} +// CHECK:STDOUT: inst60000035: {kind: ReturnSlotPattern, arg0: inst6000002F, type: type(symbolic_constant6000000E)} // CHECK:STDOUT: inst60000036: {kind: PatternType, arg0: inst60000030, type: type(TypeType)} -// CHECK:STDOUT: inst60000037: {kind: OutParamPattern, arg0: inst60000035, arg1: call_param1, type: type(symbolic_constantE)} -// CHECK:STDOUT: inst60000038: {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(symbolic_constant4)} +// CHECK:STDOUT: inst60000037: {kind: OutParamPattern, arg0: inst60000035, arg1: call_param1, type: type(symbolic_constant6000000E)} +// CHECK:STDOUT: inst60000038: {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(symbolic_constant60000004)} // CHECK:STDOUT: inst60000039: {kind: SpliceBlock, arg0: inst_block60000006, arg1: inst6000001B, type: type(TypeType)} -// CHECK:STDOUT: inst6000003A: {kind: OutParam, arg0: call_param1, arg1: name(ReturnSlot), type: type(symbolic_constantA)} -// CHECK:STDOUT: inst6000003B: {kind: ReturnSlot, arg0: inst6000002E, arg1: inst6000003A, type: type(symbolic_constantA)} +// CHECK:STDOUT: inst6000003A: {kind: OutParam, arg0: call_param1, arg1: name(ReturnSlot), type: type(symbolic_constant6000000A)} +// CHECK:STDOUT: inst6000003B: {kind: ReturnSlot, arg0: inst6000002E, arg1: inst6000003A, type: type(symbolic_constant6000000A)} // CHECK:STDOUT: inst6000003C: {kind: FunctionDecl, arg0: function60000000, arg1: inst_block60000013, type: type(inst6000003D)} // CHECK:STDOUT: inst6000003D: {kind: FunctionType, arg0: function60000000, arg1: specific, type: type(TypeType)} // CHECK:STDOUT: inst6000003E: {kind: StructValue, arg0: inst_block_empty, type: type(inst6000003D)} @@ -461,11 +461,11 @@ fn Foo[T:! type](p: T*) -> (T*, ()) { // CHECK:STDOUT: inst60000044: {kind: RequireCompleteType, arg0: inst6000001C, type: type(inst(WitnessType))} // CHECK:STDOUT: inst60000045: {kind: RequireCompleteType, arg0: inst6000001D, type: type(inst(WitnessType))} // CHECK:STDOUT: inst60000046: {kind: RequireCompleteType, arg0: inst6000002E, type: type(inst(WitnessType))} -// CHECK:STDOUT: inst60000047: {kind: NameRef, arg0: name2, arg1: inst6000001E, type: type(symbolic_constant4)} +// CHECK:STDOUT: inst60000047: {kind: NameRef, arg0: name2, arg1: inst6000001E, type: type(symbolic_constant60000004)} // CHECK:STDOUT: inst60000048: {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst60000025)} -// CHECK:STDOUT: inst60000049: {kind: TupleLiteral, arg0: inst_block60000019, type: type(symbolic_constantA)} +// CHECK:STDOUT: inst60000049: {kind: TupleLiteral, arg0: inst_block60000019, type: type(symbolic_constant6000000A)} // CHECK:STDOUT: inst6000004A: {kind: RequireCompleteType, arg0: inst6000002E, type: type(inst(WitnessType))} -// CHECK:STDOUT: inst6000004B: {kind: TupleAccess, arg0: inst6000003A, arg1: element0, type: type(symbolic_constant4)} +// CHECK:STDOUT: inst6000004B: {kind: TupleAccess, arg0: inst6000003A, arg1: element0, type: type(symbolic_constant60000004)} // CHECK:STDOUT: inst6000004C: {kind: RequireCompleteType, arg0: inst6000001C, type: type(inst(WitnessType))} // CHECK:STDOUT: inst6000004D: {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: entity_name60000003, type: type(TypeType)} // CHECK:STDOUT: inst6000004E: {kind: InterfaceDecl, arg0: interface60000000, arg1: inst_block_empty, type: type(TypeType)} @@ -757,60 +757,60 @@ fn Foo[T:! type](p: T*) -> (T*, ()) { // CHECK:STDOUT: inst6000016C: {kind: SpecificImplFunction, arg0: inst60000168, arg1: specific60000019, type: type(inst(SpecificFunctionType))} // CHECK:STDOUT: inst6000016D: {kind: BoundMethod, arg0: inst60000047, arg1: inst6000016A, type: type(inst(BoundMethodType))} // CHECK:STDOUT: inst6000016E: {kind: RequireCompleteType, arg0: inst6000001C, type: type(inst(WitnessType))} -// CHECK:STDOUT: inst6000016F: {kind: Call, arg0: inst6000016D, arg1: inst_block6000007F, type: type(symbolic_constant4)} -// CHECK:STDOUT: inst60000170: {kind: InitializeFrom, arg0: inst6000016F, arg1: inst6000004B, type: type(symbolic_constant4)} +// CHECK:STDOUT: inst6000016F: {kind: Call, arg0: inst6000016D, arg1: inst_block6000007F, type: type(symbolic_constant60000004)} +// CHECK:STDOUT: inst60000170: {kind: InitializeFrom, arg0: inst6000016F, arg1: inst6000004B, type: type(symbolic_constant60000004)} // CHECK:STDOUT: inst60000171: {kind: TupleAccess, arg0: inst6000003A, arg1: element1, type: type(inst60000025)} // CHECK:STDOUT: inst60000172: {kind: TupleInit, arg0: inst_block_empty, arg1: inst60000171, type: type(inst60000025)} // CHECK:STDOUT: inst60000173: {kind: Converted, arg0: inst60000048, arg1: inst60000172, type: type(inst60000025)} -// CHECK:STDOUT: inst60000174: {kind: TupleInit, arg0: inst_block60000080, arg1: inst6000003A, type: type(symbolic_constantA)} -// CHECK:STDOUT: inst60000175: {kind: Converted, arg0: inst60000049, arg1: inst60000174, type: type(symbolic_constantA)} +// CHECK:STDOUT: inst60000174: {kind: TupleInit, arg0: inst_block60000080, arg1: inst6000003A, type: type(symbolic_constant6000000A)} +// CHECK:STDOUT: inst60000175: {kind: Converted, arg0: inst60000049, arg1: inst60000174, type: type(symbolic_constant6000000A)} // CHECK:STDOUT: inst60000176: {kind: ReturnExpr, arg0: inst60000175, arg1: inst6000003A} // CHECK:STDOUT: constant_values: // CHECK:STDOUT: values: // CHECK:STDOUT: instF: concrete_constant(instF) // CHECK:STDOUT: inst60000011: concrete_constant(inst60000011) // CHECK:STDOUT: inst60000012: concrete_constant(inst60000012) -// CHECK:STDOUT: inst60000013: symbolic_constant0 -// CHECK:STDOUT: inst60000014: symbolic_constant0 -// CHECK:STDOUT: inst60000015: symbolic_constant2 -// CHECK:STDOUT: inst60000016: symbolic_constant1 -// CHECK:STDOUT: inst60000017: symbolic_constant2 +// CHECK:STDOUT: inst60000013: symbolic_constant60000000 +// CHECK:STDOUT: inst60000014: symbolic_constant60000000 +// CHECK:STDOUT: inst60000015: symbolic_constant60000002 +// CHECK:STDOUT: inst60000016: symbolic_constant60000001 +// CHECK:STDOUT: inst60000017: symbolic_constant60000002 // CHECK:STDOUT: inst60000018: concrete_constant(inst60000018) // CHECK:STDOUT: inst60000019: concrete_constant(inst60000019) -// CHECK:STDOUT: inst6000001A: symbolic_constant2 -// CHECK:STDOUT: inst6000001B: symbolic_constant4 -// CHECK:STDOUT: inst6000001C: symbolic_constant3 -// CHECK:STDOUT: inst6000001D: symbolic_constant4 -// CHECK:STDOUT: inst6000001F: symbolic_constant5 +// CHECK:STDOUT: inst6000001A: symbolic_constant60000002 +// CHECK:STDOUT: inst6000001B: symbolic_constant60000004 +// CHECK:STDOUT: inst6000001C: symbolic_constant60000003 +// CHECK:STDOUT: inst6000001D: symbolic_constant60000004 +// CHECK:STDOUT: inst6000001F: symbolic_constant60000005 // CHECK:STDOUT: inst60000020: concrete_constant(inst60000020) -// CHECK:STDOUT: inst60000021: symbolic_constant6 +// CHECK:STDOUT: inst60000021: symbolic_constant60000006 // CHECK:STDOUT: inst60000022: concrete_constant(inst60000022) -// CHECK:STDOUT: inst60000023: symbolic_constant2 -// CHECK:STDOUT: inst60000024: symbolic_constant4 +// CHECK:STDOUT: inst60000023: symbolic_constant60000002 +// CHECK:STDOUT: inst60000024: symbolic_constant60000004 // CHECK:STDOUT: inst60000025: concrete_constant(inst60000025) // CHECK:STDOUT: inst60000026: concrete_constant(inst60000027) // CHECK:STDOUT: inst60000027: concrete_constant(inst60000027) // CHECK:STDOUT: inst60000028: concrete_constant(inst60000028) -// CHECK:STDOUT: inst60000029: symbolic_constant8 -// CHECK:STDOUT: inst6000002A: symbolic_constant7 -// CHECK:STDOUT: inst6000002B: symbolic_constant8 +// CHECK:STDOUT: inst60000029: symbolic_constant60000008 +// CHECK:STDOUT: inst6000002A: symbolic_constant60000007 +// CHECK:STDOUT: inst6000002B: symbolic_constant60000008 // CHECK:STDOUT: inst6000002C: concrete_constant(inst6000002C) // CHECK:STDOUT: inst6000002D: concrete_constant(inst60000025) -// CHECK:STDOUT: inst6000002E: symbolic_constant9 -// CHECK:STDOUT: inst6000002F: symbolic_constantA -// CHECK:STDOUT: inst60000030: symbolic_constantA -// CHECK:STDOUT: inst60000031: symbolic_constantC -// CHECK:STDOUT: inst60000032: symbolic_constantB -// CHECK:STDOUT: inst60000033: symbolic_constantC -// CHECK:STDOUT: inst60000034: symbolic_constantD +// CHECK:STDOUT: inst6000002E: symbolic_constant60000009 +// CHECK:STDOUT: inst6000002F: symbolic_constant6000000A +// CHECK:STDOUT: inst60000030: symbolic_constant6000000A +// CHECK:STDOUT: inst60000031: symbolic_constant6000000C +// CHECK:STDOUT: inst60000032: symbolic_constant6000000B +// CHECK:STDOUT: inst60000033: symbolic_constant6000000C +// CHECK:STDOUT: inst60000034: symbolic_constant6000000D // CHECK:STDOUT: inst60000035: concrete_constant(inst60000035) -// CHECK:STDOUT: inst60000036: symbolic_constantE +// CHECK:STDOUT: inst60000036: symbolic_constant6000000E // CHECK:STDOUT: inst60000037: concrete_constant(inst60000037) -// CHECK:STDOUT: inst60000039: symbolic_constant4 +// CHECK:STDOUT: inst60000039: symbolic_constant60000004 // CHECK:STDOUT: inst6000003C: concrete_constant(inst6000003E) // CHECK:STDOUT: inst6000003D: concrete_constant(inst6000003D) // CHECK:STDOUT: inst6000003E: concrete_constant(inst6000003E) -// CHECK:STDOUT: inst6000003F: symbolic_constantF +// CHECK:STDOUT: inst6000003F: symbolic_constant6000000F // CHECK:STDOUT: inst60000040: symbolic_constant60000011 // CHECK:STDOUT: inst60000041: symbolic_constant60000010 // CHECK:STDOUT: inst60000042: symbolic_constant60000011 @@ -1112,22 +1112,22 @@ fn Foo[T:! type](p: T*) -> (T*, ()) { // CHECK:STDOUT: inst60000172: concrete_constant(inst60000027) // CHECK:STDOUT: inst60000173: concrete_constant(inst60000027) // CHECK:STDOUT: symbolic_constants: -// CHECK:STDOUT: symbolic_constant0: {inst: inst60000014, generic: generic, index: generic_inst, kind: self} -// CHECK:STDOUT: symbolic_constant1: {inst: inst60000016, generic: generic, index: generic_inst, kind: checked} -// CHECK:STDOUT: symbolic_constant2: {inst: inst60000016, generic: generic60000000, index: generic_inst_in_decl0, kind: checked} -// CHECK:STDOUT: symbolic_constant3: {inst: inst6000001C, generic: generic, index: generic_inst, kind: checked} -// CHECK:STDOUT: symbolic_constant4: {inst: inst6000001C, generic: generic60000000, index: generic_inst_in_decl1, kind: checked} -// CHECK:STDOUT: symbolic_constant5: {inst: inst6000001F, generic: generic, index: generic_inst, kind: checked} -// CHECK:STDOUT: symbolic_constant6: {inst: inst6000001F, generic: generic60000000, index: generic_inst_in_decl2, kind: checked} -// CHECK:STDOUT: symbolic_constant7: {inst: inst6000002A, generic: generic, index: generic_inst, kind: checked} -// CHECK:STDOUT: symbolic_constant8: {inst: inst6000002A, generic: generic60000000, index: generic_inst_in_decl3, kind: checked} -// CHECK:STDOUT: symbolic_constant9: {inst: inst6000002E, generic: generic, index: generic_inst, kind: checked} -// CHECK:STDOUT: symbolic_constantA: {inst: inst6000002E, generic: generic60000000, index: generic_inst_in_decl4, kind: checked} -// CHECK:STDOUT: symbolic_constantB: {inst: inst60000032, generic: generic, index: generic_inst, kind: checked} -// CHECK:STDOUT: symbolic_constantC: {inst: inst60000032, generic: generic60000000, index: generic_inst_in_decl5, kind: checked} -// CHECK:STDOUT: symbolic_constantD: {inst: inst60000034, generic: generic, index: generic_inst, kind: checked} -// CHECK:STDOUT: symbolic_constantE: {inst: inst60000034, generic: generic60000000, index: generic_inst_in_decl6, kind: checked} -// CHECK:STDOUT: symbolic_constantF: {inst: inst6000003F, generic: generic, index: generic_inst, kind: checked} +// CHECK:STDOUT: symbolic_constant60000000: {inst: inst60000014, generic: generic, index: generic_inst, kind: self} +// CHECK:STDOUT: symbolic_constant60000001: {inst: inst60000016, generic: generic, index: generic_inst, kind: checked} +// CHECK:STDOUT: symbolic_constant60000002: {inst: inst60000016, generic: generic60000000, index: generic_inst_in_decl0, kind: checked} +// CHECK:STDOUT: symbolic_constant60000003: {inst: inst6000001C, generic: generic, index: generic_inst, kind: checked} +// CHECK:STDOUT: symbolic_constant60000004: {inst: inst6000001C, generic: generic60000000, index: generic_inst_in_decl1, kind: checked} +// CHECK:STDOUT: symbolic_constant60000005: {inst: inst6000001F, generic: generic, index: generic_inst, kind: checked} +// CHECK:STDOUT: symbolic_constant60000006: {inst: inst6000001F, generic: generic60000000, index: generic_inst_in_decl2, kind: checked} +// CHECK:STDOUT: symbolic_constant60000007: {inst: inst6000002A, generic: generic, index: generic_inst, kind: checked} +// CHECK:STDOUT: symbolic_constant60000008: {inst: inst6000002A, generic: generic60000000, index: generic_inst_in_decl3, kind: checked} +// CHECK:STDOUT: symbolic_constant60000009: {inst: inst6000002E, generic: generic, index: generic_inst, kind: checked} +// CHECK:STDOUT: symbolic_constant6000000A: {inst: inst6000002E, generic: generic60000000, index: generic_inst_in_decl4, kind: checked} +// CHECK:STDOUT: symbolic_constant6000000B: {inst: inst60000032, generic: generic, index: generic_inst, kind: checked} +// CHECK:STDOUT: symbolic_constant6000000C: {inst: inst60000032, generic: generic60000000, index: generic_inst_in_decl5, kind: checked} +// CHECK:STDOUT: symbolic_constant6000000D: {inst: inst60000034, generic: generic, index: generic_inst, kind: checked} +// CHECK:STDOUT: symbolic_constant6000000E: {inst: inst60000034, generic: generic60000000, index: generic_inst_in_decl6, kind: checked} +// CHECK:STDOUT: symbolic_constant6000000F: {inst: inst6000003F, generic: generic, index: generic_inst, kind: checked} // CHECK:STDOUT: symbolic_constant60000010: {inst: inst60000041, generic: generic, index: generic_inst, kind: checked} // CHECK:STDOUT: symbolic_constant60000011: {inst: inst60000041, generic: generic60000000, index: generic_inst_in_def0, kind: checked} // CHECK:STDOUT: symbolic_constant60000012: {inst: inst60000044, generic: generic, index: generic_inst, kind: checked} diff --git a/toolchain/driver/compile_subcommand.cpp b/toolchain/driver/compile_subcommand.cpp index ad5cb6932564..3b45c30d323e 100644 --- a/toolchain/driver/compile_subcommand.cpp +++ b/toolchain/driver/compile_subcommand.cpp @@ -616,8 +616,8 @@ class MultiUnitCache { auto include_in_dumps() -> const IncludeInDumpsStore& { if (!include_in_dumps_) { - include_in_dumps_.emplace(IncludeInDumpsStore::MakeWithExplicitSize( - IdTag(), units_.size(), false)); + include_in_dumps_.emplace( + IncludeInDumpsStore::MakeWithExplicitSize(units_.size(), false)); for (const auto& [i, unit] : llvm::enumerate(units_)) { // If this is first accessed after lexing is complete, we need to apply // per-file includes. Otherwise, this is based only on the exclude @@ -637,8 +637,8 @@ class MultiUnitCache { auto tree_and_subtrees_getters() -> const TreeAndSubtreesGettersStore& { if (!tree_and_subtrees_getters_) { tree_and_subtrees_getters_.emplace( - TreeAndSubtreesGettersStore::MakeWithExplicitSize( - IdTag(), units_.size(), nullptr)); + TreeAndSubtreesGettersStore::MakeWithExplicitSize(units_.size(), + nullptr)); for (const auto& [i, unit] : llvm::enumerate(units_)) { if (unit->has_source()) { tree_and_subtrees_getters_->Set(SemIR::CheckIRId(i), diff --git a/toolchain/language_server/context.cpp b/toolchain/language_server/context.cpp index 635c8beb8fba..50c9ba0669f5 100644 --- a/toolchain/language_server/context.cpp +++ b/toolchain/language_server/context.cpp @@ -166,7 +166,7 @@ auto Context::File::SetText(Context& context, std::optional version, Check::CheckParseTreesOptions check_options; check_options.vlog_stream = context.vlog_stream(); auto getters = - Parse::GetTreeAndSubtreesStore::MakeWithExplicitSize(IdTag(), 1, getter); + Parse::GetTreeAndSubtreesStore::MakeWithExplicitSize(1, getter); auto clang_invocation = BuildClangInvocation(consumer, fs, context.installation(), diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index 9e2577ad2078..9466e364c1b3 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -51,11 +51,11 @@ FileContext::FileContext(Context& context, const SemIR::File& sem_ir, vlog_stream_(vlog_stream), functions_(LoweredFunctionStore::MakeForOverwrite(sem_ir.functions())), specific_functions_(sem_ir.specifics(), nullptr), - types_(LoweredTypeStore::MakeWithExplicitSize(sem_ir.insts().GetIdTag(), - sem_ir.insts().size(), - {nullptr, nullptr})), + types_(LoweredTypeStore::MakeWithExplicitSize( + sem_ir.constant_values().ConcreteStoreSize(), + sem_ir.constant_values().GetTypeIdTag(), {nullptr, nullptr})), constants_(LoweredConstantStore::MakeWithExplicitSize( - sem_ir.insts().GetIdTag(), sem_ir.insts().size(), nullptr)), + sem_ir.insts().size(), sem_ir.insts().GetIdTag(), nullptr)), lowered_specifics_(sem_ir.generics(), llvm::SmallVector()), coalescer_(vlog_stream_, sem_ir.specifics()), diff --git a/toolchain/lower/file_context.h b/toolchain/lower/file_context.h index 7b6c7de12a5b..87fb25cb180b 100644 --- a/toolchain/lower/file_context.h +++ b/toolchain/lower/file_context.h @@ -21,7 +21,8 @@ namespace Carbon::Lower { class FileContext { public: using LoweredConstantStore = - FixedSizeValueStore; + FixedSizeValueStore>; explicit FileContext(Context& context, const SemIR::File& sem_ir, const SemIR::InstNamer* inst_namer, @@ -249,14 +250,19 @@ class FileContext { // Maps callables to lowered functions. SemIR treats callables as the // canonical form of a function, so lowering needs to do the same. using LoweredFunctionStore = - FixedSizeValueStore; + FixedSizeValueStore>; LoweredFunctionStore functions_; // Maps specific callables to lowered functions. - FixedSizeValueStore specific_functions_; + FixedSizeValueStore> + specific_functions_; // Provides lowered versions of types. Entries are non-symbolic types. - using LoweredTypeStore = FixedSizeValueStore; + // + // TypeIds internally are concrete ConstantIds. + using LoweredTypeStore = + FixedSizeValueStore>; LoweredTypeStore types_; // Maps constants to their lowered values. Indexes are the `InstId` for @@ -269,13 +275,17 @@ class FileContext { // For a generic function, keep track of the specifics for which LLVM // function declarations were created. Those can be retrieved then from // `specific_functions_`. - FixedSizeValueStore> + FixedSizeValueStore, + Tag> lowered_specifics_; SpecificCoalescer coalescer_; - FixedSizeValueStore vtables_; - FixedSizeValueStore + FixedSizeValueStore> + vtables_; + FixedSizeValueStore> specific_vtables_; }; diff --git a/toolchain/lower/specific_coalescer.h b/toolchain/lower/specific_coalescer.h index 48ffdec55ad6..74bf4b2c39ea 100644 --- a/toolchain/lower/specific_coalescer.h +++ b/toolchain/lower/specific_coalescer.h @@ -16,9 +16,11 @@ class SpecificCoalescer { public: using LoweredSpecificsStore = FixedSizeValueStore>; + llvm::SmallVector, + Tag>; using LoweredLlvmFunctionStore = - FixedSizeValueStore; + FixedSizeValueStore>; // Describes a specific function's body fingerprint. struct SpecificFunctionFingerprint { @@ -128,11 +130,13 @@ class SpecificCoalescer { // For specifics that exist in lowered_specifics, a hash of their function // type information. - FixedSizeValueStore> + FixedSizeValueStore, + Tag> lowered_specifics_type_fingerprint_; // This is initialized and populated while lowering a specific. - FixedSizeValueStore + FixedSizeValueStore> lowered_specific_fingerprint_; // Equivalent specifics that have been found. For each specific, this points @@ -142,7 +146,8 @@ class SpecificCoalescer { // // Entries are initialized to `SpecificId::None`, which defines that there is // no other equivalent specific to this `SpecificId`. - FixedSizeValueStore + FixedSizeValueStore> equivalent_specifics_; // Non-equivalent specifics found. diff --git a/toolchain/sem_ir/associated_constant.h b/toolchain/sem_ir/associated_constant.h index 69c1b96882e6..8a8108b133b4 100644 --- a/toolchain/sem_ir/associated_constant.h +++ b/toolchain/sem_ir/associated_constant.h @@ -50,7 +50,7 @@ struct AssociatedConstant : public Printable { }; using AssociatedConstantStore = - ValueStore; + ValueStore>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/clang_decl.h b/toolchain/sem_ir/clang_decl.h index d7d0e75dee24..aaa4158a9a4b 100644 --- a/toolchain/sem_ir/clang_decl.h +++ b/toolchain/sem_ir/clang_decl.h @@ -96,7 +96,7 @@ struct ClangDecl : public Printable { // Use the AST node pointer directly when doing `Lookup` to find an ID. using ClangDeclStore = - CanonicalValueStore; + CanonicalValueStore, ClangDecl>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/class.h b/toolchain/sem_ir/class.h index c1e70732600e..641aee9b0132 100644 --- a/toolchain/sem_ir/class.h +++ b/toolchain/sem_ir/class.h @@ -116,7 +116,7 @@ struct Class : public EntityWithParamsBase, auto GetObjectRepr(const File& file, SpecificId specific_id) const -> TypeId; }; -using ClassStore = ValueStore; +using ClassStore = ValueStore>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/constant.h b/toolchain/sem_ir/constant.h index 91c49fe71cd2..54a5dd8f2ea0 100644 --- a/toolchain/sem_ir/constant.h +++ b/toolchain/sem_ir/constant.h @@ -116,12 +116,15 @@ class ConstantValueStore { // Constructs an unusable ConstantValueStore, only good as a placeholder (eg: // in C++ interop, where there's no foreign SemIR to reference) explicit ConstantValueStore(UnusableType /* tag */) - : default_(ConstantId::None), insts_(nullptr) {} + : default_(ConstantId::None), + values_(CheckIRId::None), + symbolic_constants_(CheckIRId::None), + insts_(nullptr) {} explicit ConstantValueStore(ConstantId default_value, const InstStore* insts) : default_(default_value), - values_((CARBON_CHECK(insts), insts->GetIdTag())), - symbolic_constants_(insts->GetIdTag()), + values_(insts->GetIdTag()), + symbolic_constants_(insts->GetIdTag().GetContainerTag()), insts_(insts) {} // Returns the constant value of the requested instruction, which is default_ @@ -247,6 +250,26 @@ class ConstantValueStore { }); } + // The tag used in ConstantIds for concrete constants. + using ConcreteIdTagType = IdTag>; + auto GetConcreteIdTag() const -> ConcreteIdTagType { + return values_.GetIdTag().ToEquivalentIdType(); + } + // The tag used for TypeId, which are concrete constants internally. + using TypeIdTagType = IdTag>; + auto GetTypeIdTag() const -> TypeIdTagType { + return values_.GetIdTag().ToEquivalentIdType(); + } + // The tag used in ConstantIds for symbolic constants. + using SymbolicIdTagType = + IdTag>; + auto GetSymbolicIdTag() const -> SymbolicIdTagType { + return symbolic_constants_.GetIdTag(); + } + + // The size of the value store for concrete constant values. + auto ConcreteStoreSize() const -> size_t { return values_.size(); } + private: const ConstantId default_; @@ -256,14 +279,15 @@ class ConstantValueStore { // // Set inline size to 0 because these will typically be too large for the // stack, while this does make File smaller. - ValueStore values_; + ValueStore> values_; // A mapping from a symbolic constant ID index to information about the // symbolic constant. For a concrete constant, the only information that we // track is the instruction ID, which is stored directly within the // `ConstantId`. For a symbolic constant, we also track information about // where the constant was used, which is stored here. - ValueStore symbolic_constants_; + ValueStore> + symbolic_constants_; const InstStore* insts_; }; diff --git a/toolchain/sem_ir/cpp_global_var.h b/toolchain/sem_ir/cpp_global_var.h index e7c597411b02..586b176d8f0c 100644 --- a/toolchain/sem_ir/cpp_global_var.h +++ b/toolchain/sem_ir/cpp_global_var.h @@ -49,8 +49,8 @@ struct CppGlobalVar : public Printable { }; // Use the name of a C++ global variable when doing `Lookup` to find an ID. -using CppGlobalVarStore = - CanonicalValueStore; +using CppGlobalVarStore = CanonicalValueStore, CppGlobalVar>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/cpp_overload_set.h b/toolchain/sem_ir/cpp_overload_set.h index ad532f82fb4f..30ded7b2df02 100644 --- a/toolchain/sem_ir/cpp_overload_set.h +++ b/toolchain/sem_ir/cpp_overload_set.h @@ -39,7 +39,8 @@ struct CppOverloadSet : public Printable { } }; -using CppOverloadSetStore = ValueStore; +using CppOverloadSetStore = + ValueStore>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/entity_name.h b/toolchain/sem_ir/entity_name.h index 404ce3da919a..1c62133e7e04 100644 --- a/toolchain/sem_ir/entity_name.h +++ b/toolchain/sem_ir/entity_name.h @@ -60,7 +60,8 @@ struct EntityName : public Printable { // Value store for EntityName. In addition to the regular ValueStore // functionality, this can provide optional canonical IDs for EntityNames. -struct EntityNameStore : public ValueStore { +struct EntityNameStore + : public ValueStore> { public: using ValueStore::ValueStore; diff --git a/toolchain/sem_ir/facet_type_info.h b/toolchain/sem_ir/facet_type_info.h index a8de9d549e39..2584780bbdbb 100644 --- a/toolchain/sem_ir/facet_type_info.h +++ b/toolchain/sem_ir/facet_type_info.h @@ -113,7 +113,8 @@ constexpr FacetTypeInfo::RewriteConstraint FacetTypeInfo::RewriteConstraint::None = {.lhs_id = InstId::None, .rhs_id = InstId::None}; -using FacetTypeInfoStore = CanonicalValueStore; +using FacetTypeInfoStore = + CanonicalValueStore>; struct IdentifiedFacetType { using RequiredInterface = SpecificInterface; diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 823a4e38b50f..dac5d6d19a88 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -43,7 +43,7 @@ File::File(const Parse::Tree* parse_tree, CheckIRId check_ir_id, named_constraints_(check_ir_id), require_impls_(check_ir_id), // 1 reserved id for `RequireImplsBlockId::Empty`. - require_impls_blocks_(allocator_, IdTag(check_ir_id.index, 1)), + require_impls_blocks_(allocator_, check_ir_id, 1), associated_constants_(check_ir_id), facet_types_(check_ir_id), identified_facet_types_(&facet_types_), @@ -53,7 +53,7 @@ File::File(const Parse::Tree* parse_tree, CheckIRId check_ir_id, specifics_(check_ir_id), // The `2` prevents adding a tag for the global ids // `ImportIRId::{ApiForImpl,Cpp}`. - import_irs_(IdTag(check_ir_id.index, 2)), + import_irs_(check_ir_id, 2), clang_decls_(check_ir_id), // The `+1` prevents adding a tag to the global `NameSpace::PackageInstId` // instruction. It's not a "singleton" instruction, but it's a unique @@ -64,9 +64,9 @@ File::File(const Parse::Tree* parse_tree, CheckIRId check_ir_id, inst_blocks_(allocator_, check_ir_id), constants_(this), // 1 reserved id for `StructTypeFieldsId::Empty`. - struct_type_fields_(allocator_, IdTag(check_ir_id.index, 1)), + struct_type_fields_(allocator_, check_ir_id, 1), // 1 reserved id for `CustomLayoutId::Empty`. - custom_layouts_(allocator_, IdTag(check_ir_id.index, 1)), + custom_layouts_(allocator_, check_ir_id, 1), expr_regions_(check_ir_id), clang_source_locs_(check_ir_id) { // `type`, `form`, and the error type are both complete & concrete types. diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 2630ee6e8807..e6a22d32a1b6 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -63,9 +63,10 @@ struct ExprRegion { InstId result_id; }; -using ExprRegionStore = ValueStore; +using ExprRegionStore = ValueStore>; -using CustomLayoutStore = BlockValueStore; +using CustomLayoutStore = + BlockValueStore>; // The semantic IR for a single file. class File : public Printable { @@ -264,7 +265,7 @@ class File : public Printable { auto expr_regions() const -> const ExprRegionStore& { return expr_regions_; } using ClangSourceLocStore = - ValueStore; + ValueStore>; auto clang_source_locs() -> ClangSourceLocStore& { return clang_source_locs_; } @@ -409,7 +410,7 @@ class File : public Printable { StructTypeFieldsStore struct_type_fields_; // Storage for custom layouts. - CustomLayoutStore custom_layouts_ = CustomLayoutStore(allocator_); + CustomLayoutStore custom_layouts_; // Descriptions of types used in this file. TypeStore types_ = TypeStore(this); diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index bab69523da00..126cafa10766 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -120,7 +120,7 @@ auto Formatter::Format() -> void { auto Formatter::ComputeNodeParents() -> void { CARBON_CHECK(!node_parents_); node_parents_ = NodeParentStore::MakeWithExplicitSize( - IdTag(), sem_ir_->parse_tree().size(), Parse::NodeId::None); + sem_ir_->parse_tree().size(), Parse::NodeId::None); for (auto n : sem_ir_->parse_tree().postorder()) { for (auto child : get_tree_and_subtrees_().children(n)) { node_parents_->Set(child, n); diff --git a/toolchain/sem_ir/formatter.h b/toolchain/sem_ir/formatter.h index bc259623d630..d0447a7db101 100644 --- a/toolchain/sem_ir/formatter.h +++ b/toolchain/sem_ir/formatter.h @@ -407,7 +407,7 @@ class Formatter { // Indexes of chunks of output that should be included when an instruction is // referenced, indexed by the instruction's index. - FixedSizeValueStore tentative_inst_chunks_; + FixedSizeValueStore> tentative_inst_chunks_; // Maps nodes to their parents. Only set when dump ranges are in use, because // the parents aren't used otherwise. diff --git a/toolchain/sem_ir/function.h b/toolchain/sem_ir/function.h index d4b552f9875b..79a0c7d55d43 100644 --- a/toolchain/sem_ir/function.h +++ b/toolchain/sem_ir/function.h @@ -213,7 +213,7 @@ struct Function : public EntityWithParamsBase, } }; -using FunctionStore = ValueStore; +using FunctionStore = ValueStore>; class File; diff --git a/toolchain/sem_ir/generic.cpp b/toolchain/sem_ir/generic.cpp index bff25fc47a7e..cd828a646c7b 100644 --- a/toolchain/sem_ir/generic.cpp +++ b/toolchain/sem_ir/generic.cpp @@ -19,8 +19,7 @@ class SpecificStore::KeyContext : public TranslatingKeyContext { friend auto operator==(const Key&, const Key&) -> bool = default; }; - explicit KeyContext(const ValueStore* specifics) - : specifics_(specifics) {} + explicit KeyContext(const ValueStore* specifics) : specifics_(specifics) {} auto TranslateKey(SpecificId id) const -> Key { const auto& specific = specifics_->Get(id); @@ -28,7 +27,7 @@ class SpecificStore::KeyContext : public TranslatingKeyContext { } private: - const ValueStore* specifics_; + const ValueStore* specifics_; }; auto SpecificStore::GetOrAdd(GenericId generic_id, InstBlockId args_id) diff --git a/toolchain/sem_ir/generic.h b/toolchain/sem_ir/generic.h index 3ce86474d9c6..a76fe30d9d90 100644 --- a/toolchain/sem_ir/generic.h +++ b/toolchain/sem_ir/generic.h @@ -53,7 +53,7 @@ struct Generic : public Printable { }; // Provides storage for generics. -class GenericStore : public ValueStore { +class GenericStore : public ValueStore> { public: using ValueStore::ValueStore; @@ -109,6 +109,7 @@ struct Specific : Printable { class SpecificStore : public Yaml::Printable { public: using IdType = SpecificId; + using ValueStore = ValueStore>; explicit SpecificStore(CheckIRId check_ir_id) : specifics_(check_ir_id) {} @@ -144,8 +145,7 @@ class SpecificStore : public Yaml::Printable { auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const -> void; - auto values() const [[clang::lifetimebound]] - -> ValueStore::Range { + auto values() const [[clang::lifetimebound]] -> ValueStore::Range { return specifics_.values(); } auto size() const -> size_t { return specifics_.size(); } @@ -159,7 +159,7 @@ class SpecificStore : public Yaml::Printable { // Context for hashing keys. class KeyContext; - ValueStore specifics_; + ValueStore specifics_; Carbon::Set lookup_table_; }; diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 403838ca6429..479ed0ca1ec9 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -173,6 +173,11 @@ class MetaInstId : public InstId { // constant instruction that defines the constant. Symbolic constants are an // index into a separate table of `SymbolicConstant`s maintained by the constant // value store. +// +// IdTags for ConstantIds are slightly complex, and you need to know if the +// constant is concrete or symbolic to know its tag: +// - Concrete ConstantIds use the tag of the store of InstIds. +// - Symbolic ConstantIds use the tag of the store of internal SymbolicIds. struct ConstantId : public IdBase { static constexpr llvm::StringLiteral Label = "constant"; diff --git a/toolchain/sem_ir/impl.h b/toolchain/sem_ir/impl.h index ffc4f80264e2..ada254edd9d2 100644 --- a/toolchain/sem_ir/impl.h +++ b/toolchain/sem_ir/impl.h @@ -202,7 +202,7 @@ class ImplStore { } auto values() const [[clang::lifetimebound]] - -> ValueStore::Range { + -> ValueStore>::Range { return values_.values(); } auto size() const -> size_t { return values_.size(); } @@ -212,7 +212,7 @@ class ImplStore { private: File& sem_ir_; - ValueStore values_; + ValueStore> values_; Map, ImplOrLookupBucketId> lookup_; // Buckets with at least 2 entries, which will be rare; see LookupBucketRef. llvm::SmallVector> lookup_buckets_; diff --git a/toolchain/sem_ir/import_ir.h b/toolchain/sem_ir/import_ir.h index 4494addb6ea1..5846461a53d0 100644 --- a/toolchain/sem_ir/import_ir.h +++ b/toolchain/sem_ir/import_ir.h @@ -26,7 +26,7 @@ struct ImportIR : public Printable { static_assert(sizeof(ImportIR) == 8 + sizeof(uintptr_t), "Unexpected size"); -using ImportIRStore = ValueStore; +using ImportIRStore = ValueStore>; // A reference to an instruction in an imported IR. Used for diagnostics with // LocId. For a `Cpp` import, points to a Clang source location. diff --git a/toolchain/sem_ir/inst.h b/toolchain/sem_ir/inst.h index 2cbe14d88928..899d8cab1a0e 100644 --- a/toolchain/sem_ir/inst.h +++ b/toolchain/sem_ir/inst.h @@ -459,6 +459,7 @@ struct LocIdAndInst { class InstStore { public: using IdType = InstId; + using IdTagType = IdTag>; explicit InstStore(File* file, int32_t reserved_inst_ids); @@ -658,7 +659,7 @@ class InstStore { } auto values() const [[clang::lifetimebound]] - -> ValueStore::Range { + -> ValueStore>::Range { return values_.values(); } auto size() const -> int { return values_.size(); } @@ -670,7 +671,7 @@ class InstStore { return values_.GetRawIndex(id); } - auto GetIdTag() const -> IdTag { return values_.GetIdTag(); } + auto GetIdTag() const -> IdTagType { return values_.GetIdTag(); } private: // Given a symbolic type, get the corresponding unattached type. @@ -687,19 +688,20 @@ class InstStore { File* file_; llvm::SmallVector loc_ids_; - ValueStore values_; + ValueStore> values_; }; // Adapts BlockValueStore for instruction blocks. -class InstBlockStore : public BlockValueStore { +class InstBlockStore + : public BlockValueStore> { public: - using BaseType = BlockValueStore; + using BaseType = BlockValueStore>; explicit InstBlockStore(llvm::BumpPtrAllocator& allocator, CheckIRId check_ir_id = CheckIRId::None) // 4 reserved ids for the // `InstBlockId::{Empty,Exports,Imports,GlobalInit}` global ids. - : BaseType(allocator, IdTag(check_ir_id.index, 4)) { + : BaseType(allocator, check_ir_id, 4) { auto exports_id = AddPlaceholder(); CARBON_CHECK(exports_id == InstBlockId::Exports); auto imports_id = AddPlaceholder(); diff --git a/toolchain/sem_ir/inst_fingerprinter.cpp b/toolchain/sem_ir/inst_fingerprinter.cpp index 657b4b97c69c..b8b9631310a7 100644 --- a/toolchain/sem_ir/inst_fingerprinter.cpp +++ b/toolchain/sem_ir/inst_fingerprinter.cpp @@ -25,7 +25,8 @@ namespace Carbon::SemIR { namespace { struct Worklist { - using FingerprintStore = FixedSizeValueStore; + using FingerprintStore = + FixedSizeValueStore>; using FilesFingerprintStores = FixedSizeValueStore; @@ -66,8 +67,8 @@ struct Worklist { auto SetFingerprint(const File* file, InstId inst_id, uint64_t fingerprint) { auto& store = fingerprints->Get(file->check_ir_id()); if (store.size() == 0) { - store = FixedSizeValueStore::MakeWithExplicitSize( - file->insts().GetIdTag(), file->insts().size(), 0); + store = FingerprintStore::MakeWithExplicitSize( + file->insts().size(), file->insts().GetIdTag(), 0); } store.Set(inst_id, fingerprint ? fingerprint : 1); } diff --git a/toolchain/sem_ir/inst_fingerprinter.h b/toolchain/sem_ir/inst_fingerprinter.h index f0ef5ef568ab..f20214b55bc7 100644 --- a/toolchain/sem_ir/inst_fingerprinter.h +++ b/toolchain/sem_ir/inst_fingerprinter.h @@ -18,7 +18,8 @@ class InstFingerprinter { explicit InstFingerprinter(int total_ir_count) : fingerprints_(FilesFingerprintStores::MakeWithExplicitSizeFrom( total_ir_count, [] { - return FingerprintStore::MakeForOverwriteWithExplicitSize(0); + return FingerprintStore::MakeForOverwriteWithExplicitSize( + 0, CheckIRId::None); })) {} // Gets or computes a fingerprint for the given instruction. @@ -43,7 +44,8 @@ class InstFingerprinter { // the `GetOrCompute` overload for `InstBlockId`s, and may save some work if // the same canonical inst block is used by multiple instructions, for example // as a specific argument list. - using FingerprintStore = FixedSizeValueStore; + using FingerprintStore = + FixedSizeValueStore>; using FilesFingerprintStores = FixedSizeValueStore; FilesFingerprintStores fingerprints_; diff --git a/toolchain/sem_ir/interface.h b/toolchain/sem_ir/interface.h index a635cb19d896..06891e55cf9d 100644 --- a/toolchain/sem_ir/interface.h +++ b/toolchain/sem_ir/interface.h @@ -52,7 +52,7 @@ struct Interface : public EntityWithParamsBase, } }; -using InterfaceStore = ValueStore; +using InterfaceStore = ValueStore>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/name_scope.cpp b/toolchain/sem_ir/name_scope.cpp index 42eeb215f2fd..0dd8e17507aa 100644 --- a/toolchain/sem_ir/name_scope.cpp +++ b/toolchain/sem_ir/name_scope.cpp @@ -14,7 +14,7 @@ namespace Carbon::SemIR { NameScopeStore::NameScopeStore(const File* file) // 1 reserved untagged id because the Package NameScope is used across // Files. - : file_(file), values_(IdTag(file->check_ir_id().index, 1)) {} + : file_(file), values_(file->check_ir_id(), 1) {} auto NameScope::Print(llvm::raw_ostream& out) const -> void { out << "{inst: " << inst_id_ << ", parent_scope: " << parent_scope_id_ diff --git a/toolchain/sem_ir/name_scope.h b/toolchain/sem_ir/name_scope.h index 1d621916cf44..b814e25dedb9 100644 --- a/toolchain/sem_ir/name_scope.h +++ b/toolchain/sem_ir/name_scope.h @@ -366,7 +366,7 @@ class NameScopeStore { private: const File* file_; - ValueStore values_; + ValueStore> values_; }; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/named_constraint.h b/toolchain/sem_ir/named_constraint.h index 23f9e3f466b1..4639e7df8f81 100644 --- a/toolchain/sem_ir/named_constraint.h +++ b/toolchain/sem_ir/named_constraint.h @@ -49,7 +49,8 @@ struct NamedConstraint : public EntityWithParamsBase, } }; -using NamedConstraintStore = ValueStore; +using NamedConstraintStore = + ValueStore>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/require_impls.h b/toolchain/sem_ir/require_impls.h index de649f0f0457..4fd186ce6545 100644 --- a/toolchain/sem_ir/require_impls.h +++ b/toolchain/sem_ir/require_impls.h @@ -43,10 +43,11 @@ struct RequireImpls : Printable { } }; -using RequireImplsStore = ValueStore; +using RequireImplsStore = + ValueStore>; using RequireImplsBlockStore = - BlockValueStore; + BlockValueStore>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/specific_interface.h b/toolchain/sem_ir/specific_interface.h index 5fa5ee341fc0..ae10022e156b 100644 --- a/toolchain/sem_ir/specific_interface.h +++ b/toolchain/sem_ir/specific_interface.h @@ -27,7 +27,7 @@ inline constexpr SpecificInterface SpecificInterface::None = { .interface_id = InterfaceId::None, .specific_id = SpecificId::None}; using SpecificInterfaceStore = - CanonicalValueStore; + CanonicalValueStore>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/struct_type_field.h b/toolchain/sem_ir/struct_type_field.h index 709563cf5a6e..2ac1cca28f16 100644 --- a/toolchain/sem_ir/struct_type_field.h +++ b/toolchain/sem_ir/struct_type_field.h @@ -25,7 +25,7 @@ struct StructTypeField : Printable { }; using StructTypeFieldsStore = - BlockValueStore; + BlockValueStore>; // See common/hashing.h. Supports canonicalization of fields. inline auto CarbonHashValue(const StructTypeField& value, uint64_t seed) diff --git a/toolchain/sem_ir/vtable.h b/toolchain/sem_ir/vtable.h index 7011b18e13cf..96d99bb6f505 100644 --- a/toolchain/sem_ir/vtable.h +++ b/toolchain/sem_ir/vtable.h @@ -29,7 +29,7 @@ struct Vtable : public VtableFields, public Printable { } }; -using VtableStore = ValueStore; +using VtableStore = ValueStore>; } // namespace Carbon::SemIR