Initialize vptrs to point to vtables (#5244)

Adds a mapping to keep track of vtable LLVM IR decls/defs for use.
Adds the vtable_id to the vtable_ptr initialize instruction for lookup.
Adds emission of vtable declarations for use outside the file that
defines the vtable. (this isn't done lazily, it's done for any imported
class - it could be done lazily & maybe eventually has to be lazy to
handle generics)
This commit is contained in:
David Blaikie
2025-04-05 06:11:34 +00:00
committed by GitHub
parent 8c113c1241
commit 8e7bb2f953
8 changed files with 218 additions and 63 deletions
+27 -21
View File
@@ -156,7 +156,8 @@ static auto ConvertAggregateElement(
llvm::ArrayRef<SemIR::InstId> src_literal_elems,
ConversionTarget::Kind kind, SemIR::InstId target_id,
SemIR::TypeId target_elem_type, PendingBlock* target_block,
size_t src_field_index, size_t target_field_index) -> SemIR::InstId {
size_t src_field_index, size_t target_field_index,
SemIR::InstId vtable_id = SemIR::InstId::None) -> SemIR::InstId {
// Compute the location of the source element. This goes into the current code
// block, not into the target block.
// TODO: Ideally we would discard this instruction if it's unused.
@@ -179,7 +180,7 @@ static auto ConvertAggregateElement(
target.init_id = MakeElementAccessInst<TargetAccessInstT>(
context, loc_id, target_id, target_elem_type, *target_block,
target_field_index);
return Convert(context, loc_id, src_elem_id, target);
return Convert(context, loc_id, src_elem_id, target, vtable_id);
}
// Performs a conversion from a tuple to an array type. This function only
@@ -372,12 +373,10 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type,
// Common implementation for ConvertStructToStruct and ConvertStructToClass.
template <typename TargetAccessInstT>
static auto ConvertStructToStructOrClass(Context& context,
SemIR::StructType src_type,
SemIR::StructType dest_type,
SemIR::InstId value_id,
ConversionTarget target)
-> SemIR::InstId {
static auto ConvertStructToStructOrClass(
Context& context, SemIR::StructType src_type, SemIR::StructType dest_type,
SemIR::InstId value_id, ConversionTarget target,
SemIR::InstId dest_vtable_id = SemIR::InstId::None) -> SemIR::InstId {
static_assert(std::is_same_v<SemIR::ClassElementAccess, TargetAccessInstT> ||
std::is_same_v<SemIR::StructAccess, TargetAccessInstT>);
constexpr bool ToClass =
@@ -466,7 +465,8 @@ static auto ConvertStructToStructOrClass(Context& context,
.base_id = target.init_id,
.index = SemIR::ElementIndex(i)});
auto vtable_ptr_id = AddInst<SemIR::VtablePtr>(
context, value_loc_id, {.type_id = dest_field.type_id});
context, value_loc_id,
{.type_id = dest_field.type_id, .vtable_id = dest_vtable_id});
auto init_id =
AddInst<SemIR::InitializeFrom>(context, value_loc_id,
{.type_id = dest_field.type_id,
@@ -512,7 +512,8 @@ static auto ConvertStructToStructOrClass(Context& context,
ConvertAggregateElement<SemIR::StructAccess, TargetAccessInstT>(
context, value_loc_id, value_id, src_field.type_id, literal_elems,
inner_kind, target.init_id, dest_field.type_id, target.init_block,
src_field_index, src_field_index + dest_vptr_offset);
src_field_index, src_field_index + dest_vptr_offset,
dest_vtable_id);
if (init_id == SemIR::ErrorInst::SingletonInstId) {
return SemIR::ErrorInst::SingletonInstId;
}
@@ -554,10 +555,10 @@ static auto ConvertStructToStruct(Context& context, SemIR::StructType src_type,
// Performs a conversion from a struct to a class type. This function only
// converts the type, and does not perform a final conversion to the requested
// expression category.
static auto ConvertStructToClass(Context& context, SemIR::StructType src_type,
SemIR::ClassType dest_type,
SemIR::InstId value_id,
ConversionTarget target) -> SemIR::InstId {
static auto ConvertStructToClass(
Context& context, SemIR::StructType src_type, SemIR::ClassType dest_type,
SemIR::InstId value_id, ConversionTarget target,
SemIR::InstId dest_vtable_id = SemIR::InstId::None) -> SemIR::InstId {
PendingBlock target_block(&context);
auto& dest_class_info = context.classes().Get(dest_type.class_id);
CARBON_CHECK(dest_class_info.inheritance_kind != SemIR::Class::Abstract);
@@ -580,7 +581,8 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type,
}
auto result_id = ConvertStructToStructOrClass<SemIR::ClassElementAccess>(
context, src_type, dest_struct_type, value_id, target);
context, src_type, dest_struct_type, value_id, target,
dest_vtable_id.has_value() ? dest_vtable_id : dest_class_info.vtable_id);
if (need_temporary) {
target_block.InsertHere();
@@ -778,9 +780,10 @@ static auto DiagnoseConversionFailureToConstraintValue(
}
}
static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
SemIR::InstId value_id,
ConversionTarget target) -> SemIR::InstId {
static auto PerformBuiltinConversion(
Context& context, SemIR::LocId loc_id, SemIR::InstId value_id,
ConversionTarget target, SemIR::InstId vtable_id = SemIR::InstId::None)
-> SemIR::InstId {
auto& sem_ir = context.sem_ir();
auto value = sem_ir.insts().Get(value_id);
auto value_type_id = value.type_id();
@@ -952,7 +955,8 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
.Get(target_class_type->class_id)
.adapt_id.has_value()) {
return ConvertStructToClass(context, *src_struct_type,
*target_class_type, value_id, target);
*target_class_type, value_id, target,
vtable_id);
}
}
@@ -1133,7 +1137,8 @@ auto PerformAction(Context& context, SemIR::LocId loc_id,
}
auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
ConversionTarget target) -> SemIR::InstId {
ConversionTarget target, SemIR::InstId vtable_id)
-> SemIR::InstId {
auto& sem_ir = context.sem_ir();
auto orig_expr_id = expr_id;
@@ -1197,7 +1202,8 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
}
// Check whether any builtin conversion applies.
expr_id = PerformBuiltinConversion(context, loc_id, expr_id, target);
expr_id =
PerformBuiltinConversion(context, loc_id, expr_id, target, vtable_id);
if (expr_id == SemIR::ErrorInst::SingletonInstId) {
return expr_id;
}