// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_ #define CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_ #include "common/set.h" #include "toolchain/base/value_store.h" #include "toolchain/sem_ir/ids.h" namespace Carbon::SemIR { // Information for a generic entity, such as a generic class, a generic // interface, or generic function. // // Note that this includes both checked generics and template generics. struct Generic : public Printable { auto Print(llvm::raw_ostream& out) const -> void { out << "{decl: " << decl_id << ", bindings: " << bindings_id << "}"; } // Returns the eval block for the specified region of the generic. This is a // block of instructions that should be evaluated to compute the values and // instructions needed by that region of the generic. auto GetEvalBlock(GenericInstIndex::Region region) const -> InstBlockId { return region == GenericInstIndex::Region::Declaration ? decl_block_id : definition_block_id; } // The following members always have values, and do not change throughout the // lifetime of the generic. // The first declaration of the generic entity. InstId decl_id; // A block containing the IDs of compile time bindings in this generic scope. // The index in this block will match the `bind_index` in the name binding // instruction's `EntityName`. InstBlockId bindings_id; // The self specific of this generic, which is a specific where every generic // parameter's argument is that same parameter. For example, the self specific // of `Vector(T:! type)` is `Vector(T)`. SpecificId self_specific_id; // The following members are set at the end of the corresponding region of the // generic. // The eval block for the declaration region of the generic. InstBlockId decl_block_id = InstBlockId::Invalid; // The eval block for the definition region of the generic. InstBlockId definition_block_id = InstBlockId::Invalid; }; // Provides storage for generics. class GenericStore : public ValueStore { public: // Get the self specific for a generic, or an invalid specific for an invalid // generic ID. auto GetSelfSpecific(GenericId id) -> SpecificId { return id.is_valid() ? Get(id).self_specific_id : SpecificId::Invalid; } }; // A specific, which is the combination of a generic and specified generic // arguments. For each construct that depends on a compile-time parameter in the // generic entity, this contains the corresponding specific value. This includes // values for the compile-time parameters themselves. struct Specific : Printable { auto Print(llvm::raw_ostream& out) const -> void { out << "{generic: " << generic_id << ", args: " << args_id << "}"; } // Returns the value block for this region of the specific. This is a block // containing values and instructions produced by evaluating the corresponding // eval block of the generic within the context of this specific. These are // the constant values and types and the instantiated template-dependent // instructions that are used in this region of the specific. auto GetValueBlock(GenericInstIndex::Region region) const -> InstBlockId { return region == GenericInstIndex::Region::Declaration ? decl_block_id : definition_block_id; } // The generic that this is a specific version of. GenericId generic_id; // Argument values, corresponding to the bindings in `Generic::bindings_id`. InstBlockId args_id; // The following members are set when the corresponding region of the specific // is resolved. // The value block for the declaration region of the specific. InstBlockId decl_block_id = InstBlockId::Invalid; // The value block for the definition region of the specific. InstBlockId definition_block_id = InstBlockId::Invalid; }; // Provides storage for deduplicated specifics, which represent generics plus // their associated generic argument list. class SpecificStore : public Yaml::Printable { public: // Adds a new specific, or gets the existing specific for a specified generic // and argument list. Returns the ID of the specific. The argument IDs must be // for instructions in the constant block, and must be a canonical instruction // block ID. auto GetOrAdd(GenericId generic_id, InstBlockId args_id) -> SpecificId; // Gets the specific with the given ID. auto Get(SpecificId specific_id) const -> const Specific& { return specifics_.Get(specific_id); } // Gets the specific with the given ID. auto Get(SpecificId specific_id) -> Specific& { return specifics_.Get(specific_id); } // These are to support printable structures, and are not guaranteed. auto OutputYaml() const -> Yaml::OutputMapping { return specifics_.OutputYaml(); } // Collects memory usage of members. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const -> void; auto array_ref() const -> llvm::ArrayRef { return specifics_.array_ref(); } auto size() const -> size_t { return specifics_.size(); } private: // Context for hashing keys. class KeyContext; ValueStore specifics_; Carbon::Set lookup_table_; }; // Gets the substituted value of a potentially generic constant within a // specific. Note that this does not perform substitution, and will return // `Invalid` if the substituted constant value is not yet known. auto GetConstantInSpecific(const File& sem_ir, SpecificId specific_id, ConstantId const_id) -> ConstantId; // Gets the substituted constant value of a potentially generic instruction // within a specific. Note that this does not perform substitution, and will // return `Invalid` if the substituted constant value is not yet known. auto GetConstantValueInSpecific(const File& sem_ir, SpecificId specific_id, InstId inst_id) -> ConstantId; // Gets the substituted value of a potentially generic type within a specific. // Note that this does not perform substitution, and will return `Invalid` if // the substituted type is not yet known. auto GetTypeInSpecific(const File& sem_ir, SpecificId specific_id, TypeId type_id) -> TypeId; } // namespace Carbon::SemIR #endif // CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_