Remove labels from the builtin inst kind macro (#4558)

This is stamping out the per-instruction structs, similar to what we do
elsewhere. `BuiltinInstKind::label` then finishes shifting to
`InstKind::ir_name`.
This commit is contained in:
Jon Ross-Perkins
2024-11-22 00:59:49 +00:00
committed by GitHub
parent e42b377cf6
commit be5db6e1cd
10 changed files with 216 additions and 113 deletions
+4 -3
View File
@@ -56,8 +56,9 @@ auto Mangler::MangleInverseQualifiedNameScope(llvm::raw_ostream& os,
names_to_render.push_back(
{.name_scope_id = interface.scope_id, .prefix = ':'});
auto self_inst_id = constant_values().GetConstantInstId(impl.self_id);
CARBON_KIND_SWITCH(insts().Get(self_inst_id)) {
auto self_inst =
insts().Get(constant_values().GetConstantInstId(impl.self_id));
CARBON_KIND_SWITCH(self_inst) {
case CARBON_KIND(SemIR::ClassType class_type): {
auto next_name_scope_id =
sem_ir().classes().Get(class_type.class_id).scope_id;
@@ -76,7 +77,7 @@ auto Mangler::MangleInverseQualifiedNameScope(llvm::raw_ostream& os,
case SemIR::TypeType::Kind:
case SemIR::VtableType::Kind:
case SemIR::WitnessType::Kind: {
os << self_inst_id.builtin_inst_kind().label();
os << self_inst.kind().ir_name();
break;
}
case CARBON_KIND(SemIR::IntType int_type): {
+1 -9
View File
@@ -7,17 +7,9 @@
namespace Carbon::SemIR {
CARBON_DEFINE_ENUM_CLASS_NAMES(BuiltinInstKind) = {
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) \
CARBON_ENUM_CLASS_NAME_STRING(Name)
#include "toolchain/sem_ir/inst_kind.def"
};
auto BuiltinInstKind::label() -> llvm::StringRef {
static constexpr llvm::StringLiteral Labels[] = {
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, Label) Label,
#include "toolchain/sem_ir/inst_kind.def"
};
return Labels[AsInt()];
}
} // namespace Carbon::SemIR
+4 -8
View File
@@ -12,22 +12,18 @@
namespace Carbon::SemIR {
CARBON_DEFINE_RAW_ENUM_CLASS(BuiltinInstKind, uint8_t) {
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \
CARBON_RAW_ENUM_ENUMERATOR(Name)
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) CARBON_RAW_ENUM_ENUMERATOR(Name)
#include "toolchain/sem_ir/inst_kind.def"
};
class BuiltinInstKind : public CARBON_ENUM_BASE(BuiltinInstKind) {
public:
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \
CARBON_ENUM_CONSTANT_DECL(Name)
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) CARBON_ENUM_CONSTANT_DECL(Name)
#include "toolchain/sem_ir/inst_kind.def"
auto label() -> llvm::StringRef;
// The count of enum values excluding Invalid.
static constexpr uint8_t ValidCount = 0
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) +1
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) +1
#include "toolchain/sem_ir/inst_kind.def"
;
@@ -36,7 +32,7 @@ class BuiltinInstKind : public CARBON_ENUM_BASE(BuiltinInstKind) {
using EnumBase::FromInt;
};
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) \
CARBON_ENUM_CONSTANT_DEFINITION(BuiltinInstKind, Name)
#include "toolchain/sem_ir/inst_kind.def"
+1 -1
View File
@@ -43,7 +43,7 @@ File::File(CheckIRId check_ir_id, IdentifierId package_id,
// Error uses a self-referential type so that it's not accidentally treated as
// a normal type. Every other builtin is a type, including the
// self-referential TypeType.
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) \
insts_.AddInNoBlock(LocIdAndInst::NoLoc<Name>( \
{.type_id = BuiltinInstKind::Name == BuiltinInstKind::ErrorInst \
? TypeId::Error \
-2
View File
@@ -1021,8 +1021,6 @@ class FormatterImpl {
auto FormatArg(BoolValue v) -> void { out_ << v; }
auto FormatArg(BuiltinInstKind kind) -> void { out_ << kind.label(); }
auto FormatArg(EntityNameId id) -> void {
const auto& info = sem_ir_.entity_names().Get(id);
FormatName(info.name_id);
+3 -4
View File
@@ -40,8 +40,7 @@ struct InstId : public IdBase, public Printable<InstId> {
static const InstId Invalid;
// Builtin inst IDs.
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \
static const InstId Builtin##Name;
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) static const InstId Builtin##Name;
#include "toolchain/sem_ir/inst_kind.def"
// The namespace for a `package` expression.
@@ -83,8 +82,8 @@ struct InstId : public IdBase, public Printable<InstId> {
constexpr InstId InstId::Invalid = InstId(InvalidIndex);
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) \
constexpr InstId InstId::Builtin##Name = \
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) \
constexpr InstId InstId::Builtin##Name = \
InstId::ForBuiltin(BuiltinInstKind::Name);
#include "toolchain/sem_ir/inst_kind.def"
+16 -55
View File
@@ -13,9 +13,9 @@
//
// Temporarily, we have CARBON_SEM_IR_BUILTIN_INST_KIND too:
//
// - CARBON_SEM_IR_BUILTIN_INST_KIND(Name, Label)
// Defines a non-Invalid builtin type. The label is used for stringifying
// types. Falls back to CARBON_SEM_IR_INST_KIND if not defined.
// - CARBON_SEM_IR_BUILTIN_INST_KIND(Name)
// Defines a non-Invalid builtin type. Falls back to CARBON_SEM_IR_INST_KIND
// if not defined.
//
// TODO: Merge builtin instructions into the standard CARBON_SEM_IR_INST_KIND,
// tracking the "builtin" annotation separately. This approach is used for
@@ -25,7 +25,7 @@
// CARBON_SEM_IR_INST_KIND. However, if it's provided, make
// CARBON_SEM_IR_INST_KIND optional. Per the above TODO, this is temporary.
#ifndef CARBON_SEM_IR_BUILTIN_INST_KIND
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, ...) CARBON_SEM_IR_INST_KIND(Name)
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name) CARBON_SEM_IR_INST_KIND(Name)
#else
#ifndef CARBON_SEM_IR_INST_KIND
#define CARBON_SEM_IR_INST_KIND(Name)
@@ -36,57 +36,18 @@
#error "Must define the x-macro to use this file."
#endif
// Tracks expressions which are valid as types.
// This has a deliberately self-referential type.
CARBON_SEM_IR_BUILTIN_INST_KIND(TypeType, "type")
// Used when a semantic error has been detected, and a SemIR InstId is still
// required. For example, when there is a type checking issue, this will be used
// in the type_id. It's typically used as a cue that semantic checking doesn't
// need to issue further diagnostics.
CARBON_SEM_IR_BUILTIN_INST_KIND(ErrorInst, "<error>")
// Used for the type of patterns that do not match a fixed type.
CARBON_SEM_IR_BUILTIN_INST_KIND(AutoType, "auto")
// -----------------------------------------------------------------------------
// TODO: Below CARBON_SEM_IR_BUILTIN_INST_KIND types are all placeholders. While
// the above may last, the below are expected to need to change in order to
// better reflect Carbon's design. Keeping distinct placeholders can help find
// usages for later fixes.
// -----------------------------------------------------------------------------
// The type of bool literals and branch conditions, bool.
CARBON_SEM_IR_BUILTIN_INST_KIND(BoolType, "bool")
// An arbitrary-precision integer type, which is used as the type of integer
// literals and as the parameter type of `Core.Int` and `Core.Float`. This type
// only provides compile-time operations, and is represented as an empty type at
// runtime.
CARBON_SEM_IR_BUILTIN_INST_KIND(IntLiteralType, "Core.IntLiteral")
// The legacy float type. This is currently used for real literals, and is
// treated as f64. It's separate from `FloatType`, and should change to mirror
// integers, likely replacing this with a `FloatLiteralType`.
CARBON_SEM_IR_BUILTIN_INST_KIND(LegacyFloatType, "f64")
// The type of string values and String literals.
CARBON_SEM_IR_BUILTIN_INST_KIND(StringType, "String")
// The type of bound method values.
CARBON_SEM_IR_BUILTIN_INST_KIND(BoundMethodType, "<bound method>")
// The type of specific functions.
CARBON_SEM_IR_BUILTIN_INST_KIND(SpecificFunctionType, "<specific function>")
// The type of namespace and imported package names.
CARBON_SEM_IR_BUILTIN_INST_KIND(NamespaceType, "<namespace>")
// The type of witnesses.
CARBON_SEM_IR_BUILTIN_INST_KIND(WitnessType, "<witness>")
// The type of virtual function tables
CARBON_SEM_IR_BUILTIN_INST_KIND(VtableType, "<vtable>")
CARBON_SEM_IR_BUILTIN_INST_KIND(TypeType)
CARBON_SEM_IR_BUILTIN_INST_KIND(ErrorInst)
CARBON_SEM_IR_BUILTIN_INST_KIND(AutoType)
CARBON_SEM_IR_BUILTIN_INST_KIND(BoolType)
CARBON_SEM_IR_BUILTIN_INST_KIND(IntLiteralType)
CARBON_SEM_IR_BUILTIN_INST_KIND(LegacyFloatType)
CARBON_SEM_IR_BUILTIN_INST_KIND(StringType)
CARBON_SEM_IR_BUILTIN_INST_KIND(BoundMethodType)
CARBON_SEM_IR_BUILTIN_INST_KIND(SpecificFunctionType)
CARBON_SEM_IR_BUILTIN_INST_KIND(NamespaceType)
CARBON_SEM_IR_BUILTIN_INST_KIND(WitnessType)
CARBON_SEM_IR_BUILTIN_INST_KIND(VtableType)
// For each instruction kind declared here there is a matching definition in
// `typed_insts.h`.
+1 -1
View File
@@ -146,7 +146,7 @@ auto InstNamer::GetNameFor(ScopeId scope_id, InstId inst_id) const
// Check for a builtin.
if (inst_id.is_builtin()) {
return inst_id.builtin_inst_kind().label().str();
return sem_ir_.insts().Get(inst_id).kind().ir_name().str();
}
if (inst_id == InstId::PackageNamespace) {
+16 -18
View File
@@ -76,12 +76,6 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id)
continue;
}
// Builtins have designated labels.
if (step.inst_id.is_builtin()) {
out << step.inst_id.builtin_inst_kind().label();
continue;
}
const auto& sem_ir = step.sem_ir;
// Helper for instructions with the current sem_ir.
auto push_inst_id = [&](InstId inst_id) {
@@ -120,6 +114,22 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id)
auto untyped_inst = sem_ir.insts().Get(step.inst_id);
CARBON_KIND_SWITCH(untyped_inst) {
case SemIR::AutoType::Kind:
case SemIR::BoolType::Kind:
case SemIR::BoundMethodType::Kind:
case SemIR::ErrorInst::Kind:
case SemIR::IntLiteralType::Kind:
case SemIR::LegacyFloatType::Kind:
case SemIR::NamespaceType::Kind:
case SemIR::SpecificFunctionType::Kind:
case SemIR::StringType::Kind:
case SemIR::TypeType::Kind:
case SemIR::VtableType::Kind:
case SemIR::WitnessType::Kind: {
// Builtin instructions use their IR name as a label.
out << untyped_inst.kind().ir_name();
break;
}
case CARBON_KIND(ArrayType inst): {
if (step.index == 0) {
out << "[";
@@ -346,16 +356,13 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id)
case Assign::Kind:
case AssociatedConstantDecl::Kind:
case AssociatedEntity::Kind:
case AutoType::Kind:
case BaseDecl::Kind:
case BindName::Kind:
case BindValue::Kind:
case BindingPattern::Kind:
case BlockArg::Kind:
case BoolLiteral::Kind:
case BoolType::Kind:
case BoundMethod::Kind:
case BoundMethodType::Kind:
case Branch::Kind:
case BranchIf::Kind:
case BranchWithArg::Kind:
@@ -366,7 +373,6 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id)
case CompleteTypeWitness::Kind:
case Converted::Kind:
case Deref::Kind:
case ErrorInst::Kind:
case FieldDecl::Kind:
case FloatLiteral::Kind:
case FunctionDecl::Kind:
@@ -375,14 +381,11 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id)
case ImportRefLoaded::Kind:
case ImportRefUnloaded::Kind:
case InitializeFrom::Kind:
case IntLiteralType::Kind:
case IntValue::Kind:
case InterfaceDecl::Kind:
case InterfaceWitness::Kind:
case InterfaceWitnessAccess::Kind:
case LegacyFloatType::Kind:
case Namespace::Kind:
case NamespaceType::Kind:
case OutParam::Kind:
case OutParamPattern::Kind:
case RequirementEquivalent::Kind:
@@ -394,10 +397,8 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id)
case ReturnSlotPattern::Kind:
case SpecificConstant::Kind:
case SpecificFunction::Kind:
case SpecificFunctionType::Kind:
case SpliceBlock::Kind:
case StringLiteral::Kind:
case StringType::Kind:
case StructAccess::Kind:
case StructInit::Kind:
case StructLiteral::Kind:
@@ -409,15 +410,12 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id)
case TupleInit::Kind:
case TupleLiteral::Kind:
case TupleValue::Kind:
case TypeType::Kind:
case UnaryOperatorNot::Kind:
case ValueAsRef::Kind:
case ValueOfInitializer::Kind:
case ValueParam::Kind:
case ValueParamPattern::Kind:
case VarStorage::Kind:
case VtableType::Kind:
case WitnessType::Kind:
// We don't know how to print this instruction, but it might have a
// constant value that we can print.
auto const_inst_id =
+170 -12
View File
@@ -45,19 +45,32 @@
namespace Carbon::SemIR {
// A builtin instruction, corresponding to instructions like
// InstId::BuiltinTypeType.
// Used for the type of patterns that do not match a fixed type.
//
// Builtins don't have a parse node associated with them.
#define CARBON_SEM_IR_BUILTIN_INST_KIND(Name, Label) \
struct Name { \
static constexpr auto Kind = InstKind::Name.Define<Parse::InvalidNodeId>( \
{.ir_name = Label, \
.is_type = InstIsType::Always, \
.constant_kind = InstConstantKind::Always}); \
TypeId type_id; \
};
#include "toolchain/sem_ir/inst_kind.def"
// TODO: Annotate as a builtin.
struct AutoType {
static constexpr auto Kind = InstKind::AutoType.Define<Parse::InvalidNodeId>(
{.ir_name = "auto",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// The type of bool literals and branch conditions, bool.
//
// Although this is a builtin, it may still evolve to a more standard type and
// be removed.
//
// TODO: Annotate as a builtin.
struct BoolType {
static constexpr auto Kind = InstKind::BoolType.Define<Parse::InvalidNodeId>(
{.ir_name = "bool",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// An adapted type declaration in a class, of the form `adapt T;`.
struct AdaptDecl {
@@ -370,6 +383,20 @@ struct BoundMethod {
InstId function_id;
};
// The type of bound method values.
//
// Although this is a builtin, it may still evolve to a more standard type and
// be removed.
struct BoundMethodType {
static constexpr auto Kind =
InstKind::BoundMethodType.Define<Parse::InvalidNodeId>(
{.ir_name = "<bound method>",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// Common representation for all kinds of `Branch*` node.
struct AnyBranch {
static constexpr InstKind Kinds[] = {InstKind::Branch, InstKind::BranchIf,
@@ -535,6 +562,21 @@ struct Deref {
InstId pointer_id;
};
// Used when a semantic error has been detected, and a SemIR InstId is still
// required. For example, when there is a type checking issue, this will be used
// in the type_id. It's typically used as a cue that semantic checking doesn't
// need to issue further diagnostics.
//
// TODO: Annotate as a builtin.
struct ErrorInst {
static constexpr auto Kind = InstKind::ErrorInst.Define<Parse::InvalidNodeId>(
{.ir_name = "<error>",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// An `export bind_name` declaration.
struct ExportDecl {
static constexpr auto Kind =
@@ -624,6 +666,22 @@ struct FloatType {
InstId bit_width_id;
};
// The legacy float type. This is currently used for real literals, and is
// treated as f64. It's separate from `FloatType`, and should change to mirror
// integers, likely replacing this with a `FloatLiteralType`.
//
// Although this is a builtin, it may still evolve to a more standard type and
// be removed.
struct LegacyFloatType {
static constexpr auto Kind =
InstKind::LegacyFloatType.Define<Parse::InvalidNodeId>(
{.ir_name = "f64",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// A function declaration.
struct FunctionDecl {
static constexpr auto Kind =
@@ -801,6 +859,23 @@ struct IntValue {
IntId int_id;
};
// An arbitrary-precision integer type, which is used as the type of integer
// literals and as the parameter type of `Core.Int` and `Core.Float`. This type
// only provides compile-time operations, and is represented as an empty type at
// runtime.
//
// Although this is a builtin, it may still evolve to a more standard type and
// be removed.
struct IntLiteralType {
static constexpr auto Kind =
InstKind::IntLiteralType.Define<Parse::InvalidNodeId>(
{.ir_name = "Core.IntLiteral",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// An integer type.
struct IntType {
static constexpr auto Kind = InstKind::IntType.Define<Parse::InvalidNodeId>(
@@ -840,6 +915,20 @@ struct Namespace {
AbsoluteInstId import_id;
};
// The type of namespace and imported package names.
//
// Although this is a builtin, it may still evolve to a more standard type and
// be removed.
struct NamespaceType {
static constexpr auto Kind =
InstKind::NamespaceType.Define<Parse::InvalidNodeId>(
{.ir_name = "<namespace>",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// A parameter for a function or other parameterized block, as exposed in the
// SemIR calling convention. The sub-kinds differ only in their expression
// category.
@@ -1057,6 +1146,20 @@ struct SpecificFunction {
SpecificId specific_id;
};
// The type of specific functions.
//
// Although this is a builtin, it may still evolve to a more standard type and
// be removed.
struct SpecificFunctionType {
static constexpr auto Kind =
InstKind::SpecificFunctionType.Define<Parse::InvalidNodeId>(
{.ir_name = "<specific function>",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// Splices a block into the location where this appears. This may be an
// expression, producing a result with a given type. For example, when
// constructing from aggregates we may figure out which conversions are required
@@ -1081,6 +1184,20 @@ struct StringLiteral {
StringLiteralValueId string_literal_id;
};
// The type of string values and String literals.
//
// Although this is a builtin, it may still evolve to a more standard type and
// be removed.
struct StringType {
static constexpr auto Kind =
InstKind::StringType.Define<Parse::InvalidNodeId>(
{.ir_name = "String",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// Access to a struct type, with the index into the struct_id representation.
struct StructAccess {
// TODO: Make Parse::NodeId more specific.
@@ -1208,6 +1325,19 @@ struct TupleValue {
InstBlockId elements_id;
};
// Tracks expressions which are valid as types. This has a deliberately
// self-referential type.
//
// TODO: Annotate as a builtin.
struct TypeType {
static constexpr auto Kind = InstKind::TypeType.Define<Parse::InvalidNodeId>(
{.ir_name = "type",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// The `not` operator, such as `not operand`.
struct UnaryOperatorNot {
// TODO: Make Parse::NodeId more specific.
@@ -1270,6 +1400,20 @@ struct VarStorage {
NameId name_id;
};
// The type of virtual function tables.
//
// Although this is a builtin, it may still evolve to a more standard type and
// be removed.
struct VtableType {
static constexpr auto Kind =
InstKind::VtableType.Define<Parse::InvalidNodeId>(
{.ir_name = "<vtable>",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// An `expr where requirements` expression.
struct WhereExpr {
static constexpr auto Kind = InstKind::WhereExpr.Define<Parse::WhereExprId>(
@@ -1284,6 +1428,20 @@ struct WhereExpr {
InstBlockId requirements_id;
};
// The type of witnesses.
//
// Although this is a builtin, it may still evolve to a more standard type and
// be removed.
struct WitnessType {
static constexpr auto Kind =
InstKind::WitnessType.Define<Parse::InvalidNodeId>(
{.ir_name = "<witness>",
.is_type = InstIsType::Always,
.constant_kind = InstConstantKind::Always});
TypeId type_id;
};
// These concepts are an implementation detail of the library, not public API.
namespace Internal {