constant.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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. struct SymbolicConstant : Printable<SymbolicConstant> {
  31. // The constant instruction that defines the value of this symbolic constant.
  32. InstId inst_id;
  33. // The enclosing generic. If this is `None`, then this is an abstract
  34. // symbolic constant, such as a constant instruction in the constants block,
  35. // rather than one associated with a particular generic.
  36. GenericId generic_id;
  37. // The index of this symbolic constant within the generic's list of symbolic
  38. // constants, or `None` if `generic_id` is `None`.
  39. GenericInstIndex index;
  40. // The kind of dependence this symbolic constant exhibits. Should never be
  41. // `None`.
  42. ConstantDependence dependence;
  43. auto Print(llvm::raw_ostream& out) const -> void {
  44. out << "{inst: " << inst_id << ", generic: " << generic_id
  45. << ", index: " << index << ", kind: ";
  46. switch (dependence) {
  47. case ConstantDependence::None:
  48. out << "<error: concrete>";
  49. break;
  50. case ConstantDependence::PeriodSelf:
  51. out << "self";
  52. break;
  53. case ConstantDependence::Checked:
  54. out << "checked";
  55. break;
  56. case ConstantDependence::Template:
  57. out << "template";
  58. break;
  59. }
  60. out << "}";
  61. }
  62. };
  63. // Provides a ValueStore wrapper for tracking the constant values of
  64. // instructions.
  65. class ConstantValueStore {
  66. public:
  67. explicit ConstantValueStore(ConstantId default_value)
  68. : default_(default_value) {}
  69. // Returns the constant value of the requested instruction, which is default_
  70. // if unallocated. Always returns an unattached constant.
  71. auto Get(InstId inst_id) const -> ConstantId {
  72. auto const_id = GetAttached(inst_id);
  73. return const_id.has_value() ? GetUnattachedConstant(const_id) : const_id;
  74. }
  75. // Returns the constant value of the requested instruction, which is default_
  76. // if unallocated. This may be an attached constant.
  77. auto GetAttached(InstId inst_id) const -> ConstantId {
  78. CARBON_DCHECK(inst_id.index >= 0);
  79. return static_cast<size_t>(inst_id.index) >= values_.size()
  80. ? default_
  81. : values_[inst_id.index];
  82. }
  83. // Sets the constant value of the given instruction, or sets that it is known
  84. // to not be a constant.
  85. auto Set(InstId inst_id, ConstantId const_id) -> void {
  86. CARBON_DCHECK(inst_id.index >= 0);
  87. if (static_cast<size_t>(inst_id.index) >= values_.size()) {
  88. values_.resize(inst_id.index + 1, default_);
  89. }
  90. values_[inst_id.index] = const_id;
  91. }
  92. // Gets the instruction ID that defines the value of the given constant.
  93. // Returns `None` if the constant ID is non-constant. Requires
  94. // `const_id.has_value()`.
  95. auto GetInstId(ConstantId const_id) const -> InstId {
  96. if (const_id.is_concrete()) {
  97. return const_id.concrete_inst_id();
  98. }
  99. if (const_id.is_symbolic()) {
  100. return GetSymbolicConstant(const_id).inst_id;
  101. }
  102. return InstId::None;
  103. }
  104. // Gets the instruction ID that defines the value of the given constant.
  105. // Returns `None` if the constant ID is non-constant or `None`.
  106. auto GetInstIdIfValid(ConstantId const_id) const -> InstId {
  107. return const_id.has_value() ? GetInstId(const_id) : InstId::None;
  108. }
  109. // Given an instruction, returns the unique constant instruction that is
  110. // equivalent to it. Returns `None` for a non-constant instruction.
  111. auto GetConstantInstId(InstId inst_id) const -> InstId {
  112. return GetInstId(GetAttached(inst_id));
  113. }
  114. // Given a symbolic constant, returns the unattached form of that constant.
  115. // For any other constant ID, returns the ID unchanged.
  116. auto GetUnattachedConstant(ConstantId const_id) const -> ConstantId {
  117. if (const_id.is_symbolic()) {
  118. return GetAttached(GetSymbolicConstant(const_id).inst_id);
  119. }
  120. return const_id;
  121. }
  122. auto AddSymbolicConstant(SymbolicConstant constant) -> ConstantId {
  123. symbolic_constants_.push_back(constant);
  124. return ConstantId::ForSymbolicConstantIndex(symbolic_constants_.size() - 1);
  125. }
  126. auto GetSymbolicConstant(ConstantId const_id) -> SymbolicConstant& {
  127. return symbolic_constants_[const_id.symbolic_index()];
  128. }
  129. auto GetSymbolicConstant(ConstantId const_id) const
  130. -> const SymbolicConstant& {
  131. return symbolic_constants_[const_id.symbolic_index()];
  132. }
  133. // Get the dependence of the given constant.
  134. auto GetDependence(ConstantId const_id) const -> ConstantDependence {
  135. return const_id.is_symbolic() ? GetSymbolicConstant(const_id).dependence
  136. : ConstantDependence::None;
  137. }
  138. // Returns true for symbolic constants other than those that are only symbolic
  139. // because they depend on `.Self`.
  140. auto DependsOnGenericParameter(ConstantId const_id) const -> bool {
  141. return GetDependence(const_id) > ConstantDependence::PeriodSelf;
  142. }
  143. // Collects memory usage of members.
  144. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  145. -> void {
  146. mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
  147. mem_usage.Collect(MemUsage::ConcatLabel(label, "symbolic_constants_"),
  148. symbolic_constants_);
  149. }
  150. // Makes an iterable range over pairs of the instruction id and constant value
  151. // id for each value in the store.
  152. auto enumerate() const -> auto {
  153. auto index_to_id = [](auto pair) -> std::pair<InstId, ConstantId> {
  154. auto [index, value] = pair;
  155. return std::pair<InstId, ConstantId>(InstId(index), value);
  156. };
  157. return llvm::map_range(llvm::enumerate(values_), index_to_id);
  158. }
  159. // Returns the symbolic constants mapping as an ArrayRef whose keys are
  160. // symbolic indexes of constants.
  161. auto symbolic_constants() const -> llvm::ArrayRef<SymbolicConstant> {
  162. return symbolic_constants_;
  163. }
  164. private:
  165. const ConstantId default_;
  166. // A mapping from `InstId::index` to the corresponding constant value. This is
  167. // expected to be sparse, and may be smaller than the list of instructions if
  168. // there are trailing non-constant instructions.
  169. //
  170. // Set inline size to 0 because these will typically be too large for the
  171. // stack, while this does make File smaller.
  172. llvm::SmallVector<ConstantId, 0> values_;
  173. // A mapping from a symbolic constant ID index to information about the
  174. // symbolic constant. For a concrete constant, the only information that we
  175. // track is the instruction ID, which is stored directly within the
  176. // `ConstantId`. For a symbolic constant, we also track information about
  177. // where the constant was used, which is stored here.
  178. llvm::SmallVector<SymbolicConstant, 0> symbolic_constants_;
  179. };
  180. // Given a constant ID, returns an instruction that has that constant value.
  181. // For an unattached constant, the returned instruction is the instruction that
  182. // defines the constant; for an attached constant, this is the instruction in
  183. // the eval block that computes the constant value in each specific.
  184. //
  185. // Returns InstId::None if the ConstantId is None or NotConstant.
  186. auto GetInstWithConstantValue(const SemIR::File& file,
  187. SemIR::ConstantId const_id) -> SemIR::InstId;
  188. // Provides storage for instructions representing deduplicated global constants.
  189. class ConstantStore {
  190. public:
  191. explicit ConstantStore(File* sem_ir) : sem_ir_(sem_ir) {}
  192. // Adds a new constant instruction, or gets the existing constant with this
  193. // value. Returns the ID of the constant.
  194. //
  195. // This updates `sem_ir->insts()` and `sem_ir->constant_values()` if the
  196. // constant is new.
  197. auto GetOrAdd(Inst inst, ConstantDependence dependence) -> ConstantId;
  198. // Collects memory usage of members.
  199. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  200. -> void {
  201. mem_usage.Collect(MemUsage::ConcatLabel(label, "map_"), map_);
  202. mem_usage.Collect(MemUsage::ConcatLabel(label, "constants_"), constants_);
  203. }
  204. // Returns a copy of the constant IDs as a vector, in an arbitrary but
  205. // stable order. This should not be used anywhere performance-sensitive.
  206. auto array_ref() const -> llvm::ArrayRef<InstId> { return constants_; }
  207. auto size() const -> int { return constants_.size(); }
  208. private:
  209. File* const sem_ir_;
  210. Map<Inst, ConstantId> map_;
  211. llvm::SmallVector<InstId, 0> constants_;
  212. };
  213. } // namespace Carbon::SemIR
  214. #endif // CARBON_TOOLCHAIN_SEM_IR_CONSTANT_H_