Track the type as written in BaseDecl and AdaptDecl. (#4564)

Represent the type as an `InstId` rather than as a `TypeId` to preserve
how it was written and better support tracking its value in a generic.
Add accessors to `Class` to get the base and adapted type to reduce code
duplication, and add `TypeStore::GetObjectRepr` to make it easier to map
from a type to its possibly-adapted object representation type. In
passing, also move `GetIntTypeInfo` and `GetUnqualifiedType` into
`TypeStore`.

This fixes specifics of generic adapters to properly look at the
specific adapted type, and also fixes importing of adapters.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2024-11-27 22:26:30 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent e0db74a2a1
commit d6ec885eb3
51 changed files with 1530 additions and 415 deletions
+30 -39
View File
@@ -99,30 +99,12 @@ static auto EmitAggregateConstant(ConstantContext& context,
return ConstantType::get(llvm_type, elements);
}
// For each instruction InstT, there is a function below to convert it to an
// `llvm::Constant*`:
// For each instruction InstT that can be emitted as a constant, there is a
// function below to convert it to an `llvm::Constant*`:
//
// auto EmitAsConstant(ConstantContext& context, SemIR::InstT inst)
// -> llvm::Constant*;
template <typename InstT>
requires(InstT::Kind.constant_kind() == SemIR::InstConstantKind::Never ||
InstT::Kind.constant_kind() == SemIR::InstConstantKind::SymbolicOnly)
static auto EmitAsConstant(ConstantContext& /*context*/, InstT inst)
-> llvm::Constant* {
CARBON_FATAL("Unexpected constant instruction kind {0}", inst);
}
// For constants that are always of type `type`, produce the trivial runtime
// representation of type `type`.
template <typename InstT>
requires(InstT::Kind.is_type() == SemIR::InstIsType::Always &&
InstT::Kind.constant_kind() != SemIR::InstConstantKind::SymbolicOnly)
static auto EmitAsConstant(ConstantContext& context, InstT /*inst*/)
-> llvm::Constant* {
return context.GetTypeAsValue();
}
// Represent facet values the same as types.
static auto EmitAsConstant(ConstantContext& context, SemIR::FacetValue /*inst*/)
-> llvm::Constant* {
@@ -197,20 +179,6 @@ static auto EmitAsConstant(ConstantContext& context, SemIR::FloatLiteral inst)
return llvm::ConstantFP::get(context.GetType(inst.type_id), value);
}
static auto EmitAsConstant(ConstantContext& context,
SemIR::InterfaceWitness inst) -> llvm::Constant* {
// TODO: For dynamic dispatch, we might want to lower witness tables as
// constants.
return context.GetUnusedConstant(inst.type_id);
}
static auto EmitAsConstant(ConstantContext& /*context*/,
SemIR::ImplDecl /*inst*/) -> llvm::Constant* {
// An ImplDecl isn't a value, so this constant value won't ever be used.
// It also doesn't even have a type, so we can't use GetUnusedConstant.
return nullptr;
}
static auto EmitAsConstant(ConstantContext& context, SemIR::IntValue inst)
-> llvm::Constant* {
auto* type = context.GetType(inst.type_id);
@@ -226,7 +194,8 @@ static auto EmitAsConstant(ConstantContext& context, SemIR::IntValue inst)
auto val = context.sem_ir().ints().Get(inst.int_id);
int bit_width = int_type->getBitWidth();
bool is_signed = context.sem_ir().GetIntTypeInfo(inst.type_id).is_signed;
bool is_signed =
context.sem_ir().types().GetIntTypeInfo(inst.type_id).is_signed;
return llvm::ConstantInt::get(type, is_signed ? val.sextOrTrunc(bit_width)
: val.zextOrTrunc(bit_width));
}
@@ -246,6 +215,28 @@ static auto EmitAsConstant(ConstantContext& /*context*/,
CARBON_FATAL("TODO: Add support: {0}", inst);
}
// Tries to emit an LLVM constant value for this constant instruction. Centrally
// handles some common cases and then dispatches to the relevant EmitAsConstant
// overload based on the type of the instruction for the remaining cases.
template <typename InstT>
static auto MaybeEmitAsConstant(ConstantContext& context, InstT inst)
-> llvm::Constant* {
if constexpr (InstT::Kind.constant_kind() == SemIR::InstConstantKind::Never ||
InstT::Kind.constant_kind() ==
SemIR::InstConstantKind::SymbolicOnly) {
CARBON_FATAL("Unexpected constant instruction kind {0}", inst);
} else if constexpr (!InstT::Kind.is_lowered()) {
// This instruction has a constant value, but that constant value will never
// be used by lowering.
return nullptr;
} else if constexpr (InstT::Kind.is_type() == SemIR::InstIsType::Always) {
// All types are lowered to the same value.
return context.GetTypeAsValue();
} else {
return EmitAsConstant(context, inst);
}
}
auto LowerConstants(FileContext& file_context,
llvm::MutableArrayRef<llvm::Constant*> constants) -> void {
ConstantContext context(file_context, constants);
@@ -273,10 +264,10 @@ auto LowerConstants(FileContext& file_context,
}
llvm::Constant* value = nullptr;
CARBON_KIND_SWITCH(inst) {
#define CARBON_SEM_IR_INST_KIND(Name) \
case CARBON_KIND(SemIR::Name const_inst): { \
value = EmitAsConstant(context, const_inst); \
break; \
#define CARBON_SEM_IR_INST_KIND(Name) \
case CARBON_KIND(SemIR::Name const_inst): { \
value = MaybeEmitAsConstant(context, const_inst); \
break; \
}
#include "toolchain/sem_ir/inst_kind.def"
}