generic.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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_GENERIC_H_
  5. #define CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_
  6. #include "common/set.h"
  7. #include "toolchain/base/value_store.h"
  8. #include "toolchain/sem_ir/ids.h"
  9. namespace Carbon::SemIR {
  10. // Information for a generic entity, such as a generic class, a generic
  11. // interface, or generic function.
  12. //
  13. // Note that this includes both checked generics and template generics.
  14. struct Generic : public Printable<Generic> {
  15. auto Print(llvm::raw_ostream& out) const -> void {
  16. out << "{decl: " << decl_id << ", bindings: " << bindings_id
  17. << ", self_specific_id: " << self_specific_id
  18. << ", decl_block_id: " << decl_block_id
  19. << ", definition_block_id: " << definition_block_id << "}";
  20. }
  21. // Returns the eval block for the specified region of the generic. This is a
  22. // block of instructions that should be evaluated to compute the values and
  23. // instructions needed by that region of the generic.
  24. auto GetEvalBlock(GenericInstIndex::Region region) const -> InstBlockId {
  25. return region == GenericInstIndex::Region::Declaration
  26. ? decl_block_id
  27. : definition_block_id;
  28. }
  29. // The following members always have values, and do not change throughout the
  30. // lifetime of the generic.
  31. // The first declaration of the generic entity.
  32. InstId decl_id;
  33. // A block containing the IDs of compile time bindings in this generic scope.
  34. // The index in this block will match the `bind_index` in the name binding
  35. // instruction's `EntityName`.
  36. InstBlockId bindings_id;
  37. // The self specific of this generic, which is a specific where every generic
  38. // parameter's argument is that same parameter. For example, the self specific
  39. // of `Vector(T:! type)` is `Vector(T)`.
  40. SpecificId self_specific_id;
  41. // The following members are set at the end of the corresponding region of the
  42. // generic.
  43. // The eval block for the declaration region of the generic.
  44. InstBlockId decl_block_id = InstBlockId::None;
  45. // The eval block for the definition region of the generic.
  46. InstBlockId definition_block_id = InstBlockId::None;
  47. };
  48. // Provides storage for generics.
  49. class GenericStore : public ValueStore<GenericId, Generic, Tag<CheckIRId>> {
  50. public:
  51. using ValueStore::ValueStore;
  52. // Get the self specific for a generic, or `None` if the `id` is `None`.
  53. auto GetSelfSpecific(GenericId id) const -> SpecificId {
  54. return id.has_value() ? Get(id).self_specific_id : SpecificId::None;
  55. }
  56. };
  57. // A specific, which is the combination of a generic and specified generic
  58. // arguments. For each construct that depends on a compile-time parameter in the
  59. // generic entity, this contains the corresponding specific value. This includes
  60. // values for the compile-time parameters themselves.
  61. struct Specific : Printable<Specific> {
  62. auto Print(llvm::raw_ostream& out) const -> void {
  63. out << "{generic: " << generic_id << ", args: " << args_id
  64. << ", decl_block_id: " << decl_block_id
  65. << ", definition_block_id: " << definition_block_id << "}";
  66. }
  67. // Returns true if this specific has never been resolved. Such specifics are
  68. // used to track non-canonical argument values, for example in a non-canonical
  69. // `ClassType` that describes how the arguments to the class were written.
  70. auto IsUnresolved() const -> bool { return !decl_block_id.has_value(); }
  71. // Returns the value block for this region of the specific. This is a block
  72. // containing values and instructions produced by evaluating the corresponding
  73. // eval block of the generic within the context of this specific. These are
  74. // the constant values and types and the instantiated template-dependent
  75. // instructions that are used in this region of the specific. Each inst in
  76. // the value block corresponds to the inst in the corresponding eval block
  77. // with the same index.
  78. auto GetValueBlock(GenericInstIndex::Region region) const -> InstBlockId {
  79. return region == GenericInstIndex::Region::Declaration
  80. ? decl_block_id
  81. : definition_block_id;
  82. }
  83. // The generic that this is a specific version of.
  84. GenericId generic_id;
  85. // Argument values, corresponding to the bindings in `Generic::bindings_id`.
  86. InstBlockId args_id;
  87. // The following members are set when the corresponding region of the specific
  88. // is resolved.
  89. // The value block for the declaration region of the specific.
  90. InstBlockId decl_block_id = InstBlockId::None;
  91. // The value block for the definition region of the specific.
  92. InstBlockId definition_block_id = InstBlockId::None;
  93. };
  94. // Provides storage for deduplicated specifics, which represent generics plus
  95. // their associated generic argument list.
  96. class SpecificStore : public Yaml::Printable<SpecificStore> {
  97. public:
  98. using IdType = SpecificId;
  99. using ValueStore = ValueStore<SpecificId, Specific, Tag<CheckIRId>>;
  100. explicit SpecificStore(CheckIRId check_ir_id) : specifics_(check_ir_id) {}
  101. // Adds a new specific, or gets the existing specific for a specified generic
  102. // and argument list. Returns the ID of the specific. The argument IDs must be
  103. // for instructions in the constant block, and must be a canonical instruction
  104. // block ID.
  105. auto GetOrAdd(GenericId generic_id, InstBlockId args_id) -> SpecificId;
  106. // Gets the specific with the given ID.
  107. auto Get(SpecificId specific_id) const -> const Specific& {
  108. return specifics_.Get(specific_id);
  109. }
  110. // Gets the specific with the given ID.
  111. auto Get(SpecificId specific_id) -> Specific& {
  112. return specifics_.Get(specific_id);
  113. }
  114. // Gets the arguments of the specified specific, or `Empty` if `None` is
  115. // passed.
  116. auto GetArgsOrEmpty(SpecificId specific_id) const -> InstBlockId {
  117. return specific_id.has_value() ? Get(specific_id).args_id
  118. : InstBlockId::Empty;
  119. }
  120. // These are to support printable structures, and are not guaranteed.
  121. auto OutputYaml() const -> Yaml::OutputMapping {
  122. return specifics_.OutputYaml();
  123. }
  124. // Collects memory usage of members.
  125. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  126. -> void;
  127. auto values() const [[clang::lifetimebound]] -> ValueStore::Range {
  128. return specifics_.values();
  129. }
  130. auto size() const -> size_t { return specifics_.size(); }
  131. auto enumerate() const [[clang::lifetimebound]] -> auto {
  132. return specifics_.enumerate();
  133. }
  134. auto GetIdTag() const { return specifics_.GetIdTag(); }
  135. private:
  136. // Context for hashing keys.
  137. class KeyContext;
  138. ValueStore specifics_;
  139. Carbon::Set<SpecificId, 0, KeyContext> lookup_table_;
  140. };
  141. // Gets the substituted constant value of a potentially generic instruction
  142. // within a specific. Note that this does not perform substitution, and will
  143. // return `None` if the substituted constant value is not yet known.
  144. auto GetConstantValueInSpecific(const File& sem_ir, SpecificId specific_id,
  145. InstId inst_id) -> ConstantId;
  146. // Gets the substituted constant value of a potentially generic instruction
  147. // within a specific, where the generic instruction and the specific may be in
  148. // different files. Returns the file in which the constant value was found and
  149. // the constant ID in that file.
  150. auto GetConstantValueInSpecific(const File& specific_ir, SpecificId specific_id,
  151. const File& inst_ir, InstId inst_id)
  152. -> std::pair<const File*, ConstantId>;
  153. // Gets the substituted type of an instruction within a specific. Note that this
  154. // does not perform substitution, and will return `None` if the substituted type
  155. // is not yet known.
  156. auto GetTypeOfInstInSpecific(const File& sem_ir, SpecificId specific_id,
  157. InstId inst_id) -> TypeId;
  158. // Gets the substituted type of a potentially generic instruction within a
  159. // specific, where the generic instruction and the specific may be in different
  160. // files. Returns the file in which the type was found and the type ID in that
  161. // file.
  162. auto GetTypeOfInstInSpecific(const File& specific_ir, SpecificId specific_id,
  163. const File& inst_ir, InstId inst_id)
  164. -> std::pair<const File*, TypeId>;
  165. } // namespace Carbon::SemIR
  166. #endif // CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_