mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Add a vtableDecl inst and use that in classes instead of VtablePtr (#5945)
This addresses/avoids the duplicate import of vtables. I went through a few iterations/etc along the way and left them in the commit history for the PR in case any of them are useful to illustrate how I got here, or worth revisiting. Essentially I ended up with a circularity in importing - importing the class imported the vtable_decl which imported the virtual functions - and then pending specifics of the virtual functions needed the self specific of the enclosing class which wasn't ready yet. Adding ImportRef to the vtable_decl to break the cycle caused me trouble when naming the vtable_decl instructions - so I tried making the functions in the vtable unloaded ImportRefs instead. That worked, but meant that importing a class still was doing O(number of vtable entries) even if the vtable wasn't used. So I revisited the lazy vtable_decl - figured out how to make the naming work (when building the vtable_ptr, even though the vtable_decl doesn't have to be loaded for the vtable_ptr, I force it to be loaded anyway, to load the vtable so it's usable by lowering, etc). And then I could go back to the old non-lazy loaded vtable entries (using some loaded ImportRefs in the cases where we needed them/had already adopted them). Then thinking about the VtablePtr instruction, went back/forth on exactly what it needed - went from VtablePtr's member being a VtableDecl InstId, to a ClassId, then back to a VtableId as it was before this patch. Naming the instructions has one oddity, that the VtableDecl and VtablePtr instructions seem to need to add the pending name for the VtableId - despite not using the VtableId in their own name - should the inst namer be doing this work for parameters of instructions rather than requiring the inst to do it deliberately? (or am I holding it wrong in some way?) --------- Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
co-authored by
Richard Smith
parent
7727c62880
commit
3f9fc633fe
+31
-34
@@ -165,7 +165,7 @@ static auto ConvertAggregateElement(
|
||||
ConversionTarget::Kind kind, SemIR::InstId target_id,
|
||||
SemIR::TypeInstId target_elem_type_inst, PendingBlock* target_block,
|
||||
size_t src_field_index, size_t target_field_index,
|
||||
SemIR::InstId vtable_ptr_inst_id = SemIR::InstId::None) -> SemIR::InstId {
|
||||
SemIR::ClassType* vtable_class_type = nullptr) -> SemIR::InstId {
|
||||
auto src_elem_type =
|
||||
context.types().GetTypeIdForTypeInstId(src_elem_type_inst);
|
||||
auto target_elem_type =
|
||||
@@ -193,7 +193,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, vtable_ptr_inst_id);
|
||||
return Convert(context, loc_id, src_elem_id, target, vtable_class_type);
|
||||
}
|
||||
|
||||
// Performs a conversion from a tuple to an array type. This function only
|
||||
@@ -390,7 +390,7 @@ template <typename TargetAccessInstT>
|
||||
static auto ConvertStructToStructOrClass(
|
||||
Context& context, SemIR::StructType src_type, SemIR::StructType dest_type,
|
||||
SemIR::InstId value_id, ConversionTarget target,
|
||||
SemIR::InstId vtable_ptr_inst_id = SemIR::InstId::None) -> SemIR::InstId {
|
||||
SemIR::ClassType* vtable_class_type = nullptr) -> SemIR::InstId {
|
||||
static_assert(std::is_same_v<SemIR::ClassElementAccess, TargetAccessInstT> ||
|
||||
std::is_same_v<SemIR::StructAccess, TargetAccessInstT>);
|
||||
constexpr bool ToClass =
|
||||
@@ -480,11 +480,22 @@ static auto ConvertStructToStructOrClass(
|
||||
{.type_id = vptr_type_id,
|
||||
.base_id = target.init_id,
|
||||
.index = SemIR::ElementIndex(i)});
|
||||
auto init_id =
|
||||
AddInst<SemIR::InitializeFrom>(context, value_loc_id,
|
||||
{.type_id = vptr_type_id,
|
||||
.src_id = vtable_ptr_inst_id,
|
||||
.dest_id = dest_id});
|
||||
auto vtable_decl_id =
|
||||
context.classes().Get(vtable_class_type->class_id).vtable_decl_id;
|
||||
LoadImportRef(context, vtable_decl_id);
|
||||
auto canonical_vtable_decl_id =
|
||||
context.constant_values().GetConstantInstId(vtable_decl_id);
|
||||
auto vtable_ptr_id = AddInst<SemIR::VtablePtr>(
|
||||
context, value_loc_id,
|
||||
{.type_id = GetPointerType(context, SemIR::VtableType::TypeInstId),
|
||||
.vtable_id = context.insts()
|
||||
.GetAs<SemIR::VtableDecl>(canonical_vtable_decl_id)
|
||||
.vtable_id,
|
||||
.specific_id = vtable_class_type->specific_id});
|
||||
auto init_id = AddInst<SemIR::InitializeFrom>(context, value_loc_id,
|
||||
{.type_id = vptr_type_id,
|
||||
.src_id = vtable_ptr_id,
|
||||
.dest_id = dest_id});
|
||||
new_block.Set(i, init_id);
|
||||
continue;
|
||||
}
|
||||
@@ -526,7 +537,7 @@ static auto ConvertStructToStructOrClass(
|
||||
context, value_loc_id, value_id, src_field.type_inst_id,
|
||||
literal_elems, inner_kind, target.init_id, dest_field.type_inst_id,
|
||||
target.init_block, src_field_index,
|
||||
src_field_index + dest_vptr_offset, vtable_ptr_inst_id);
|
||||
src_field_index + dest_vptr_offset, vtable_class_type);
|
||||
if (init_id == SemIR::ErrorInst::InstId) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
@@ -568,10 +579,11 @@ 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 dest_vtable_ptr_inst_id = SemIR::InstId::None)
|
||||
static auto ConvertStructToClass(Context& context, SemIR::StructType src_type,
|
||||
SemIR::ClassType dest_type,
|
||||
SemIR::InstId value_id,
|
||||
ConversionTarget target,
|
||||
SemIR::ClassType* vtable_class_type)
|
||||
-> SemIR::InstId {
|
||||
PendingBlock target_block(&context);
|
||||
auto& dest_class_info = context.classes().Get(dest_type.class_id);
|
||||
@@ -598,24 +610,9 @@ static auto ConvertStructToClass(
|
||||
SemIR::LocId(value_id), {.type_id = target.type_id});
|
||||
}
|
||||
|
||||
if (!dest_vtable_ptr_inst_id.has_value()) {
|
||||
dest_vtable_ptr_inst_id = dest_class_info.vtable_ptr_id;
|
||||
if (dest_type.specific_id.has_value() &&
|
||||
dest_vtable_ptr_inst_id.has_value()) {
|
||||
LoadImportRef(context, dest_vtable_ptr_inst_id);
|
||||
dest_vtable_ptr_inst_id = context.constant_values().GetInstId(
|
||||
GetConstantValueInSpecific(context.sem_ir(), dest_type.specific_id,
|
||||
dest_vtable_ptr_inst_id));
|
||||
}
|
||||
}
|
||||
|
||||
if (dest_vtable_ptr_inst_id.has_value()) {
|
||||
LoadImportRef(context, dest_vtable_ptr_inst_id);
|
||||
}
|
||||
|
||||
auto result_id = ConvertStructToStructOrClass<SemIR::ClassElementAccess>(
|
||||
context, src_type, dest_struct_type, value_id, target,
|
||||
dest_vtable_ptr_inst_id);
|
||||
vtable_class_type ? vtable_class_type : &dest_type);
|
||||
|
||||
if (need_temporary) {
|
||||
target_block.InsertHere();
|
||||
@@ -799,8 +796,8 @@ static auto DiagnoseConversionFailureToConstraintValue(
|
||||
|
||||
static auto PerformBuiltinConversion(
|
||||
Context& context, SemIR::LocId loc_id, SemIR::InstId value_id,
|
||||
ConversionTarget target,
|
||||
SemIR::InstId vtable_ptr_inst_id = SemIR::InstId::None) -> SemIR::InstId {
|
||||
ConversionTarget target, SemIR::ClassType* vtable_class_type = nullptr)
|
||||
-> SemIR::InstId {
|
||||
auto& sem_ir = context.sem_ir();
|
||||
auto value = sem_ir.insts().Get(value_id);
|
||||
auto value_type_id = value.type_id();
|
||||
@@ -974,7 +971,7 @@ static auto PerformBuiltinConversion(
|
||||
.adapt_id.has_value()) {
|
||||
return ConvertStructToClass(context, *src_struct_type,
|
||||
*target_class_type, value_id, target,
|
||||
vtable_ptr_inst_id);
|
||||
vtable_class_type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1201,7 +1198,7 @@ auto PerformAction(Context& context, SemIR::LocId loc_id,
|
||||
}
|
||||
|
||||
auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
|
||||
ConversionTarget target, SemIR::InstId vtable_ptr_inst_id)
|
||||
ConversionTarget target, SemIR::ClassType* vtable_class_type)
|
||||
-> SemIR::InstId {
|
||||
auto& sem_ir = context.sem_ir();
|
||||
auto orig_expr_id = expr_id;
|
||||
@@ -1266,7 +1263,7 @@ 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,
|
||||
vtable_ptr_inst_id);
|
||||
vtable_class_type);
|
||||
if (expr_id == SemIR::ErrorInst::InstId) {
|
||||
return expr_id;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user