value_stores.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_SEM_IR_VALUE_STORES_H_
  5. #define CARBON_TOOLCHAIN_SEM_IR_VALUE_STORES_H_
  6. #include "llvm/ADT/DenseMap.h"
  7. #include "toolchain/base/value_store.h"
  8. #include "toolchain/base/yaml.h"
  9. #include "toolchain/sem_ir/inst.h"
  10. namespace Carbon::SemIR {
  11. // Provides a ValueStore wrapper for an API specific to instructions.
  12. class InstStore {
  13. public:
  14. // Adds an instruction to the instruction list, returning an ID to reference
  15. // the instruction. Note that this doesn't add the instruction to any
  16. // instruction block. Check::Context::AddInst or InstBlockStack::AddInst
  17. // should usually be used instead, to add the instruction to the current
  18. // block.
  19. auto AddInNoBlock(Inst inst) -> InstId { return values_.Add(inst); }
  20. // Returns the requested instruction.
  21. auto Get(InstId inst_id) const -> Inst { return values_.Get(inst_id); }
  22. // Returns the requested instruction, which is known to have the specified
  23. // type.
  24. template <typename InstT>
  25. auto GetAs(InstId inst_id) const -> InstT {
  26. return Get(inst_id).As<InstT>();
  27. }
  28. // Overwrites a given instruction with a new value.
  29. auto Set(InstId inst_id, Inst inst) -> void { values_.Get(inst_id) = inst; }
  30. // Reserves space.
  31. auto Reserve(size_t size) -> void { values_.Reserve(size); }
  32. auto array_ref() const -> llvm::ArrayRef<Inst> { return values_.array_ref(); }
  33. auto size() const -> int { return values_.size(); }
  34. private:
  35. ValueStore<InstId, Inst> values_;
  36. };
  37. // Provides storage for instructions representing global constants.
  38. class ConstantStore {
  39. public:
  40. // Add a constant instruction.
  41. auto Add(InstId inst_id) -> void { values_.push_back(inst_id); }
  42. auto array_ref() const -> llvm::ArrayRef<InstId> { return values_; }
  43. auto size() const -> int { return values_.size(); }
  44. private:
  45. llvm::SmallVector<InstId> values_;
  46. };
  47. // Provides a ValueStore-like interface for names.
  48. //
  49. // A name is either an identifier name or a special name such as `self` that
  50. // does not correspond to an identifier token. Identifier names are represented
  51. // as `NameId`s with the same non-negative index as the `IdentifierId` of the
  52. // identifier. Special names are represented as `NameId`s with a negative
  53. // index.
  54. //
  55. // `SemIR::NameId` values should be obtained by using `NameId::ForIdentifier`
  56. // or the named constants such as `NameId::SelfValue`.
  57. //
  58. // As we do not require any additional explicit storage for names, this is
  59. // currently a wrapper around an identifier store that has no state of its own.
  60. class NameStoreWrapper {
  61. public:
  62. explicit NameStoreWrapper(const StringStoreWrapper<IdentifierId>* identifiers)
  63. : identifiers_(identifiers) {}
  64. // Returns the requested name as a string, if it is an identifier name. This
  65. // returns std::nullopt for special names.
  66. auto GetAsStringIfIdentifier(NameId name_id) const
  67. -> std::optional<llvm::StringRef> {
  68. if (auto identifier_id = name_id.AsIdentifierId();
  69. identifier_id.is_valid()) {
  70. return identifiers_->Get(identifier_id);
  71. }
  72. return std::nullopt;
  73. }
  74. // Returns the requested name as a string for formatted output. This returns
  75. // `"r#name"` if `name` is a keyword.
  76. auto GetFormatted(NameId name_id) const -> llvm::StringRef;
  77. // Returns a best-effort name to use as the basis for SemIR and LLVM IR
  78. // names. This is always identifier-shaped, but may be ambiguous, for example
  79. // if there is both a `self` and an `r#self` in the same scope. Returns ""
  80. // for an invalid name.
  81. auto GetIRBaseName(NameId name_id) const -> llvm::StringRef;
  82. private:
  83. const StringStoreWrapper<IdentifierId>* identifiers_;
  84. };
  85. // Provides a ValueStore wrapper for an API specific to name scopes.
  86. class NameScopeStore {
  87. public:
  88. // Adds a name scope, returning an ID to reference it.
  89. auto Add() -> NameScopeId { return values_.AddDefaultValue(); }
  90. // Adds an entry to a name scope. Returns true on success, false on
  91. // duplicates.
  92. auto AddEntry(NameScopeId scope_id, NameId name_id, InstId target_id)
  93. -> bool {
  94. return values_.Get(scope_id).insert({name_id, target_id}).second;
  95. }
  96. // Returns the requested name scope.
  97. auto Get(NameScopeId scope_id) const
  98. -> const llvm::DenseMap<NameId, InstId>& {
  99. return values_.Get(scope_id);
  100. }
  101. private:
  102. ValueStore<NameScopeId, llvm::DenseMap<NameId, InstId>> values_;
  103. };
  104. // Provides a block-based ValueStore, which uses slab allocation of added
  105. // blocks. This allows references to values to outlast vector resizes that might
  106. // otherwise invalidate references.
  107. //
  108. // BlockValueStore is used as-is, but there are also children that expose the
  109. // protected members for type-specific functionality.
  110. template <typename IdT, typename ValueT>
  111. class BlockValueStore : public Yaml::Printable<BlockValueStore<IdT, ValueT>> {
  112. public:
  113. explicit BlockValueStore(llvm::BumpPtrAllocator& allocator)
  114. : allocator_(&allocator) {}
  115. // Adds a block with the given content, returning an ID to reference it.
  116. auto Add(llvm::ArrayRef<ValueT> content) -> IdT {
  117. return values_.Add(AllocateCopy(content));
  118. }
  119. // Returns the requested block.
  120. auto Get(IdT id) const -> llvm::ArrayRef<ValueT> { return values_.Get(id); }
  121. // Returns the requested block.
  122. auto Get(IdT id) -> llvm::MutableArrayRef<ValueT> { return values_.Get(id); }
  123. auto OutputYaml() const -> Yaml::OutputMapping {
  124. return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
  125. for (auto block_index : llvm::seq(values_.size())) {
  126. auto block_id = IdT(block_index);
  127. map.Add(PrintToString(block_id),
  128. Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
  129. auto block = Get(block_id);
  130. for (auto i : llvm::seq(block.size())) {
  131. map.Add(llvm::itostr(i), Yaml::OutputScalar(block[i]));
  132. }
  133. }));
  134. }
  135. });
  136. }
  137. auto size() const -> int { return values_.size(); }
  138. protected:
  139. // Reserves and returns a block ID. The contents of the block
  140. // should be specified by calling Set, or similar.
  141. auto AddDefaultValue() -> InstBlockId { return values_.AddDefaultValue(); }
  142. // Adds an uninitialized block of the given size.
  143. auto AddUninitialized(size_t size) -> InstBlockId {
  144. return values_.Add(AllocateUninitialized(size));
  145. }
  146. // Sets the contents of an empty block to the given content.
  147. auto Set(InstBlockId block_id, llvm::ArrayRef<InstId> content) -> void {
  148. CARBON_CHECK(Get(block_id).empty())
  149. << "inst block content set more than once";
  150. values_.Get(block_id) = AllocateCopy(content);
  151. }
  152. private:
  153. // Allocates an uninitialized array using our slab allocator.
  154. auto AllocateUninitialized(std::size_t size)
  155. -> llvm::MutableArrayRef<ValueT> {
  156. // We're not going to run a destructor, so ensure that's OK.
  157. static_assert(std::is_trivially_destructible_v<ValueT>);
  158. auto storage = static_cast<ValueT*>(
  159. allocator_->Allocate(size * sizeof(ValueT), alignof(ValueT)));
  160. return llvm::MutableArrayRef<ValueT>(storage, size);
  161. }
  162. // Allocates a copy of the given data using our slab allocator.
  163. auto AllocateCopy(llvm::ArrayRef<ValueT> data)
  164. -> llvm::MutableArrayRef<ValueT> {
  165. auto result = AllocateUninitialized(data.size());
  166. std::uninitialized_copy(data.begin(), data.end(), result.begin());
  167. return result;
  168. }
  169. llvm::BumpPtrAllocator* allocator_;
  170. ValueStore<IdT, llvm::MutableArrayRef<ValueT>> values_;
  171. };
  172. // Adapts BlockValueStore for instruction blocks.
  173. class InstBlockStore : public BlockValueStore<InstBlockId, InstId> {
  174. public:
  175. using BaseType = BlockValueStore<InstBlockId, InstId>;
  176. using BaseType::AddDefaultValue;
  177. using BaseType::AddUninitialized;
  178. using BaseType::BaseType;
  179. auto Set(InstBlockId block_id, llvm::ArrayRef<InstId> content) -> void {
  180. CARBON_CHECK(block_id != InstBlockId::Unreachable);
  181. BlockValueStore<InstBlockId, InstId>::Set(block_id, content);
  182. }
  183. };
  184. } // namespace Carbon::SemIR
  185. // Support use of NameId as DenseMap/DenseSet keys.
  186. template <>
  187. struct llvm::DenseMapInfo<Carbon::SemIR::NameId>
  188. : public Carbon::IndexMapInfo<Carbon::SemIR::NameId> {};
  189. #endif // CARBON_TOOLCHAIN_SEM_IR_VALUE_STORES_H_