constant.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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_CONSTANT_H_
  5. #define CARBON_TOOLCHAIN_SEM_IR_CONSTANT_H_
  6. #include "common/map.h"
  7. #include "toolchain/base/yaml.h"
  8. #include "toolchain/sem_ir/ids.h"
  9. #include "toolchain/sem_ir/inst.h"
  10. namespace Carbon::SemIR {
  11. // The kinds of symbolic bindings that a constant might depend on. These are
  12. // ordered from least to most dependent, so that the dependence of an operation
  13. // can typically be computed by taking the maximum of the dependences of its
  14. // operands.
  15. enum class ConstantDependence : uint8_t {
  16. // This constant's value is known concretely, and does not depend on any
  17. // symbolic binding.
  18. None,
  19. // The only symbolic binding that this constant depends on is `.Self`.
  20. PeriodSelf,
  21. // The only symbolic bindings that this constant depends on are checked
  22. // generic bindings.
  23. Checked,
  24. // This symbolic binding depends on a template-dependent value, such as a
  25. // template parameter.
  26. Template,
  27. };
  28. // Information about a symbolic constant value. These are indexed by
  29. // `ConstantId`s for which `is_symbolic` is true.
  30. //
  31. // A constant value is defined by the canonical ID of a fully-evaluated inst,
  32. // called a "constant inst", which may depend on the canonical IDs of other
  33. // constant insts. "Canonical" here means that it is chosen such that equal
  34. // constants will have equal canonical IDs. This is typically achieved by
  35. // deduplication in `ConstantStore`, but certain kinds of constant insts are
  36. // canonicalized in other ways.
  37. //
  38. // That constant inst ID fully defines the constant value in itself, but for
  39. // symbolic constant values we sometimes need efficient access to metadata about
  40. // the mapping between the constant and corresponding constants in specifics of
  41. // its enclosing generic. As a result, the ID of a concrete constant directly
  42. // encodes the ID of the constant inst, but the ID of a symbolic constant is an
  43. // index into a table of `SymbolicConstant` entries containing that metadata, as
  44. // well as the constant inst ID.
  45. //
  46. // The price of this optimization is that the constant value's ID depends on the
  47. // enclosing generic, which isn't semantically relevant unless we're
  48. // specifically operating on the generic -> specific mapping. As a result, every
  49. // symbolic constant is represented by two `SymbolicConstant`s, with separate
  50. // IDs: one with that additional metadata, and one without it. The form with
  51. // additional metadata is called an "attached constant", and the form without it
  52. // is an "unattached constant". Note that constants in separate generics may be
  53. // represented by the same unattached constant. In general, only one of these
  54. // IDs is correct to use in a given situation; `ConstantValueStore` can be used
  55. // to map between them if necessary.
  56. //
  57. // Equivalently, you can think of an unattached constant as being implicitly
  58. // parameterized by the `bind_symbolic_name` constant insts that it depends on,
  59. // whereas an attached constant explicitly binds them to parameters of the
  60. // enclosing generic. It's the difference between "`Vector(T)` where `T` is some
  61. // value of type `type`" and "`Vector(T)` where `T` is the `T:! type` parameter
  62. // of this particular enclosing generic".
  63. //
  64. // TODO: consider instead keeping this metadata in a separate hash map keyed by
  65. // a `GenericId`/`ConstantId` pair, so that each constant has a single
  66. // `ConstantId`, rather than separate attached and unattached IDs.
  67. struct SymbolicConstant : Printable<SymbolicConstant> {
  68. // The canonical ID of the inst that defines this constant.
  69. InstId inst_id;
  70. // The generic that this constant is attached to, or `None` if this is an
  71. // unattached constant.
  72. GenericId generic_id;
  73. // The index of this constant within the generic's eval block, if this is an
  74. // attached constant. For a given specific of that generic, this is also the
  75. // index of this constant's value in the value block of that specific. If
  76. // this constant is unattached, `index` will be `None`.
  77. GenericInstIndex index;
  78. // The kind of dependence this symbolic constant exhibits. Should never be
  79. // `None`.
  80. ConstantDependence dependence;
  81. auto Print(llvm::raw_ostream& out) const -> void {
  82. out << "{inst: " << inst_id << ", generic: " << generic_id
  83. << ", index: " << index << ", kind: ";
  84. switch (dependence) {
  85. case ConstantDependence::None:
  86. out << "<error: concrete>";
  87. break;
  88. case ConstantDependence::PeriodSelf:
  89. out << "self";
  90. break;
  91. case ConstantDependence::Checked:
  92. out << "checked";
  93. break;
  94. case ConstantDependence::Template:
  95. out << "template";
  96. break;
  97. }
  98. out << "}";
  99. }
  100. };
  101. // Provides a ValueStore wrapper for tracking the constant values of
  102. // instructions.
  103. class ConstantValueStore {
  104. struct UnusableType {};
  105. public:
  106. inline static const auto Unusable = UnusableType();
  107. // Constructs an unusable ConstantValueStore, only good as a placeholder (eg:
  108. // in C++ interop, where there's no foreign SemIR to reference)
  109. explicit ConstantValueStore(UnusableType /* tag */)
  110. : default_(ConstantId::None),
  111. values_(CheckIRId::None),
  112. symbolic_constants_(CheckIRId::None),
  113. insts_(nullptr) {}
  114. explicit ConstantValueStore(ConstantId default_value, const InstStore* insts)
  115. : default_(default_value),
  116. values_(insts->GetIdTag()),
  117. symbolic_constants_(insts->GetIdTag().GetContainerTag()),
  118. insts_(insts) {}
  119. // Returns the constant value of the requested instruction, which is default_
  120. // if unallocated. Always returns an unattached constant.
  121. auto Get(InstId inst_id) const -> ConstantId {
  122. auto const_id = GetAttached(inst_id);
  123. return const_id.has_value() ? GetUnattachedConstant(const_id) : const_id;
  124. }
  125. // Returns the constant value of the requested instruction, which is default_
  126. // if unallocated. This may be an attached constant.
  127. auto GetAttached(InstId inst_id) const -> ConstantId {
  128. CARBON_CHECK(insts_,
  129. "Used ConstantValueStores must have an associated InstStore.");
  130. return values_.GetWithDefault(inst_id, default_);
  131. }
  132. // Sets the constant value of the given instruction, or sets that it is known
  133. // to not be a constant.
  134. auto Set(InstId inst_id, ConstantId const_id) -> void {
  135. CARBON_CHECK(insts_,
  136. "Used ConstantValueStores must have an associated InstStore.");
  137. auto index = insts_->GetRawIndex(inst_id);
  138. if (static_cast<size_t>(index) >= values_.size()) {
  139. values_.Resize(index + 1, default_);
  140. }
  141. values_.Get(inst_id) = const_id;
  142. }
  143. // Gets the ID of the underlying constant inst for the given constant. Returns
  144. // `None` if the constant ID is non-constant. Requires `const_id.has_value()`.
  145. auto GetInstId(ConstantId const_id) const -> InstId {
  146. if (const_id.is_concrete()) {
  147. return const_id.concrete_inst_id();
  148. }
  149. if (const_id.is_symbolic()) {
  150. return GetSymbolicConstant(const_id).inst_id;
  151. }
  152. return InstId::None;
  153. }
  154. // Gets the ID of the underlying constant inst for the given constant. Returns
  155. // `None` if the constant ID is non-constant or `None`.
  156. auto GetInstIdIfValid(ConstantId const_id) const -> InstId {
  157. return const_id.has_value() ? GetInstId(const_id) : InstId::None;
  158. }
  159. // Given an instruction, returns the unique constant instruction that is
  160. // equivalent to it. Returns `None` for a non-constant instruction.
  161. auto GetConstantInstId(InstId inst_id) const -> InstId {
  162. return GetInstId(GetAttached(inst_id));
  163. }
  164. // Given a type instruction, returns the unique constant instruction that is
  165. // equivalent to it. Returns `None` for a non-constant instruction.
  166. auto GetConstantTypeInstId(TypeInstId inst_id) const -> TypeInstId {
  167. // If the source instruction has type `type`, its constant value will too,
  168. // since the constant value of `type` is itself.
  169. return TypeInstId::UnsafeMake(GetInstId(GetAttached(inst_id)));
  170. }
  171. // Given a symbolic constant, returns the unattached form of that constant.
  172. // For any other constant ID, returns the ID unchanged.
  173. auto GetUnattachedConstant(ConstantId const_id) const -> ConstantId {
  174. if (const_id.is_symbolic()) {
  175. return values_.Get(GetSymbolicConstant(const_id).inst_id);
  176. }
  177. return const_id;
  178. }
  179. auto AddSymbolicConstant(SymbolicConstant constant) -> ConstantId {
  180. return ConstantId::ForSymbolicConstantId(symbolic_constants_.Add(constant));
  181. }
  182. auto GetSymbolicConstant(ConstantId const_id) -> SymbolicConstant& {
  183. return symbolic_constants_.Get(const_id.symbolic_id());
  184. }
  185. auto GetSymbolicConstant(ConstantId const_id) const
  186. -> const SymbolicConstant& {
  187. return symbolic_constants_.Get(const_id.symbolic_id());
  188. }
  189. // Get the dependence of the given constant.
  190. auto GetDependence(ConstantId const_id) const -> ConstantDependence {
  191. return const_id.is_symbolic() ? GetSymbolicConstant(const_id).dependence
  192. : ConstantDependence::None;
  193. }
  194. // Returns true for symbolic constants other than those that are only symbolic
  195. // because they depend on `.Self`.
  196. auto DependsOnGenericParameter(ConstantId const_id) const -> bool {
  197. return GetDependence(const_id) > ConstantDependence::PeriodSelf;
  198. }
  199. // Collects memory usage of members.
  200. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  201. -> void {
  202. mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
  203. mem_usage.Collect(MemUsage::ConcatLabel(label, "symbolic_constants_"),
  204. symbolic_constants_);
  205. }
  206. // Makes an iterable range over pairs of the instruction id and constant value
  207. // id for each value in the store.
  208. auto enumerate() const -> auto { return values_.enumerate(); }
  209. // Outputs assigned constant values, and all symbolic constants.
  210. auto OutputYaml(bool include_singletons) const -> Yaml::OutputMapping {
  211. return Yaml::OutputMapping([&, include_singletons](
  212. Yaml::OutputMapping::Map map) {
  213. map.Add("values", Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
  214. for (auto [id, value] : values_.enumerate()) {
  215. if (!include_singletons && IsSingletonInstId(id)) {
  216. continue;
  217. }
  218. if (!value.has_value() || value.is_constant()) {
  219. map.Add(PrintToString(id), Yaml::OutputScalar(value));
  220. }
  221. }
  222. }));
  223. map.Add("symbolic_constants", symbolic_constants_.OutputYaml());
  224. });
  225. }
  226. // The tag used in ConstantIds for concrete constants.
  227. using ConcreteIdTagType = IdTag<SemIR::ConstantId, Tag<SemIR::CheckIRId>>;
  228. auto GetConcreteIdTag() const -> ConcreteIdTagType {
  229. return values_.GetIdTag().ToEquivalentIdType<SemIR::ConstantId>();
  230. }
  231. // The tag used for TypeId, which are concrete constants internally.
  232. using TypeIdTagType = IdTag<SemIR::TypeId, Tag<SemIR::CheckIRId>>;
  233. auto GetTypeIdTag() const -> TypeIdTagType {
  234. return values_.GetIdTag().ToEquivalentIdType<SemIR::TypeId>();
  235. }
  236. // The tag used in ConstantIds for symbolic constants.
  237. using SymbolicIdTagType =
  238. IdTag<ConstantId::SymbolicId, Tag<SemIR::CheckIRId>>;
  239. auto GetSymbolicIdTag() const -> SymbolicIdTagType {
  240. return symbolic_constants_.GetIdTag();
  241. }
  242. // The size of the value store for concrete constant values.
  243. auto ConcreteStoreSize() const -> size_t { return values_.size(); }
  244. private:
  245. const ConstantId default_;
  246. // A mapping from `InstId::index` to the corresponding constant value. This is
  247. // expected to be sparse, and may be smaller than the list of instructions if
  248. // there are trailing non-constant instructions.
  249. //
  250. // Set inline size to 0 because these will typically be too large for the
  251. // stack, while this does make File smaller.
  252. ValueStore<InstId, ConstantId, Tag<CheckIRId>> values_;
  253. // A mapping from a symbolic constant ID index to information about the
  254. // symbolic constant. For a concrete constant, the only information that we
  255. // track is the instruction ID, which is stored directly within the
  256. // `ConstantId`. For a symbolic constant, we also track information about
  257. // where the constant was used, which is stored here.
  258. ValueStore<ConstantId::SymbolicId, SymbolicConstant, Tag<CheckIRId>>
  259. symbolic_constants_;
  260. const InstStore* insts_;
  261. };
  262. // Given a constant ID, returns an instruction that has that constant value.
  263. // For an unattached constant, the returned instruction is the instruction that
  264. // defines the constant; for an attached constant, this is the instruction in
  265. // the eval block that computes the constant value in each specific.
  266. //
  267. // Returns InstId::None if the ConstantId is None or NotConstant.
  268. auto GetInstWithConstantValue(const File& file, ConstantId const_id) -> InstId;
  269. // Provides storage for instructions representing deduplicated global constants.
  270. class ConstantStore {
  271. public:
  272. explicit ConstantStore(File* sem_ir) : sem_ir_(sem_ir) {}
  273. // Adds a new constant instruction, or gets the existing constant with this
  274. // value. Returns the ID of the constant.
  275. //
  276. // This updates `sem_ir->insts()` and `sem_ir->constant_values()` if the
  277. // constant is new.
  278. auto GetOrAdd(Inst inst, ConstantDependence dependence) -> ConstantId;
  279. // Collects memory usage of members.
  280. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  281. -> void {
  282. mem_usage.Collect(MemUsage::ConcatLabel(label, "map_"), map_);
  283. mem_usage.Collect(MemUsage::ConcatLabel(label, "constants_"), constants_);
  284. }
  285. // Returns a copy of the constant IDs as a vector, in an arbitrary but
  286. // stable order. This should not be used anywhere performance-sensitive.
  287. auto array_ref() const -> llvm::ArrayRef<InstId> { return constants_; }
  288. auto size() const -> int { return constants_.size(); }
  289. private:
  290. File* const sem_ir_;
  291. Map<Inst, ConstantId> map_;
  292. llvm::SmallVector<InstId, 0> constants_;
  293. };
  294. } // namespace Carbon::SemIR
  295. #endif // CARBON_TOOLCHAIN_SEM_IR_CONSTANT_H_