constant.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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 invalid, 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 invalid if `generic_id` is invalid.
  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 Invalid if the constant ID is non-constant. Requires is_valid.
  56. auto GetInstId(ConstantId const_id) const -> InstId {
  57. if (const_id.is_template()) {
  58. return const_id.template_inst_id();
  59. }
  60. if (const_id.is_symbolic()) {
  61. return GetSymbolicConstant(const_id).inst_id;
  62. }
  63. return InstId::Invalid;
  64. }
  65. // Gets the instruction ID that defines the value of the given constant.
  66. // Returns Invalid if the constant ID is non-constant or invalid.
  67. auto GetInstIdIfValid(ConstantId const_id) const -> InstId {
  68. return const_id.is_valid() ? GetInstId(const_id) : InstId::Invalid;
  69. }
  70. // Given an instruction, returns the unique constant instruction that is
  71. // equivalent to it. Returns Invalid for a non-constant instruction.
  72. auto GetConstantInstId(InstId inst_id) const -> InstId {
  73. return GetInstId(Get(inst_id));
  74. }
  75. // Returns whether two constant IDs represent the same constant value. This
  76. // includes the case where they might be in different generics and thus might
  77. // have different ConstantIds, but are still symbolically equal.
  78. auto AreEqualAcrossDeclarations(ConstantId a, ConstantId b) const -> bool {
  79. return GetInstId(a) == GetInstId(b);
  80. }
  81. auto AddSymbolicConstant(SymbolicConstant constant) -> ConstantId {
  82. symbolic_constants_.push_back(constant);
  83. return ConstantId::ForSymbolicConstantIndex(symbolic_constants_.size() - 1);
  84. }
  85. auto GetSymbolicConstant(ConstantId const_id) -> SymbolicConstant& {
  86. return symbolic_constants_[const_id.symbolic_index()];
  87. }
  88. auto GetSymbolicConstant(ConstantId const_id) const
  89. -> const SymbolicConstant& {
  90. return symbolic_constants_[const_id.symbolic_index()];
  91. }
  92. // Returns true for symbolic constants other than those that are only symbolic
  93. // because they depend on `.Self`.
  94. auto DependsOnGenericParameter(ConstantId const_id) const -> bool {
  95. return const_id.is_symbolic() &&
  96. !GetSymbolicConstant(const_id).period_self_only;
  97. }
  98. // Collects memory usage of members.
  99. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  100. -> void {
  101. mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
  102. mem_usage.Collect(MemUsage::ConcatLabel(label, "symbolic_constants_"),
  103. symbolic_constants_);
  104. }
  105. // Returns the constant values mapping as an ArrayRef whose keys are
  106. // instruction indexes. Some of the elements in this mapping may be Invalid or
  107. // NotConstant.
  108. auto array_ref() const -> llvm::ArrayRef<ConstantId> { return values_; }
  109. // Returns the symbolic constants mapping as an ArrayRef whose keys are
  110. // symbolic indexes of constants.
  111. auto symbolic_constants() const -> llvm::ArrayRef<SymbolicConstant> {
  112. return symbolic_constants_;
  113. }
  114. private:
  115. const ConstantId default_;
  116. // A mapping from `InstId::index` to the corresponding constant value. This is
  117. // expected to be sparse, and may be smaller than the list of instructions if
  118. // there are trailing non-constant instructions.
  119. //
  120. // Set inline size to 0 because these will typically be too large for the
  121. // stack, while this does make File smaller.
  122. llvm::SmallVector<ConstantId, 0> values_;
  123. // A mapping from a symbolic constant ID index to information about the
  124. // symbolic constant. For a template constant, the only information that we
  125. // track is the instruction ID, which is stored directly within the
  126. // `ConstantId`. For a symbolic constant, we also track information about
  127. // where the constant was used, which is stored here.
  128. llvm::SmallVector<SymbolicConstant, 0> symbolic_constants_;
  129. };
  130. // Provides storage for instructions representing deduplicated global constants.
  131. class ConstantStore {
  132. public:
  133. explicit ConstantStore(File* sem_ir) : sem_ir_(sem_ir) {}
  134. // Adds a new constant instruction, or gets the existing constant with this
  135. // value. Returns the ID of the constant.
  136. //
  137. // This updates `sem_ir->insts()` and `sem_ir->constant_values()` if the
  138. // constant is new.
  139. enum PhaseKind : uint8_t { IsTemplate, IsPeriodSelfSymbolic, IsSymbolic };
  140. auto GetOrAdd(Inst inst, PhaseKind phase) -> ConstantId;
  141. // Collects memory usage of members.
  142. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  143. -> void {
  144. mem_usage.Collect(MemUsage::ConcatLabel(label, "map_"), map_);
  145. mem_usage.Collect(MemUsage::ConcatLabel(label, "constants_"), constants_);
  146. }
  147. // Returns a copy of the constant IDs as a vector, in an arbitrary but
  148. // stable order. This should not be used anywhere performance-sensitive.
  149. auto array_ref() const -> llvm::ArrayRef<InstId> { return constants_; }
  150. auto size() const -> int { return constants_.size(); }
  151. private:
  152. File* const sem_ir_;
  153. Map<Inst, ConstantId> map_;
  154. llvm::SmallVector<InstId, 0> constants_;
  155. };
  156. } // namespace Carbon::SemIR
  157. #endif // CARBON_TOOLCHAIN_SEM_IR_CONSTANT_H_