constant.h 6.6 KB

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