constant.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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.
  71. auto Get(InstId inst_id) const -> ConstantId {
  72. CARBON_DCHECK(inst_id.index >= 0);
  73. return static_cast<size_t>(inst_id.index) >= values_.size()
  74. ? default_
  75. : values_[inst_id.index];
  76. }
  77. // Sets the constant value of the given instruction, or sets that it is known
  78. // to not be a constant.
  79. auto Set(InstId inst_id, ConstantId const_id) -> void {
  80. CARBON_DCHECK(inst_id.index >= 0);
  81. if (static_cast<size_t>(inst_id.index) >= values_.size()) {
  82. values_.resize(inst_id.index + 1, default_);
  83. }
  84. values_[inst_id.index] = const_id;
  85. }
  86. // Gets the instruction ID that defines the value of the given constant.
  87. // Returns `None` if the constant ID is non-constant. Requires
  88. // `const_id.has_value()`.
  89. auto GetInstId(ConstantId const_id) const -> InstId {
  90. if (const_id.is_concrete()) {
  91. return const_id.concrete_inst_id();
  92. }
  93. if (const_id.is_symbolic()) {
  94. return GetSymbolicConstant(const_id).inst_id;
  95. }
  96. return InstId::None;
  97. }
  98. // Gets the instruction ID that defines the value of the given constant.
  99. // Returns `None` if the constant ID is non-constant or `None`.
  100. auto GetInstIdIfValid(ConstantId const_id) const -> InstId {
  101. return const_id.has_value() ? GetInstId(const_id) : InstId::None;
  102. }
  103. // Given an instruction, returns the unique constant instruction that is
  104. // equivalent to it. Returns `None` for a non-constant instruction.
  105. auto GetConstantInstId(InstId inst_id) const -> InstId {
  106. return GetInstId(Get(inst_id));
  107. }
  108. auto AddSymbolicConstant(SymbolicConstant constant) -> ConstantId {
  109. symbolic_constants_.push_back(constant);
  110. return ConstantId::ForSymbolicConstantIndex(symbolic_constants_.size() - 1);
  111. }
  112. auto GetSymbolicConstant(ConstantId const_id) -> SymbolicConstant& {
  113. return symbolic_constants_[const_id.symbolic_index()];
  114. }
  115. auto GetSymbolicConstant(ConstantId const_id) const
  116. -> const SymbolicConstant& {
  117. return symbolic_constants_[const_id.symbolic_index()];
  118. }
  119. // Get the dependence of the given constant.
  120. auto GetDependence(ConstantId const_id) const -> ConstantDependence {
  121. return const_id.is_symbolic() ? GetSymbolicConstant(const_id).dependence
  122. : ConstantDependence::None;
  123. }
  124. // Returns true for symbolic constants other than those that are only symbolic
  125. // because they depend on `.Self`.
  126. auto DependsOnGenericParameter(ConstantId const_id) const -> bool {
  127. return GetDependence(const_id) > ConstantDependence::PeriodSelf;
  128. }
  129. // Collects memory usage of members.
  130. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  131. -> void {
  132. mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
  133. mem_usage.Collect(MemUsage::ConcatLabel(label, "symbolic_constants_"),
  134. symbolic_constants_);
  135. }
  136. // Makes an iterable range over pairs of the instruction id and constant value
  137. // id for each value in the store.
  138. auto enumerate() const -> auto {
  139. auto index_to_id = [](auto pair) -> std::pair<InstId, ConstantId> {
  140. auto [index, value] = pair;
  141. return std::pair<InstId, ConstantId>(InstId(index), value);
  142. };
  143. return llvm::map_range(llvm::enumerate(values_), index_to_id);
  144. }
  145. // Returns the symbolic constants mapping as an ArrayRef whose keys are
  146. // symbolic indexes of constants.
  147. auto symbolic_constants() const -> llvm::ArrayRef<SymbolicConstant> {
  148. return symbolic_constants_;
  149. }
  150. private:
  151. const ConstantId default_;
  152. // A mapping from `InstId::index` to the corresponding constant value. This is
  153. // expected to be sparse, and may be smaller than the list of instructions if
  154. // there are trailing non-constant instructions.
  155. //
  156. // Set inline size to 0 because these will typically be too large for the
  157. // stack, while this does make File smaller.
  158. llvm::SmallVector<ConstantId, 0> values_;
  159. // A mapping from a symbolic constant ID index to information about the
  160. // symbolic constant. For a concrete constant, the only information that we
  161. // track is the instruction ID, which is stored directly within the
  162. // `ConstantId`. For a symbolic constant, we also track information about
  163. // where the constant was used, which is stored here.
  164. llvm::SmallVector<SymbolicConstant, 0> symbolic_constants_;
  165. };
  166. // Provides storage for instructions representing deduplicated global constants.
  167. class ConstantStore {
  168. public:
  169. explicit ConstantStore(File* sem_ir) : sem_ir_(sem_ir) {}
  170. // Adds a new constant instruction, or gets the existing constant with this
  171. // value. Returns the ID of the constant.
  172. //
  173. // This updates `sem_ir->insts()` and `sem_ir->constant_values()` if the
  174. // constant is new.
  175. auto GetOrAdd(Inst inst, ConstantDependence dependence) -> ConstantId;
  176. // Collects memory usage of members.
  177. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  178. -> void {
  179. mem_usage.Collect(MemUsage::ConcatLabel(label, "map_"), map_);
  180. mem_usage.Collect(MemUsage::ConcatLabel(label, "constants_"), constants_);
  181. }
  182. // Returns a copy of the constant IDs as a vector, in an arbitrary but
  183. // stable order. This should not be used anywhere performance-sensitive.
  184. auto array_ref() const -> llvm::ArrayRef<InstId> { return constants_; }
  185. auto size() const -> int { return constants_.size(); }
  186. private:
  187. File* const sem_ir_;
  188. Map<Inst, ConstantId> map_;
  189. llvm::SmallVector<InstId, 0> constants_;
  190. };
  191. } // namespace Carbon::SemIR
  192. #endif // CARBON_TOOLCHAIN_SEM_IR_CONSTANT_H_