| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133 |
- // 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_IDS_H_
- #define CARBON_TOOLCHAIN_SEM_IR_IDS_H_
- #include <limits>
- #include "common/check.h"
- #include "common/ostream.h"
- #include "llvm/ADT/APFloat.h"
- #include "toolchain/base/index_base.h"
- #include "toolchain/base/value_ids.h"
- #include "toolchain/diagnostics/emitter.h"
- #include "toolchain/parse/node_ids.h"
- namespace Carbon::SemIR {
- // TODO: This is in use, but not here.
- class File;
- // The ID of an `Inst`.
- struct InstId : public IdBase<InstId> {
- static constexpr llvm::StringLiteral Label = "inst";
- // The maximum ID, inclusive.
- static constexpr int Max = std::numeric_limits<int32_t>::max();
- // Represents the result of a name lookup that is temporarily disallowed
- // because the name is currently being initialized.
- static const InstId InitTombstone;
- // A placeholder used in the `ImplWitness` table of instructions for members
- // of the impl. These are replaced as values are seen for the witness table in
- // the impl declaration or definition. This is distinct from `None` for
- // debugging purposes.
- static const InstId ImplWitnessTablePlaceholder;
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- inline constexpr InstId InstId::InitTombstone = InstId(NoneIndex - 1);
- inline constexpr InstId InstId::ImplWitnessTablePlaceholder =
- InstId(NoneIndex - 2);
- // An InstId whose value is a type. The fact it's a type must be validated
- // before construction, and this allows that validation to be represented in the
- // type system.
- struct TypeInstId : public InstId {
- static const TypeInstId None;
- using InstId::InstId;
- static constexpr auto UnsafeMake(InstId id) -> TypeInstId {
- return TypeInstId(UnsafeCtor(), id);
- }
- private:
- struct UnsafeCtor {};
- explicit constexpr TypeInstId(UnsafeCtor /*unsafe*/, InstId id)
- : InstId(id) {}
- };
- inline constexpr TypeInstId TypeInstId::None =
- TypeInstId::UnsafeMake(InstId::None);
- // An InstId whose type is known to be T. The fact it's a type must be validated
- // before construction, and this allows that validation to be represented in the
- // type system.
- //
- // Unlike TypeInstId, this type can *not* be an operand in instructions, since
- // being a template prevents it from being used in non-generic contexts such as
- // switches.
- template <typename T>
- struct KnownInstId : public InstId {
- static const KnownInstId None;
- using InstId::InstId;
- static constexpr auto UnsafeMake(InstId id) -> KnownInstId {
- return KnownInstId(UnsafeCtor(), id);
- }
- private:
- struct UnsafeCtor {};
- explicit constexpr KnownInstId(UnsafeCtor /*unsafe*/, InstId id)
- : InstId(id) {}
- };
- template <typename T>
- inline constexpr KnownInstId<T> KnownInstId<T>::None =
- KnownInstId<T>::UnsafeMake(InstId::None);
- // An ID of an instruction that is referenced absolutely by another instruction.
- // This should only be used as the type of a field within a typed instruction
- // class.
- //
- // When a typed instruction has a field of this type, that field represents an
- // absolute reference to another instruction that typically resides in a
- // different entity. This behaves in most respects like an InstId field, but
- // substitution into the typed instruction leaves the field unchanged rather
- // than substituting into it.
- class AbsoluteInstId : public InstId {
- public:
- static constexpr llvm::StringLiteral Label = "absolute_inst";
- // Support implicit conversion from InstId so that InstId and AbsoluteInstId
- // have the same interface.
- explicit(false) constexpr AbsoluteInstId(InstId inst_id) : InstId(inst_id) {}
- using InstId::InstId;
- };
- // An ID of an instruction that is used as the destination of an initializing
- // expression. This should only be used as the type of a field within a typed
- // instruction class.
- //
- // This behaves in most respects like an InstId field, but constant evaluation
- // of an instruction with a destination field will not evaluate this field, and
- // substitution will not substitute into it.
- //
- // TODO: Decide on how substitution should handle this. Multiple instructions
- // can refer to the same destination, so these don't have the tree structure
- // that substitution expects, but we might need to substitute into the result of
- // an instruction.
- class DestInstId : public InstId {
- public:
- static constexpr llvm::StringLiteral Label = "dest_inst";
- // Support implicit conversion from InstId so that InstId and DestInstId
- // have the same interface.
- explicit(false) constexpr DestInstId(InstId inst_id) : InstId(inst_id) {}
- using InstId::InstId;
- };
- // An ID of an instruction that is referenced as a meta-operand of an action.
- // This should only be used as the type of a field within a typed instruction
- // class.
- //
- // This is used to model cases where an action's operand is not the value
- // produced by another instruction, but is the other instruction itself. This is
- // common for actions representing template instantiation.
- //
- // This behaves in most respects like an InstId field, but evaluation of the
- // instruction that has this field will not fail if the instruction does not
- // have a constant value. If the instruction has a constant value, it will still
- // be replaced by its constant value during evaluation like normal, but if it
- // has a non-constant value, the field is left unchanged by evaluation.
- class MetaInstId : public InstId {
- public:
- static constexpr llvm::StringLiteral Label = "meta_inst";
- // Support implicit conversion from InstId so that InstId and MetaInstId
- // have the same interface.
- explicit(false) constexpr MetaInstId(InstId inst_id) : InstId(inst_id) {}
- using InstId::InstId;
- };
- // The ID of a constant value of an expression. An expression is either:
- //
- // - a concrete constant, whose value does not depend on any generic parameters,
- // such as `42` or `i32*` or `("hello", "world")`, or
- // - a symbolic constant, whose value includes a generic parameter, such as
- // `Vector(T*)`, or
- // - a runtime expression, such as `Print("hello")`.
- //
- // Concrete constants are a thin wrapper around the instruction ID of the
- // constant instruction that defines the constant. Symbolic constants are an
- // index into a separate table of `SymbolicConstant`s maintained by the constant
- // value store.
- //
- // IdTags for ConstantIds are slightly complex, and you need to know if the
- // constant is concrete or symbolic to know its tag:
- // - Concrete ConstantIds use the tag of the store of InstIds.
- // - Symbolic ConstantIds use the tag of the store of internal SymbolicIds.
- struct ConstantId : public IdBase<ConstantId> {
- static constexpr llvm::StringLiteral Label = "constant";
- // An ID for an expression that is not constant.
- static const ConstantId NotConstant;
- // Returns the constant ID corresponding to a concrete constant, which should
- // either be in the `constants` block in the file or should be known to be
- // unique.
- static constexpr auto ForConcreteConstant(InstId const_id) -> ConstantId {
- return ConstantId(const_id.index);
- }
- using IdBase::IdBase;
- // Returns whether this represents a constant. Requires has_value.
- constexpr auto is_constant() const -> bool {
- CARBON_DCHECK(has_value());
- return *this != ConstantId::NotConstant;
- }
- // Returns whether this represents a symbolic constant. Requires has_value.
- constexpr auto is_symbolic() const -> bool {
- CARBON_DCHECK(has_value());
- return index <= FirstSymbolicId;
- }
- // Returns whether this represents a concrete constant. Requires has_value.
- constexpr auto is_concrete() const -> bool {
- CARBON_DCHECK(has_value());
- return index >= 0;
- }
- // Prints this ID to the given output stream. `disambiguate` indicates whether
- // concrete constants should be wrapped with "concrete_constant(...)" so that
- // they aren't printed the same as an InstId. This can be set to false if
- // there is no risk of ambiguity.
- auto Print(llvm::raw_ostream& out, bool disambiguate = true) const -> void;
- private:
- friend class ConstantValueStore;
- // For Dump.
- friend auto MakeSymbolicConstantId(int id) -> ConstantId;
- // A symbolic constant.
- struct SymbolicId : public IdBase<SymbolicId> {
- static constexpr llvm::StringLiteral Label = "symbolic_constant";
- using IdBase::IdBase;
- };
- // Returns the constant ID corresponding to a symbolic constant index.
- static constexpr auto ForSymbolicConstantId(SymbolicId symbolic_id)
- -> ConstantId {
- return ConstantId(FirstSymbolicId - symbolic_id.index);
- }
- // TODO: C++23 makes std::abs constexpr, but until then we mirror std::abs
- // logic here. LLVM should still optimize this.
- static constexpr auto Abs(int32_t i) -> int32_t { return i > 0 ? i : -i; }
- // Returns the instruction that describes this concrete constant value.
- // Requires `is_concrete()`. Use `ConstantValueStore::GetInstId` to get the
- // instruction ID of a `ConstantId`.
- constexpr auto concrete_inst_id() const -> InstId {
- CARBON_DCHECK(is_concrete());
- return InstId(index);
- }
- // Returns the symbolic constant index that describes this symbolic constant
- // value. Requires `is_symbolic()`.
- constexpr auto symbolic_id() const -> SymbolicId {
- CARBON_DCHECK(is_symbolic());
- return SymbolicId(FirstSymbolicId - index);
- }
- static constexpr int32_t NotConstantIndex = NoneIndex - 1;
- static constexpr int32_t FirstSymbolicId = NoneIndex - 2;
- };
- inline constexpr ConstantId ConstantId::NotConstant =
- ConstantId(NotConstantIndex);
- // The ID of a `EntityName`.
- struct EntityNameId : public IdBase<EntityNameId> {
- static constexpr llvm::StringLiteral Label = "entity_name";
- using IdBase::IdBase;
- };
- // The ID of a C++ global variable.
- struct CppGlobalVarId : public IdBase<CppGlobalVarId> {
- static constexpr llvm::StringLiteral Label = "cpp_global_var";
- using IdBase::IdBase;
- };
- // The index of a compile-time binding. This is the de Bruijn level for the
- // binding -- that is, this is the number of other compile time bindings whose
- // scope encloses this binding.
- struct CompileTimeBindIndex : public IndexBase<CompileTimeBindIndex> {
- static constexpr llvm::StringLiteral Label = "comp_time_bind";
- using IndexBase::IndexBase;
- };
- // The index of a `Call` parameter in a function. These are allocated
- // sequentially, left-to-right, to the function parameters that will have
- // arguments passed to them at runtime. In a `Call` instruction, a runtime
- // argument will have the position in the argument list corresponding to its
- // `Call` parameter index.
- struct CallParamIndex : public IndexBase<CallParamIndex> {
- static constexpr llvm::StringLiteral Label = "call_param";
- using IndexBase::IndexBase;
- };
- // The ID of a C++ overload set.
- struct CppOverloadSetId : public IdBase<CppOverloadSetId> {
- static constexpr llvm::StringLiteral Label = "cpp_overload_set";
- using IdBase::IdBase;
- };
- // The ID of a function.
- struct FunctionId : public IdBase<FunctionId> {
- static constexpr llvm::StringLiteral Label = "function";
- using IdBase::IdBase;
- };
- // The ID of an IR within the set of all IRs being evaluated in the current
- // check execution.
- struct CheckIRId : public IdBase<CheckIRId> {
- static constexpr llvm::StringLiteral Label = "check_ir";
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- // The ID of a `Class`.
- struct ClassId : public IdBase<ClassId> {
- static constexpr llvm::StringLiteral Label = "class";
- using IdBase::IdBase;
- };
- // The ID of a `Vtable`.
- struct VtableId : public IdBase<VtableId> {
- static constexpr llvm::StringLiteral Label = "vtable";
- using IdBase::IdBase;
- };
- // The ID of an `Interface`.
- struct InterfaceId : public IdBase<InterfaceId> {
- static constexpr llvm::StringLiteral Label = "interface";
- using IdBase::IdBase;
- };
- // The ID of a `NamedConstraint`.
- struct NamedConstraintId : public IdBase<NamedConstraintId> {
- static constexpr llvm::StringLiteral Label = "constraint";
- using IdBase::IdBase;
- };
- // The ID of an `AssociatedConstant`.
- struct AssociatedConstantId : public IdBase<AssociatedConstantId> {
- static constexpr llvm::StringLiteral Label = "assoc_const";
- using IdBase::IdBase;
- };
- // The ID of a `FacetTypeInfo`.
- struct FacetTypeId : public IdBase<FacetTypeId> {
- static constexpr llvm::StringLiteral Label = "facet_type";
- using DiagnosticType = Diagnostics::TypeInfo<std::string>;
- using IdBase::IdBase;
- };
- // The ID of an resolved facet type value.
- struct IdentifiedFacetTypeId : public IdBase<IdentifiedFacetTypeId> {
- static constexpr llvm::StringLiteral Label = "identified_facet_type";
- using IdBase::IdBase;
- };
- // The ID of an `Impl`.
- struct ImplId : public IdBase<ImplId> {
- using DiagnosticType = Diagnostics::TypeInfo<std::string>;
- static constexpr llvm::StringLiteral Label = "impl";
- using IdBase::IdBase;
- };
- // The ID of a `Generic`.
- struct GenericId : public IdBase<GenericId> {
- static constexpr llvm::StringLiteral Label = "generic";
- using IdBase::IdBase;
- };
- // The ID of a `Specific`, which is the result of specifying the generic
- // arguments for a generic.
- struct SpecificId : public IdBase<SpecificId> {
- using DiagnosticType = Diagnostics::TypeInfo<std::string>;
- static constexpr llvm::StringLiteral Label = "specific";
- using IdBase::IdBase;
- };
- // The ID of a `SpecificInterface`, which is an interface and a specific pair.
- struct SpecificInterfaceId : public IdBase<SpecificInterfaceId> {
- using DiagnosticType = Diagnostics::TypeInfo<std::string>;
- static constexpr llvm::StringLiteral Label = "specific_interface";
- using IdBase::IdBase;
- };
- // The index of an instruction that depends on generic parameters within a
- // region of a generic. A corresponding specific version of the instruction can
- // be found in each specific corresponding to that generic. This is a pair of a
- // region and an index, stored in 32 bits.
- struct GenericInstIndex : public IndexBase<GenericInstIndex> {
- // Where the value is first used within the generic.
- enum Region : uint8_t {
- // In the declaration.
- Declaration,
- // In the definition.
- Definition,
- };
- // An index with no value.
- static const GenericInstIndex None;
- explicit constexpr GenericInstIndex(Region region, int32_t index)
- : IndexBase(region == Declaration ? index
- : FirstDefinitionIndex - index) {
- CARBON_CHECK(index >= 0);
- }
- // Returns the index of the instruction within the region.
- auto index() const -> int32_t {
- CARBON_CHECK(has_value());
- return IndexBase::index >= 0 ? IndexBase::index
- : FirstDefinitionIndex - IndexBase::index;
- }
- // Returns the region within which this instruction was first used.
- auto region() const -> Region {
- CARBON_CHECK(has_value());
- return IndexBase::index >= 0 ? Declaration : Definition;
- }
- auto Print(llvm::raw_ostream& out) const -> void;
- private:
- static constexpr auto MakeNone() -> GenericInstIndex {
- GenericInstIndex result(Declaration, 0);
- result.IndexBase::index = NoneIndex;
- return result;
- }
- static constexpr int32_t FirstDefinitionIndex = NoneIndex - 1;
- };
- inline constexpr GenericInstIndex GenericInstIndex::None =
- GenericInstIndex::MakeNone();
- // The ID of an `ImportIR` within the set of imported IRs, both direct and
- // indirect.
- struct ImportIRId : public IdBase<ImportIRId> {
- static constexpr llvm::StringLiteral Label = "import_ir";
- // The implicit `api` import, for an `impl` file. A null entry is added if
- // there is none, as in an `api`, in which case this ID should not show up in
- // instructions.
- static const ImportIRId ApiForImpl;
- // The `Cpp` import. A null entry is added if there is none, in which case
- // this ID should not show up in instructions.
- static const ImportIRId Cpp;
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- inline constexpr ImportIRId ImportIRId::ApiForImpl = ImportIRId(0);
- inline constexpr ImportIRId ImportIRId::Cpp = ImportIRId(ApiForImpl.index + 1);
- // The ID of a `ClangDecl`.
- //
- // These IDs are importantly distinct from the `inst_id` associated with each
- // declaration. These form a dense range of IDs that is used to reference the
- // AST node pointers without storing those pointers directly into SemIR and
- // needing space to hold a full pointer. We can't avoid having these IDs without
- // embedding pointers directly into the storage of SemIR as part of an
- // instruction.
- struct ClangDeclId : public IdBase<ClangDeclId> {
- static constexpr llvm::StringLiteral Label = "clang_decl_id";
- using IdBase::IdBase;
- };
- // A boolean value.
- struct BoolValue : public IdBase<BoolValue> {
- // Not used by `Print`, but for `IdKind`.
- static constexpr llvm::StringLiteral Label = "bool";
- static const BoolValue False;
- static const BoolValue True;
- // Returns the `BoolValue` corresponding to `b`.
- static constexpr auto From(bool b) -> BoolValue { return b ? True : False; }
- // Returns the `bool` corresponding to this `BoolValue`.
- constexpr auto ToBool() -> bool {
- CARBON_CHECK(*this == False || *this == True, "Invalid bool value {0}",
- index);
- return *this != False;
- }
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- inline constexpr BoolValue BoolValue::False = BoolValue(0);
- inline constexpr BoolValue BoolValue::True = BoolValue(1);
- // A character literal value as a unicode codepoint.
- struct CharId : public IdBase<CharId> {
- // Not used by `Print`, but for `IdKind`.
- static constexpr llvm::StringLiteral Label = "";
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- // An integer kind value -- either "signed" or "unsigned".
- //
- // This might eventually capture any other properties of an integer type that
- // affect its semantics, such as overflow behavior.
- struct IntKind : public IdBase<IntKind> {
- // Not used by `Print`, but for `IdKind`.
- static constexpr llvm::StringLiteral Label = "int_kind";
- static const IntKind Unsigned;
- static const IntKind Signed;
- using IdBase::IdBase;
- // Returns whether this type is signed.
- constexpr auto is_signed() -> bool { return *this == Signed; }
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- inline constexpr IntKind IntKind::Unsigned = IntKind(0);
- inline constexpr IntKind IntKind::Signed = IntKind(1);
- // A float kind value. This describes the semantics of the floating-point type.
- // This represents very similar information to the bit-width, but is more
- // precise. In particular, there is in general more than one floating-point type
- // with a given bit-width, and while only one such type can be named with the
- // `fN` notation, the others should still be modeled as `FloatType`s.
- struct FloatKind : public IdBase<FloatKind> {
- // Not used by `Print`, but for `IdKind`.
- static constexpr llvm::StringLiteral Label = "float_kind";
- // An explicitly absent kind. Used when the kind has not been determined.
- static const FloatKind None;
- // Supported IEEE-754 interchange formats. These correspond to Carbon `fN`
- // type literal syntax.
- static const FloatKind Binary16;
- static const FloatKind Binary32;
- static const FloatKind Binary64;
- static const FloatKind Binary128;
- // Note, binary256 is not supported by LLVM and hence not by us.
- // Other formats supported by LLVM. Support for these may be
- // target-dependent.
- // TODO: Add a mechanism to use these types from Carbon code.
- static const FloatKind BFloat16;
- static const FloatKind X87Float80;
- static const FloatKind PPCFloat128;
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- // Query the LLVM semantics model associated with this kind of floating-point
- // type. This kind must be concrete.
- auto Semantics() const -> const llvm::fltSemantics&;
- };
- inline constexpr FloatKind FloatKind::None = FloatKind(NoneIndex);
- inline constexpr FloatKind FloatKind::Binary16 = FloatKind(0);
- inline constexpr FloatKind FloatKind::Binary32 = FloatKind(1);
- inline constexpr FloatKind FloatKind::Binary64 = FloatKind(2);
- inline constexpr FloatKind FloatKind::Binary128 = FloatKind(3);
- inline constexpr FloatKind FloatKind::BFloat16 = FloatKind(4);
- inline constexpr FloatKind FloatKind::X87Float80 = FloatKind(5);
- inline constexpr FloatKind FloatKind::PPCFloat128 = FloatKind(6);
- // An X-macro for special names. Uses should look like:
- //
- // #define CARBON_SPECIAL_NAME_ID_FOR_XYZ(Name) ...
- // CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_XYZ)
- // #undef CARBON_SPECIAL_NAME_ID_FOR_XYZ
- #define CARBON_SPECIAL_NAME_ID(X) \
- /* The name of `base`. */ \
- X(Base) \
- /* The name of the discriminant field (if any) in a choice. */ \
- X(ChoiceDiscriminant) \
- /* The name of the package `Core`. */ \
- X(Core) \
- /* The name of the package `Cpp`. */ \
- X(Cpp) \
- /* The name of imported C++ destructors. */ \
- X(CppDestructor) \
- /* The name of imported C++ operator functions */ \
- X(CppOperator) \
- /* The name of the default package `Main`. */ \
- X(MainPackage) \
- /* The name of `package`. */ \
- X(PackageKeyword) \
- /* The name of `.Self`. */ \
- X(PeriodSelf) \
- /* The name of the return slot in a function. */ \
- X(ReturnSlot) \
- /* The name of `Self`. */ \
- X(SelfType) \
- /* The name of `self`. */ \
- X(SelfValue) \
- /* The name of `_`. */ \
- X(Underscore) \
- /* The name of `vptr`. */ \
- X(Vptr)
- // The ID of a name. A name is either a string or a special name such as
- // `self`, `Self`, or `base`.
- struct NameId : public IdBase<NameId> {
- static constexpr llvm::StringLiteral Label = "name";
- // names().GetFormatted() is used for diagnostics.
- using DiagnosticType = Diagnostics::TypeInfo<std::string>;
- // An enum of special names.
- enum class SpecialNameId : uint8_t {
- #define CARBON_SPECIAL_NAME_ID_FOR_ENUM(Name) Name,
- CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_ENUM)
- #undef CARBON_SPECIAL_NAME_ID_FOR_ENUM
- };
- // For each SpecialNameId, provide a matching `NameId` instance for
- // convenience.
- #define CARBON_SPECIAL_NAME_ID_FOR_DECL(Name) static const NameId Name;
- CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_DECL)
- #undef CARBON_SPECIAL_NAME_ID_FOR_DECL
- // The number of non-index (<0) that exist, and will need storage in name
- // lookup.
- static const int NonIndexValueCount;
- // Returns the NameId corresponding to a particular IdentifierId.
- static auto ForIdentifier(IdentifierId id) -> NameId;
- // Returns the NameId corresponding to a particular PackageNameId. This is the
- // name that is declared when the package is imported.
- static auto ForPackageName(PackageNameId id) -> NameId;
- using IdBase::IdBase;
- // Returns the IdentifierId corresponding to this NameId, or `None` if this is
- // a special name.
- auto AsIdentifierId() const -> IdentifierId {
- return index >= 0 ? IdentifierId(index) : IdentifierId::None;
- }
- // Expose special names for `switch`.
- constexpr auto AsSpecialNameId() const -> std::optional<SpecialNameId> {
- if (index >= NoneIndex) {
- return std::nullopt;
- }
- return static_cast<SpecialNameId>(NoneIndex - 1 - index);
- }
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- // Define the special `static const NameId` values.
- #define CARBON_SPECIAL_NAME_ID_FOR_DEF(Name) \
- inline constexpr NameId NameId::Name = \
- NameId(NoneIndex - 1 - static_cast<int>(NameId::SpecialNameId::Name));
- CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_DEF)
- #undef CARBON_SPECIAL_NAME_ID_FOR_DEF
- // Count non-index values, including `None` and special names.
- #define CARBON_SPECIAL_NAME_ID_FOR_COUNT(...) +1
- inline constexpr int NameId::NonIndexValueCount =
- 1 CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_COUNT);
- #undef CARBON_SPECIAL_NAME_ID_FOR_COUNT
- // The ID of a `NameScope`.
- struct NameScopeId : public IdBase<NameScopeId> {
- static constexpr llvm::StringLiteral Label = "name_scope";
- // The package (or file) name scope, guaranteed to be the first added.
- static const NameScopeId Package;
- using IdBase::IdBase;
- };
- inline constexpr NameScopeId NameScopeId::Package = NameScopeId(0);
- // The ID of an `InstId` block.
- struct InstBlockId : public IdBase<InstBlockId> {
- static constexpr llvm::StringLiteral Label = "inst_block";
- // The canonical empty block, reused to avoid allocating empty vectors. Always
- // the 0-index block.
- static const InstBlockId Empty;
- // Exported instructions.
- //
- // Empty until the File is fully checked; intermediate state is in the
- // Check::Context.
- static const InstBlockId Exports;
- // Generated entities.
- //
- // Empty until the File is fully checked; intermediate state is in the
- // Check::Context.
- static const InstBlockId Generated;
- // Instructions produced through import logic.
- //
- // Empty until the File is fully checked; intermediate state is in the
- // Check::Context.
- static const InstBlockId Imports;
- // Global declaration initialization instructions. Empty if none are present.
- // Otherwise, __global_init function will be generated and this block will
- // be inserted into it.
- static const InstBlockId GlobalInit;
- // A convenience list of reserved IDs.
- static const std::array<InstBlockId, 5> ReservedIds;
- // An ID for unreachable code.
- static const InstBlockId Unreachable;
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- inline constexpr InstBlockId InstBlockId::Empty = InstBlockId(0);
- inline constexpr InstBlockId InstBlockId::Exports = InstBlockId(1);
- inline constexpr InstBlockId InstBlockId::Generated = InstBlockId(2);
- inline constexpr InstBlockId InstBlockId::Imports = InstBlockId(3);
- inline constexpr InstBlockId InstBlockId::GlobalInit = InstBlockId(4);
- inline constexpr InstBlockId InstBlockId::Unreachable =
- InstBlockId(NoneIndex - 1);
- inline constexpr std::array<InstBlockId, 5> InstBlockId::ReservedIds = {
- Empty, Exports, Generated, Imports, GlobalInit};
- // Contains either an `InstBlockId` value, an error value, or
- // `InstBlockId::None`.
- //
- // Error values are treated as values, though they are not representable as an
- // `InstBlockId` (unlike for the singleton error `InstId`).
- class InstBlockIdOrError {
- public:
- explicit(false) InstBlockIdOrError(InstBlockId inst_block_id)
- : InstBlockIdOrError(inst_block_id, false) {}
- static auto MakeError() -> InstBlockIdOrError {
- return {InstBlockId::None, true};
- }
- // Returns whether this class contains either an InstBlockId (other than
- // `None`) or an error.
- //
- // An error is treated as a value (as same for the singleton error `InstId`),
- // but it can not actually be materialized as an error value outside of this
- // class.
- auto has_value() const -> bool {
- return has_error_value() || inst_block_id_.has_value();
- }
- // Returns whether this class contains an error value.
- auto has_error_value() const -> bool { return error_; }
- // Returns the id of a non-empty inst block, or `None` if `has_value()` is
- // false.
- //
- // Only valid to call if `has_error_value()` is false.
- auto inst_block_id() const -> InstBlockId {
- CARBON_CHECK(!has_error_value());
- return inst_block_id_;
- }
- private:
- InstBlockIdOrError(InstBlockId inst_block_id, bool error)
- : inst_block_id_(inst_block_id), error_(error) {}
- InstBlockId inst_block_id_;
- bool error_;
- };
- // An ID of an instruction block that is referenced absolutely by an
- // instruction. This should only be used as the type of a field within a typed
- // instruction class. See AbsoluteInstId.
- class AbsoluteInstBlockId : public InstBlockId {
- public:
- // Support implicit conversion from InstBlockId so that InstBlockId and
- // AbsoluteInstBlockId have the same interface.
- explicit(false) constexpr AbsoluteInstBlockId(InstBlockId inst_block_id)
- : InstBlockId(inst_block_id) {}
- using InstBlockId::InstBlockId;
- };
- // An ID of an instruction block that is used as the declaration block within a
- // declaration instruction. This is a block that is nested within the
- // instruction, but doesn't contribute to its value. Such blocks are not
- // included in the fingerprint of the declaration. This should only be used as
- // the type of a field within a typed instruction class.
- class DeclInstBlockId : public InstBlockId {
- public:
- // Support implicit conversion from InstBlockId so that InstBlockId and
- // DeclInstBlockId have the same interface.
- explicit(false) constexpr DeclInstBlockId(InstBlockId inst_block_id)
- : InstBlockId(inst_block_id) {}
- using InstBlockId::InstBlockId;
- };
- // An ID of an instruction block that is used as a label in a branch instruction
- // or similar. This is a block that is not nested within the instruction, but
- // instead exists elsewhere in the enclosing executable region. This should
- // only be used as the type of a field within a typed instruction class.
- class LabelId : public InstBlockId {
- public:
- // Support implicit conversion from InstBlockId so that InstBlockId and
- // LabelId have the same interface.
- explicit(false) constexpr LabelId(InstBlockId inst_block_id)
- : InstBlockId(inst_block_id) {}
- using InstBlockId::InstBlockId;
- };
- // The ID of an `ExprRegion`.
- // TODO: Move this out of sem_ir and into check, if we don't wind up using it
- // in the SemIR for expression patterns.
- struct ExprRegionId : public IdBase<ExprRegionId> {
- static constexpr llvm::StringLiteral Label = "region";
- using IdBase::IdBase;
- };
- // The ID of a `StructTypeField` block.
- struct StructTypeFieldsId : public IdBase<StructTypeFieldsId> {
- static constexpr llvm::StringLiteral Label = "struct_type_fields";
- // The canonical empty block, reused to avoid allocating empty vectors. Always
- // the 0-index block.
- static const StructTypeFieldsId Empty;
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- inline constexpr StructTypeFieldsId StructTypeFieldsId::Empty =
- StructTypeFieldsId(0);
- // The ID of a `CustomLayout` block.
- struct CustomLayoutId : public IdBase<CustomLayoutId> {
- static constexpr llvm::StringLiteral Label = "custom_layout";
- // The canonical empty block. This is never used, but needed by
- // BlockValueStore.
- static const CustomLayoutId Empty;
- // The index in a custom layout of the overall size field.
- static constexpr int SizeIndex = 0;
- // The index in a custom layout of the overall alignment field.
- static constexpr int AlignIndex = 1;
- // The index in a custom layout of the offset of the first struct field.
- static constexpr int FirstFieldIndex = 2;
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- inline constexpr CustomLayoutId CustomLayoutId::Empty = CustomLayoutId(0);
- // The ID of a type.
- struct TypeId : public IdBase<TypeId> {
- static constexpr llvm::StringLiteral Label = "type";
- // `StringifyConstantInst` is used for diagnostics. However, where possible,
- // an `InstId` describing how the type was written should be preferred, using
- // `InstIdAsType` or `TypeOfInstId` as the diagnostic argument type.
- using DiagnosticType = Diagnostics::TypeInfo<std::string>;
- using IdBase::IdBase;
- // Returns the ID of the type corresponding to the constant `const_id`, which
- // must be of type `type`. As an exception, the type `Error` is of type
- // `Error`.
- static constexpr auto ForTypeConstant(ConstantId const_id) -> TypeId {
- return TypeId(const_id.index);
- }
- // Returns the constant ID that defines the type.
- auto AsConstantId() const -> ConstantId { return ConstantId(index); }
- // Returns whether this represents a symbolic type. Requires has_value.
- auto is_symbolic() const -> bool { return AsConstantId().is_symbolic(); }
- // Returns whether this represents a concrete type. Requires has_value.
- auto is_concrete() const -> bool { return AsConstantId().is_concrete(); }
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- // The ID of a `clang::SourceLocation`.
- struct ClangSourceLocId : public IdBase<ClangSourceLocId> {
- static constexpr llvm::StringLiteral Label = "clang_source_loc";
- using IdBase::IdBase;
- };
- // An index for element access, for structs, tuples, and classes.
- struct ElementIndex : public IndexBase<ElementIndex> {
- static constexpr llvm::StringLiteral Label = "element";
- using IndexBase::IndexBase;
- };
- // The ID of a library name. This is either a string literal or `default`.
- struct LibraryNameId : public IdBase<LibraryNameId> {
- static constexpr llvm::StringLiteral Label = "library_name";
- using DiagnosticType = Diagnostics::TypeInfo<std::string>;
- // The name of `default`.
- static const LibraryNameId Default;
- // Track cases where the library name was set, but has been diagnosed and
- // shouldn't be used anymore.
- static const LibraryNameId Error;
- // Returns the LibraryNameId for a library name as a string literal.
- static auto ForStringLiteralValueId(StringLiteralValueId id) -> LibraryNameId;
- using IdBase::IdBase;
- // Converts a LibraryNameId back to a string literal.
- auto AsStringLiteralValueId() const -> StringLiteralValueId {
- CARBON_CHECK(index >= NoneIndex, "{0} must be handled directly", *this);
- return StringLiteralValueId(index);
- }
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- inline constexpr LibraryNameId LibraryNameId::Default =
- LibraryNameId(NoneIndex - 1);
- inline constexpr LibraryNameId LibraryNameId::Error =
- LibraryNameId(NoneIndex - 2);
- // The ID of an `ImportIRInst`.
- struct ImportIRInstId : public IdBase<ImportIRInstId> {
- static constexpr llvm::StringLiteral Label = "import_ir_inst";
- // The maximum ID, non-inclusive. This is constrained to fit inside LocId.
- static constexpr int Max =
- -(std::numeric_limits<int32_t>::min() + 2 * Parse::NodeId::Max + 1);
- constexpr explicit ImportIRInstId(int32_t index) : IdBase(index) {
- CARBON_DCHECK(index < Max, "Index out of range: {0}", index);
- }
- };
- // The ID of a `RequireImpls`.
- struct RequireImplsId : public IdBase<RequireImplsId> {
- static constexpr llvm::StringLiteral Label = "require";
- using IdBase::IdBase;
- };
- // The ID of a `RequireImplsId` block.
- struct RequireImplsBlockId : public IdBase<RequireImplsBlockId> {
- static constexpr llvm::StringLiteral Label = "require_block";
- // The canonical empty block, reused to avoid allocating empty vectors. Always
- // the 0-index block.
- static const RequireImplsBlockId Empty;
- using IdBase::IdBase;
- auto Print(llvm::raw_ostream& out) const -> void;
- };
- inline constexpr RequireImplsBlockId RequireImplsBlockId::Empty =
- RequireImplsBlockId(0);
- // A SemIR location used as the location of instructions. This contains either a
- // InstId, NodeId, ImportIRInstId, or None. The intent is that any of these can
- // indicate the source of an instruction, and also be used to associate a line
- // in diagnostics.
- //
- // The structure is:
- // - None: The standard NoneIndex for all Id types, -1.
- // - InstId: Positive values including zero; a full 31 bits.
- // - [0, 1 << 31)
- // - NodeId: Negative values starting after None; the 24 bit NodeId range.
- // - [-2, -2 - (1 << 24))
- // - Desugared NodeId: Another 24 bit NodeId range.
- // - [-2 - (1 << 24), -2 - (1 << 25))
- // - ImportIRInstId: Remaining negative values; after NodeId, fills out negative
- // values.
- // - [-2 - (1 << 25), -(1 << 31)]
- //
- // For desugaring, use `InstStore::GetLocIdForDesugaring()`.
- struct LocId : public IdBase<LocId> {
- // The contained index kind.
- enum class Kind {
- None,
- ImportIRInstId,
- InstId,
- NodeId,
- };
- static constexpr llvm::StringLiteral Label = "loc";
- using IdBase::IdBase;
- explicit(false) constexpr LocId(ImportIRInstId import_ir_inst_id)
- : IdBase(import_ir_inst_id.has_value()
- ? FirstImportIRInstId - import_ir_inst_id.index
- : NoneIndex) {}
- explicit constexpr LocId(InstId inst_id) : IdBase(inst_id.index) {}
- explicit(false) constexpr LocId(Parse::NoneNodeId /*none*/)
- : IdBase(NoneIndex) {}
- explicit(false) constexpr LocId(Parse::NodeId node_id)
- : IdBase(FirstNodeId - node_id.index) {}
- // Forms an equivalent LocId for a desugared location. Prefer calling
- // `InstStore::GetLocIdForDesugaring`.
- auto AsDesugared() const -> LocId {
- // This should only be called for NodeId or ImportIRInstId (i.e. canonical
- // locations), but we only set the flag for NodeId.
- CARBON_CHECK(kind() != Kind::InstId, "Use InstStore::GetDesugaredLocId");
- if (index <= FirstNodeId && index > FirstDesugaredNodeId) {
- return LocId(index - Parse::NodeId::Max);
- }
- return *this;
- }
- // Returns the kind of the `LocId`.
- auto kind() const -> Kind {
- if (!has_value()) {
- return Kind::None;
- }
- if (index >= 0) {
- return Kind::InstId;
- }
- if (index <= FirstImportIRInstId) {
- return Kind::ImportIRInstId;
- }
- return Kind::NodeId;
- }
- // Returns true if the location corresponds to desugared instructions.
- // Requires a non-`InstId` location.
- auto is_desugared() const -> bool {
- return index <= FirstDesugaredNodeId && index > FirstImportIRInstId;
- }
- // Returns the equivalent `ImportIRInstId` when `kind()` matches or is `None`.
- // Note that the returned `ImportIRInstId` only identifies a location; it is
- // not correct to interpret it as the instruction from which another
- // instruction was imported. Use `InstStore::GetImportSource` for that.
- auto import_ir_inst_id() const -> ImportIRInstId {
- if (!has_value()) {
- return ImportIRInstId::None;
- }
- CARBON_CHECK(kind() == Kind::ImportIRInstId, "{0}", index);
- return ImportIRInstId(FirstImportIRInstId - index);
- }
- // Returns the equivalent `InstId` when `kind()` matches or is `None`.
- auto inst_id() const -> InstId {
- CARBON_CHECK(kind() == Kind::None || kind() == Kind::InstId, "{0}", index);
- return InstId(index);
- }
- // Returns the equivalent `NodeId` when `kind()` matches or is `None`.
- auto node_id() const -> Parse::NodeId {
- if (!has_value()) {
- return Parse::NodeId::None;
- }
- CARBON_CHECK(kind() == Kind::NodeId, "{0}", index);
- if (index <= FirstDesugaredNodeId) {
- return Parse::NodeId(FirstDesugaredNodeId - index);
- } else {
- return Parse::NodeId(FirstNodeId - index);
- }
- }
- auto Print(llvm::raw_ostream& out) const -> void;
- private:
- // The value of the 0 index for each of `NodeId` and `ImportIRInstId`.
- static constexpr int32_t FirstNodeId = NoneIndex - 1;
- static constexpr int32_t FirstDesugaredNodeId =
- FirstNodeId - Parse::NodeId::Max;
- static constexpr int32_t FirstImportIRInstId =
- FirstDesugaredNodeId - Parse::NodeId::Max;
- };
- // Polymorphic id for fields in `Any[...]` typed instruction category. Used for
- // fields where the specific instruction structs have different field types in
- // that position or do not have a field in that position at all. Allows
- // conversion with `Inst::As<>` from the specific typed instruction to the
- // `Any[...]` instruction category.
- //
- // This type participates in `Inst::FromRaw` in order to convert from specific
- // instructions to an `Any[...]` instruction category:
- // - In the case the specific instruction has a field of some `IdKind` in the
- // same position, the `Any[...]` type will hold its raw value in the
- // `AnyRawId` field.
- // - In the case the specific instruction has no field in the same position, the
- // `Any[...]` type will hold a default constructed `AnyRawId` with a `None`
- // value.
- struct AnyRawId : public AnyIdBase {
- // For IdKind.
- static constexpr llvm::StringLiteral Label = "any_raw";
- constexpr explicit AnyRawId() : AnyIdBase(AnyIdBase::NoneIndex) {}
- constexpr explicit AnyRawId(int32_t id) : AnyIdBase(id) {}
- };
- } // namespace Carbon::SemIR
- #endif // CARBON_TOOLCHAIN_SEM_IR_IDS_H_
|