Skip to content

Commit 3f9fc63

Browse files
dwblaikiezygoloid
andauthored
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 <[email protected]>
1 parent 7727c62 commit 3f9fc63

File tree

12 files changed

+290
-311
lines changed

12 files changed

+290
-311
lines changed

toolchain/check/class.cpp

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,15 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
145145
// Get some base class/type/specific info.
146146
if (base_class_type) {
147147
auto& base_class_info = context.classes().Get(base_class_type->class_id);
148-
auto base_vtable_ptr_inst_id = base_class_info.vtable_ptr_id;
149-
if (base_vtable_ptr_inst_id.has_value()) {
150-
LoadImportRef(context, base_vtable_ptr_inst_id);
148+
auto base_vtable_decl_inst_id = base_class_info.vtable_decl_id;
149+
if (base_vtable_decl_inst_id.has_value()) {
150+
LoadImportRef(context, base_vtable_decl_inst_id);
151151
auto canonical_base_vtable_inst_id =
152-
context.constant_values().GetConstantInstId(base_vtable_ptr_inst_id);
153-
const auto& base_vtable_ptr_inst =
154-
context.insts().GetAs<SemIR::VtablePtr>(
152+
context.constant_values().GetConstantInstId(base_vtable_decl_inst_id);
153+
const auto& base_vtable_decl_inst =
154+
context.insts().GetAs<SemIR::VtableDecl>(
155155
canonical_base_vtable_inst_id);
156-
base_vtable_id = base_vtable_ptr_inst.vtable_id;
156+
base_vtable_id = base_vtable_decl_inst.vtable_id;
157157
base_class_specific_id = base_class_type->specific_id;
158158
}
159159
}
@@ -187,7 +187,6 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
187187
// TODO: Avoid quadratic search. Perhaps build a map from `NameId` to the
188188
// elements of the top of `vtable_stack`.
189189
for (auto base_vtable_entry_id : base_vtable_inst_block) {
190-
LoadImportRef(context, base_vtable_entry_id);
191190
auto [derived_vtable_entry_id, derived_vtable_entry_const_id, fn_id,
192191
specific_id] =
193192
DecomposeVirtualFunction(context.sem_ir(), base_vtable_entry_id,
@@ -303,15 +302,9 @@ static auto CheckCompleteClassType(
303302
if (class_info.is_dynamic) {
304303
auto vtable_id = BuildVtable(context, node_id, class_id, base_class_type,
305304
vtable_contents);
306-
307305
auto vptr_type_id = GetPointerType(context, SemIR::VtableType::TypeInstId);
308-
auto generic_id = class_info.generic_id;
309-
auto self_specific_id = context.generics().GetSelfSpecific(generic_id);
310-
class_info.vtable_ptr_id =
311-
AddInst<SemIR::VtablePtr>(context, node_id,
312-
{.type_id = vptr_type_id,
313-
.vtable_id = vtable_id,
314-
.specific_id = self_specific_id});
306+
class_info.vtable_decl_id = AddInst<SemIR::VtableDecl>(
307+
context, node_id, {.type_id = vptr_type_id, .vtable_id = vtable_id});
315308
}
316309

317310
auto struct_type_id = GetStructType(

toolchain/check/convert.cpp

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ static auto ConvertAggregateElement(
165165
ConversionTarget::Kind kind, SemIR::InstId target_id,
166166
SemIR::TypeInstId target_elem_type_inst, PendingBlock* target_block,
167167
size_t src_field_index, size_t target_field_index,
168-
SemIR::InstId vtable_ptr_inst_id = SemIR::InstId::None) -> SemIR::InstId {
168+
SemIR::ClassType* vtable_class_type = nullptr) -> SemIR::InstId {
169169
auto src_elem_type =
170170
context.types().GetTypeIdForTypeInstId(src_elem_type_inst);
171171
auto target_elem_type =
@@ -193,7 +193,7 @@ static auto ConvertAggregateElement(
193193
target.init_id = MakeElementAccessInst<TargetAccessInstT>(
194194
context, loc_id, target_id, target_elem_type, *target_block,
195195
target_field_index);
196-
return Convert(context, loc_id, src_elem_id, target, vtable_ptr_inst_id);
196+
return Convert(context, loc_id, src_elem_id, target, vtable_class_type);
197197
}
198198

199199
// Performs a conversion from a tuple to an array type. This function only
@@ -390,7 +390,7 @@ template <typename TargetAccessInstT>
390390
static auto ConvertStructToStructOrClass(
391391
Context& context, SemIR::StructType src_type, SemIR::StructType dest_type,
392392
SemIR::InstId value_id, ConversionTarget target,
393-
SemIR::InstId vtable_ptr_inst_id = SemIR::InstId::None) -> SemIR::InstId {
393+
SemIR::ClassType* vtable_class_type = nullptr) -> SemIR::InstId {
394394
static_assert(std::is_same_v<SemIR::ClassElementAccess, TargetAccessInstT> ||
395395
std::is_same_v<SemIR::StructAccess, TargetAccessInstT>);
396396
constexpr bool ToClass =
@@ -480,11 +480,22 @@ static auto ConvertStructToStructOrClass(
480480
{.type_id = vptr_type_id,
481481
.base_id = target.init_id,
482482
.index = SemIR::ElementIndex(i)});
483-
auto init_id =
484-
AddInst<SemIR::InitializeFrom>(context, value_loc_id,
485-
{.type_id = vptr_type_id,
486-
.src_id = vtable_ptr_inst_id,
487-
.dest_id = dest_id});
483+
auto vtable_decl_id =
484+
context.classes().Get(vtable_class_type->class_id).vtable_decl_id;
485+
LoadImportRef(context, vtable_decl_id);
486+
auto canonical_vtable_decl_id =
487+
context.constant_values().GetConstantInstId(vtable_decl_id);
488+
auto vtable_ptr_id = AddInst<SemIR::VtablePtr>(
489+
context, value_loc_id,
490+
{.type_id = GetPointerType(context, SemIR::VtableType::TypeInstId),
491+
.vtable_id = context.insts()
492+
.GetAs<SemIR::VtableDecl>(canonical_vtable_decl_id)
493+
.vtable_id,
494+
.specific_id = vtable_class_type->specific_id});
495+
auto init_id = AddInst<SemIR::InitializeFrom>(context, value_loc_id,
496+
{.type_id = vptr_type_id,
497+
.src_id = vtable_ptr_id,
498+
.dest_id = dest_id});
488499
new_block.Set(i, init_id);
489500
continue;
490501
}
@@ -526,7 +537,7 @@ static auto ConvertStructToStructOrClass(
526537
context, value_loc_id, value_id, src_field.type_inst_id,
527538
literal_elems, inner_kind, target.init_id, dest_field.type_inst_id,
528539
target.init_block, src_field_index,
529-
src_field_index + dest_vptr_offset, vtable_ptr_inst_id);
540+
src_field_index + dest_vptr_offset, vtable_class_type);
530541
if (init_id == SemIR::ErrorInst::InstId) {
531542
return SemIR::ErrorInst::InstId;
532543
}
@@ -568,10 +579,11 @@ static auto ConvertStructToStruct(Context& context, SemIR::StructType src_type,
568579
// Performs a conversion from a struct to a class type. This function only
569580
// converts the type, and does not perform a final conversion to the requested
570581
// expression category.
571-
static auto ConvertStructToClass(
572-
Context& context, SemIR::StructType src_type, SemIR::ClassType dest_type,
573-
SemIR::InstId value_id, ConversionTarget target,
574-
SemIR::InstId dest_vtable_ptr_inst_id = SemIR::InstId::None)
582+
static auto ConvertStructToClass(Context& context, SemIR::StructType src_type,
583+
SemIR::ClassType dest_type,
584+
SemIR::InstId value_id,
585+
ConversionTarget target,
586+
SemIR::ClassType* vtable_class_type)
575587
-> SemIR::InstId {
576588
PendingBlock target_block(&context);
577589
auto& dest_class_info = context.classes().Get(dest_type.class_id);
@@ -598,24 +610,9 @@ static auto ConvertStructToClass(
598610
SemIR::LocId(value_id), {.type_id = target.type_id});
599611
}
600612

601-
if (!dest_vtable_ptr_inst_id.has_value()) {
602-
dest_vtable_ptr_inst_id = dest_class_info.vtable_ptr_id;
603-
if (dest_type.specific_id.has_value() &&
604-
dest_vtable_ptr_inst_id.has_value()) {
605-
LoadImportRef(context, dest_vtable_ptr_inst_id);
606-
dest_vtable_ptr_inst_id = context.constant_values().GetInstId(
607-
GetConstantValueInSpecific(context.sem_ir(), dest_type.specific_id,
608-
dest_vtable_ptr_inst_id));
609-
}
610-
}
611-
612-
if (dest_vtable_ptr_inst_id.has_value()) {
613-
LoadImportRef(context, dest_vtable_ptr_inst_id);
614-
}
615-
616613
auto result_id = ConvertStructToStructOrClass<SemIR::ClassElementAccess>(
617614
context, src_type, dest_struct_type, value_id, target,
618-
dest_vtable_ptr_inst_id);
615+
vtable_class_type ? vtable_class_type : &dest_type);
619616

620617
if (need_temporary) {
621618
target_block.InsertHere();
@@ -799,8 +796,8 @@ static auto DiagnoseConversionFailureToConstraintValue(
799796

800797
static auto PerformBuiltinConversion(
801798
Context& context, SemIR::LocId loc_id, SemIR::InstId value_id,
802-
ConversionTarget target,
803-
SemIR::InstId vtable_ptr_inst_id = SemIR::InstId::None) -> SemIR::InstId {
799+
ConversionTarget target, SemIR::ClassType* vtable_class_type = nullptr)
800+
-> SemIR::InstId {
804801
auto& sem_ir = context.sem_ir();
805802
auto value = sem_ir.insts().Get(value_id);
806803
auto value_type_id = value.type_id();
@@ -974,7 +971,7 @@ static auto PerformBuiltinConversion(
974971
.adapt_id.has_value()) {
975972
return ConvertStructToClass(context, *src_struct_type,
976973
*target_class_type, value_id, target,
977-
vtable_ptr_inst_id);
974+
vtable_class_type);
978975
}
979976
}
980977

@@ -1201,7 +1198,7 @@ auto PerformAction(Context& context, SemIR::LocId loc_id,
12011198
}
12021199

12031200
auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
1204-
ConversionTarget target, SemIR::InstId vtable_ptr_inst_id)
1201+
ConversionTarget target, SemIR::ClassType* vtable_class_type)
12051202
-> SemIR::InstId {
12061203
auto& sem_ir = context.sem_ir();
12071204
auto orig_expr_id = expr_id;
@@ -1266,7 +1263,7 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
12661263

12671264
// Check whether any builtin conversion applies.
12681265
expr_id = PerformBuiltinConversion(context, loc_id, expr_id, target,
1269-
vtable_ptr_inst_id);
1266+
vtable_class_type);
12701267
if (expr_id == SemIR::ErrorInst::InstId) {
12711268
return expr_id;
12721269
}

toolchain/check/convert.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ struct ConversionTarget {
6767
// type.
6868
auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
6969
ConversionTarget target,
70-
SemIR::InstId vtable_ptr_inst_id = SemIR::InstId::None)
71-
-> SemIR::InstId;
70+
SemIR::ClassType* vtable_class_type = nullptr) -> SemIR::InstId;
7271

7372
// Performs initialization of `target_id` from `value_id`. Returns the
7473
// possibly-converted initializing expression, which should be assigned to the

toolchain/check/import_ref.cpp

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,7 +1649,7 @@ static auto AddClassDefinition(ImportContext& context,
16491649
SemIR::Class& new_class,
16501650
SemIR::InstId complete_type_witness_id,
16511651
SemIR::InstId base_id, SemIR::InstId adapt_id,
1652-
SemIR::InstId vtable_ptr_id) -> void {
1652+
SemIR::InstId vtable_decl_id) -> void {
16531653
new_class.definition_id = new_class.first_owning_decl_id;
16541654

16551655
new_class.complete_type_witness_id = complete_type_witness_id;
@@ -1671,8 +1671,8 @@ static auto AddClassDefinition(ImportContext& context,
16711671
if (import_class.adapt_id.has_value()) {
16721672
new_class.adapt_id = adapt_id;
16731673
}
1674-
if (import_class.vtable_ptr_id.has_value()) {
1675-
new_class.vtable_ptr_id = vtable_ptr_id;
1674+
if (import_class.vtable_decl_id.has_value()) {
1675+
new_class.vtable_decl_id = vtable_decl_id;
16761676
}
16771677
}
16781678

@@ -1740,11 +1740,11 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
17401740
auto adapt_id = import_class.adapt_id.has_value()
17411741
? GetLocalConstantInstId(resolver, import_class.adapt_id)
17421742
: SemIR::InstId::None;
1743-
auto& new_class = resolver.local_classes().Get(class_id);
1744-
auto vtable_ptr_const_id =
1745-
import_class.vtable_ptr_id.has_value()
1746-
? AddImportRef(resolver, import_class.vtable_ptr_id)
1743+
auto vtable_decl_id =
1744+
import_class.vtable_decl_id.has_value()
1745+
? AddImportRef(resolver, import_class.vtable_decl_id)
17471746
: SemIR::InstId::None;
1747+
auto& new_class = resolver.local_classes().Get(class_id);
17481748

17491749
if (resolver.HasNewWork()) {
17501750
return ResolveResult::Retry(class_const_id, new_class.first_decl_id());
@@ -1770,7 +1770,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
17701770
import_class.complete_type_witness_id, complete_type_witness_const_id);
17711771
AddClassDefinition(resolver, import_class, new_class,
17721772
complete_type_witness_id, base_id, adapt_id,
1773-
vtable_ptr_const_id);
1773+
vtable_decl_id);
17741774
}
17751775

17761776
return ResolveResult::Done(class_const_id, new_class.first_decl_id());
@@ -2043,18 +2043,14 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
20432043
}
20442044

20452045
static auto TryResolveTypedInst(ImportRefResolver& resolver,
2046-
SemIR::VtablePtr inst,
2046+
SemIR::VtableDecl inst,
20472047
SemIR::ConstantId /*vtable_const_id*/)
20482048
-> ResolveResult {
20492049
const auto& import_vtable = resolver.import_vtables().Get(inst.vtable_id);
2050-
20512050
auto class_const_id =
20522051
GetLocalConstantId(resolver, resolver.import_classes()
20532052
.Get(import_vtable.class_id)
20542053
.first_owning_decl_id);
2055-
2056-
auto specific_data = GetLocalSpecificData(resolver, inst.specific_id);
2057-
20582054
auto class_const_inst = resolver.local_insts().Get(
20592055
resolver.local_constant_values().GetInstId(class_const_id));
20602056

@@ -2111,12 +2107,35 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
21112107
.virtual_functions_id =
21122108
resolver.local_inst_blocks().Add(lazy_virtual_functions)}});
21132109

2114-
return ResolveAsDeduplicated<SemIR::VtablePtr>(
2110+
return ResolveAsDeduplicated<SemIR::VtableDecl>(
21152111
resolver, {.type_id = GetPointerType(resolver.local_context(),
21162112
SemIR::VtableType::TypeInstId),
2117-
.vtable_id = new_vtable_id,
2118-
.specific_id = GetOrAddLocalSpecific(
2119-
resolver, inst.specific_id, specific_data)});
2113+
.vtable_id = new_vtable_id});
2114+
}
2115+
2116+
static auto TryResolveTypedInst(ImportRefResolver& resolver,
2117+
SemIR::VtablePtr inst,
2118+
SemIR::ConstantId /*vtable_const_id*/)
2119+
-> ResolveResult {
2120+
auto specific_data = GetLocalSpecificData(resolver, inst.specific_id);
2121+
2122+
auto vtable_const_id = GetLocalConstantId(
2123+
resolver, resolver.import_classes()
2124+
.Get(resolver.import_vtables().Get(inst.vtable_id).class_id)
2125+
.vtable_decl_id);
2126+
auto vtable_const_inst = resolver.local_insts().Get(
2127+
resolver.local_constant_values().GetInstId(vtable_const_id));
2128+
if (resolver.HasNewWork()) {
2129+
return ResolveResult::Retry();
2130+
}
2131+
2132+
return ResolveAsDeduplicated<SemIR::VtablePtr>(
2133+
resolver,
2134+
{.type_id = GetPointerType(resolver.local_context(),
2135+
SemIR::VtableType::TypeInstId),
2136+
.vtable_id = vtable_const_inst.As<SemIR::VtableDecl>().vtable_id,
2137+
.specific_id =
2138+
GetOrAddLocalSpecific(resolver, inst.specific_id, specific_data)});
21202139
}
21212140

21222141
static auto TryResolveTypedInst(ImportRefResolver& resolver,
@@ -3227,6 +3246,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver,
32273246
case CARBON_KIND(SemIR::VarStorage inst): {
32283247
return TryResolveTypedInst(resolver, inst, inst_id);
32293248
}
3249+
case CARBON_KIND(SemIR::VtableDecl inst): {
3250+
return TryResolveTypedInst(resolver, inst, const_id);
3251+
}
32303252
case CARBON_KIND(SemIR::VtablePtr inst): {
32313253
return TryResolveTypedInst(resolver, inst, const_id);
32323254
}

0 commit comments

Comments
 (0)