constant.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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. // Information about a symbolic constant value. These are indexed by
  12. // `ConstantId`s for which `is_symbolic` is true.
  13. struct SymbolicConstant : Printable<SymbolicConstant> {
  14. // The constant instruction that defines the value of this symbolic constant.
  15. InstId inst_id;
  16. // The enclosing generic. If this is `None`, then this is an abstract
  17. // symbolic constant, such as a constant instruction in the constants block,
  18. // rather than one associated with a particular generic.
  19. GenericId generic_id;
  20. // The index of this symbolic constant within the generic's list of symbolic
  21. // constants, or `None` if `generic_id` is `None`.
  22. GenericInstIndex index;
  23. // True if this is constant is symbolic just because it uses `.Self`.
  24. bool period_self_only;
  25. auto Print(llvm::raw_ostream& out) const -> void {
  26. out << "{inst: " << inst_id << ", generic: " << generic_id
  27. << ", index: " << index
  28. << ", .Self: " << (period_self_only ? "true" : "false") << "}";
  29. }
  30. };
  31. // Provides a ValueStore wrapper for tracking the constant values of
  32. // instructions.
  33. class ConstantValueStore {
  34. public:
  35. explicit ConstantValueStore(ConstantId default_value)
  36. : default_(default_value) {}
  37. // Returns the constant value of the requested instruction, which is default_
  38. // if unallocated.
  39. auto Get(InstId inst_id) const -> ConstantId {
  40. CARBON_DCHECK(inst_id.index >= 0);
  41. return static_cast<size_t>(inst_id.index) >= values_.size()
  42. ? default_
  43. : values_[inst_id.index];
  44. }
  45. // Sets the constant value of the given instruction, or sets that it is known
  46. // to not be a constant.
  47. auto Set(InstId inst_id, ConstantId const_id) -> void {
  48. CARBON_DCHECK(inst_id.index >= 0);
  49. if (static_cast<size_t>(inst_id.index) >= values_.size()) {
  50. values_.resize(inst_id.index + 1, default_);
  51. }
  52. values_[inst_id.index] = const_id;
  53. }
  54. // Gets the instruction ID that defines the value of the given constant.
  55. // Returns `None` if the constant ID is non-constant. Requires
  56. // `const_id.has_value()`.
  57. auto GetInstId(ConstantId const_id) const -> InstId {
  58. if (const_id.is_template()) {
  59. return const_id.template_inst_id();
  60. }
  61. if (const_id.is_symbolic()) {
  62. return GetSymbolicConstant(const_id).inst_id;
  63. }
  64. return InstId::None;
  65. }
  66. // Gets the instruction ID that defines the value of the given constant.
  67. // Returns `None` if the constant ID is non-constant or `None`.
  68. auto GetInstIdIfValid(ConstantId const_id) const -> InstId {
  69. return const_id.has_value() ? GetInstId(const_id) : InstId::None;
  70. }
  71. // Given an instruction, returns the unique constant instruction that is
  72. // equivalent to it. Returns `None` for a non-constant instruction.
  73. auto GetConstantInstId(InstId inst_id) const -> InstId {
  74. return GetInstId(Get(inst_id));
  75. }
  76. // Returns whether two constant IDs represent the same constant value. This
  77. // includes the case where they might be in different generics and thus might
  78. // have different ConstantIds, but are still symbolically equal.
  79. auto AreEqualAcrossDeclarations(ConstantId a, ConstantId b) const -> bool {
  80. return GetInstId(a) == GetInstId(b);
  81. }
  82. auto AddSymbolicConstant(SymbolicConstant constant) -> ConstantId {
  83. symbolic_constants_.push_back(constant);
  84. return ConstantId::ForSymbolicConstantIndex(symbolic_constants_.size() - 1);
  85. }
  86. auto GetSymbolicConstant(ConstantId const_id) -> SymbolicConstant& {
  87. return symbolic_constants_[const_id.symbolic_index()];
  88. }
  89. auto GetSymbolicConstant(ConstantId const_id) const
  90. -> const SymbolicConstant& {
  91. return symbolic_constants_[const_id.symbolic_index()];
  92. }
  93. // Returns true for symbolic constants other than those that are only symbolic
  94. // because they depend on `.Self`.
  95. auto DependsOnGenericParameter(ConstantId const_id) const -> bool {
  96. return const_id.is_symbolic() &&
  97. !GetSymbolicConstant(const_id).period_self_only;
  98. }
  99. // Collects memory usage of members.
  100. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  101. -> void {
  102. mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
  103. mem_usage.Collect(MemUsage::ConcatLabel(label, "symbolic_constants_"),
  104. symbolic_constants_);
  105. }
  106. // Returns the constant values mapping as an ArrayRef whose keys are
  107. // instruction indexes. Some of the elements in this mapping may be `None` or
  108. // NotConstant.
  109. auto array_ref() const -> llvm::ArrayRef<ConstantId> { return values_; }
  110. // Returns the symbolic constants mapping as an ArrayRef whose keys are
  111. // symbolic indexes of constants.
  112. auto symbolic_constants() const -> llvm::ArrayRef<SymbolicConstant> {
  113. return symbolic_constants_;
  114. }
  115. private:
  116. const ConstantId default_;
  117. // A mapping from `InstId::index` to the corresponding constant value. This is
  118. // expected to be sparse, and may be smaller than the list of instructions if
  119. // there are trailing non-constant instructions.
  120. //
  121. // Set inline size to 0 because these will typically be too large for the
  122. // stack, while this does make File smaller.
  123. llvm::SmallVector<ConstantId, 0> values_;
  124. // A mapping from a symbolic constant ID index to information about the
  125. // symbolic constant. For a template constant, the only information that we
  126. // track is the instruction ID, which is stored directly within the
  127. // `ConstantId`. For a symbolic constant, we also track information about
  128. // where the constant was used, which is stored here.
  129. llvm::SmallVector<SymbolicConstant, 0> symbolic_constants_;
  130. };
  131. // Provides storage for instructions representing deduplicated global constants.
  132. class ConstantStore {
  133. public:
  134. explicit ConstantStore(File* sem_ir) : sem_ir_(sem_ir) {}
  135. // Adds a new constant instruction, or gets the existing constant with this
  136. // value. Returns the ID of the constant.
  137. //
  138. // This updates `sem_ir->insts()` and `sem_ir->constant_values()` if the
  139. // constant is new.
  140. enum PhaseKind : uint8_t { IsTemplate, IsPeriodSelfSymbolic, IsSymbolic };
  141. auto GetOrAdd(Inst inst, PhaseKind phase) -> ConstantId;
  142. // Collects memory usage of members.
  143. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  144. -> void {
  145. mem_usage.Collect(MemUsage::ConcatLabel(label, "map_"), map_);
  146. mem_usage.Collect(MemUsage::ConcatLabel(label, "constants_"), constants_);
  147. }
  148. // Returns a copy of the constant IDs as a vector, in an arbitrary but
  149. // stable order. This should not be used anywhere performance-sensitive.
  150. auto array_ref() const -> llvm::ArrayRef<InstId> { return constants_; }
  151. auto size() const -> int { return constants_.size(); }
  152. private:
  153. File* const sem_ir_;
  154. Map<Inst, ConstantId> map_;
  155. llvm::SmallVector<InstId, 0> constants_;
  156. };
  157. } // namespace Carbon::SemIR
  158. #endif // CARBON_TOOLCHAIN_SEM_IR_CONSTANT_H_