mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 15:21:04 +01:00
Refactor InstKind to move metadata from macros to the type. (#4119)
This adds `DefinitionInfo` for `Define`-based configuration so that
parameters are optional. It also makes it easier to provide the
equivalent functions on both `Definition` and `Define`.
A common pattern used here is to change from a `switch` with in-line
`case`s to instead have `case`s that call an overloaded function. What's
happening here is that the instruction type is used to select an
overload, and if an overload is not defined, a compiler error would
result. Meanwhile, clusters of overloads are being defined using
`requires`-based templating, so that equivalent implementations are not
copied. This addresses a limitation of a vanilla `switch` approach where
it's hard to have redundant cases using conditional logic, while also
getting compiler errors when adding new `InstKind` entries, which had
been a significant part of why we used macros previously.
This starts hitting some odd clang-format edge cases causing
`CARBON_KIND_SWITCH(inst){` (missing space), which I haven't seen
before. Adding `CARBON_KIND_SWITCH` to .clang-format works around it.
This commit is contained in:
@@ -60,6 +60,17 @@ static auto FatalErrorIfEncountered(InstT inst) -> void {
|
||||
<< inst;
|
||||
}
|
||||
|
||||
// For instructions that are always of type `type`, produce the trivial runtime
|
||||
// representation of type `type`.
|
||||
static auto SetTrivialType(FunctionContext& context, SemIR::InstId inst_id)
|
||||
-> void {
|
||||
context.SetLocal(inst_id, context.GetTypeAsValue());
|
||||
}
|
||||
|
||||
// TODO: Consider renaming Handle##Name, instead relying on typed_inst overload
|
||||
// resolution. That would allow putting the nonexistent handler implementations
|
||||
// in `requires`-style overloads.
|
||||
// NOLINTNEXTLINE(readability-function-size): The define confuses lint.
|
||||
auto FunctionContext::LowerInst(SemIR::InstId inst_id) -> void {
|
||||
// Skip over constants. `FileContext::GetGlobal` lowers them as needed.
|
||||
if (sem_ir().constant_values().Get(inst_id).is_constant()) {
|
||||
@@ -69,25 +80,29 @@ auto FunctionContext::LowerInst(SemIR::InstId inst_id) -> void {
|
||||
auto inst = sem_ir().insts().Get(inst_id);
|
||||
CARBON_VLOG() << "Lowering " << inst_id << ": " << inst << "\n";
|
||||
builder_.getInserter().SetCurrentInstId(inst_id);
|
||||
|
||||
CARBON_KIND_SWITCH(inst) {
|
||||
#define CARBON_SEM_IR_INST_KIND_CONSTANT_ALWAYS(Name)
|
||||
#define CARBON_SEM_IR_INST_KIND(Name) \
|
||||
case CARBON_KIND(SemIR::Name typed_inst): { \
|
||||
if constexpr (SemIR::Name::Kind.is_lowered()) { \
|
||||
Handle##Name(*this, inst_id, typed_inst); \
|
||||
} else { \
|
||||
FatalErrorIfEncountered(typed_inst); \
|
||||
} \
|
||||
break; \
|
||||
#define CARBON_SEM_IR_INST_KIND(Name) \
|
||||
case CARBON_KIND(SemIR::Name typed_inst): { \
|
||||
if constexpr (!SemIR::Name::Kind.is_lowered()) { \
|
||||
FatalErrorIfEncountered(typed_inst); \
|
||||
} else if constexpr (SemIR::Name::Kind.constant_kind() == \
|
||||
SemIR::InstConstantKind::Always) { \
|
||||
CARBON_FATAL() << "Missing constant value for constant instruction " \
|
||||
<< inst; \
|
||||
} else if constexpr (SemIR::Name::Kind.is_type() == \
|
||||
SemIR::InstIsType::Always) { \
|
||||
SetTrivialType(*this, inst_id); \
|
||||
} else { \
|
||||
Handle##Name(*this, inst_id, typed_inst); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
#include "toolchain/sem_ir/inst_kind.def"
|
||||
|
||||
default:
|
||||
CARBON_FATAL() << "Missing constant value for constant instruction "
|
||||
<< inst;
|
||||
}
|
||||
|
||||
builder_.getInserter().SetCurrentInstId(SemIR::InstId::Invalid);
|
||||
} // namespace Carbon::Lower
|
||||
}
|
||||
|
||||
auto FunctionContext::GetBlockArg(SemIR::InstBlockId block_id,
|
||||
SemIR::TypeId type_id) -> llvm::PHINode* {
|
||||
|
||||
Reference in New Issue
Block a user