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
+44 -16
View File
@@ -32,9 +32,11 @@ package Create;
import Classes;
fn Create() {
var b: Classes.Base;
var i: Classes.Intermediate;
var d: Classes.Derived;
var b: Classes.Base = {};
var i: Classes.Intermediate = {.base = {}};
var d: Classes.Derived = {.base = {.base = {}}};
// TODO: Support vptr initialization without explicit source initializers.
var d2: Classes.Derived;
}
fn Use(v: Classes.Intermediate*) {
@@ -73,7 +75,6 @@ fn Use() {
var v : Derived = {.base = {}};
}
// CHECK:STDOUT: ; ModuleID = 'classes.carbon'
// CHECK:STDOUT: source_filename = "classes.carbon"
// CHECK:STDOUT:
@@ -106,21 +107,39 @@ fn Use() {
// CHECK:STDOUT: ; ModuleID = 'create.carbon'
// CHECK:STDOUT: source_filename = "create.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: @"_CIntermediate.Classes.$vtable" = external unnamed_addr constant ptr
// CHECK:STDOUT: @"_CDerived.Classes.$vtable" = external unnamed_addr constant ptr
// CHECK:STDOUT: @Base.val.loc7_3.2 = internal constant {} zeroinitializer
// CHECK:STDOUT: @Base.val.loc8_44.6 = internal constant {} zeroinitializer
// CHECK:STDOUT: @Base.val.loc9_48.6 = internal constant {} zeroinitializer
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CCreate.Create() !dbg !4 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %b.var = alloca {}, align 8, !dbg !7
// CHECK:STDOUT: %i.var = alloca { ptr, {} }, align 8, !dbg !7
// CHECK:STDOUT: %d.var = alloca { { ptr, {} } }, align 8, !dbg !7
// CHECK:STDOUT: %d2.var = alloca { { ptr, {} } }, align 8, !dbg !7
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 0, ptr %b.var), !dbg !7
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %b.var, ptr align 1 @Base.val.loc7_3.2, i64 0, i1 false), !dbg !7
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 8, ptr %i.var), !dbg !7
// CHECK:STDOUT: %.loc8_44.2.vptr = getelementptr inbounds nuw { ptr, {} }, ptr %i.var, i32 0, i32 0, !dbg !8
// CHECK:STDOUT: store ptr @"_CIntermediate.Classes.$vtable", ptr %.loc8_44.2.vptr, align 8, !dbg !8
// CHECK:STDOUT: %.loc8_44.5.base = getelementptr inbounds nuw { ptr, {} }, ptr %i.var, i32 0, i32 1, !dbg !8
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %.loc8_44.5.base, ptr align 1 @Base.val.loc8_44.6, i64 0, i1 false), !dbg !8
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 8, ptr %d.var), !dbg !7
// CHECK:STDOUT: ret void, !dbg !8
// CHECK:STDOUT: %.loc9_49.2.base = getelementptr inbounds nuw { { ptr, {} } }, ptr %d.var, i32 0, i32 0, !dbg !9
// CHECK:STDOUT: %.loc9_48.2.vptr = getelementptr inbounds nuw { ptr, {} }, ptr %.loc9_49.2.base, i32 0, i32 0, !dbg !10
// CHECK:STDOUT: store ptr @"_CDerived.Classes.$vtable", ptr %.loc9_48.2.vptr, align 8, !dbg !10
// CHECK:STDOUT: %.loc9_48.5.base = getelementptr inbounds nuw { ptr, {} }, ptr %.loc9_49.2.base, i32 0, i32 1, !dbg !10
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %.loc9_48.5.base, ptr align 1 @Base.val.loc9_48.6, i64 0, i1 false), !dbg !10
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 8, ptr %d2.var), !dbg !7
// CHECK:STDOUT: ret void, !dbg !11
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CUse.Create(ptr %v) !dbg !9 {
// CHECK:STDOUT: define void @_CUse.Create(ptr %v) !dbg !12 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: call void @_CFn.Intermediate.Classes(ptr %v), !dbg !10
// CHECK:STDOUT: ret void, !dbg !11
// CHECK:STDOUT: call void @_CFn.Intermediate.Classes(ptr %v), !dbg !13
// CHECK:STDOUT: ret void, !dbg !14
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: declare void @_CFn.Intermediate.Classes(ptr)
@@ -128,10 +147,16 @@ fn Use() {
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #0
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #1
// CHECK:STDOUT:
// CHECK:STDOUT: ; uselistorder directives
// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 2, 1, 0 }
// CHECK:STDOUT: uselistorder i32 1, { 1, 3, 0, 2, 4, 5 }
// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 3, 2, 1, 0 }
// CHECK:STDOUT: uselistorder ptr @llvm.memcpy.p0.p0.i64, { 2, 1, 0 }
// CHECK:STDOUT:
// CHECK:STDOUT: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
// CHECK:STDOUT: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
// CHECK:STDOUT:
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1}
// CHECK:STDOUT: !llvm.dbg.cu = !{!2}
@@ -144,10 +169,13 @@ fn Use() {
// CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
// CHECK:STDOUT: !6 = !{}
// CHECK:STDOUT: !7 = !DILocation(line: 7, column: 3, scope: !4)
// CHECK:STDOUT: !8 = !DILocation(line: 6, column: 1, scope: !4)
// CHECK:STDOUT: !9 = distinct !DISubprogram(name: "Use", linkageName: "_CUse.Create", scope: null, file: !3, line: 12, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !10 = !DILocation(line: 13, column: 3, scope: !9)
// CHECK:STDOUT: !11 = !DILocation(line: 12, column: 1, scope: !9)
// CHECK:STDOUT: !8 = !DILocation(line: 8, column: 33, scope: !4)
// CHECK:STDOUT: !9 = !DILocation(line: 9, column: 28, scope: !4)
// CHECK:STDOUT: !10 = !DILocation(line: 9, column: 37, scope: !4)
// CHECK:STDOUT: !11 = !DILocation(line: 6, column: 1, scope: !4)
// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "Use", linkageName: "_CUse.Create", scope: null, file: !3, line: 14, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !13 = !DILocation(line: 15, column: 3, scope: !12)
// CHECK:STDOUT: !14 = !DILocation(line: 14, column: 1, scope: !12)
// CHECK:STDOUT: ; ModuleID = 'member_init.carbon'
// CHECK:STDOUT: source_filename = "member_init.carbon"
// CHECK:STDOUT:
@@ -167,7 +195,7 @@ fn Use() {
// CHECK:STDOUT: store i32 3, ptr %i.var, align 4, !dbg !9
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 16, ptr %v.var), !dbg !9
// CHECK:STDOUT: %.loc11_24.2.vptr = getelementptr inbounds nuw { ptr, i32 }, ptr %v.var, i32 0, i32 0, !dbg !10
// CHECK:STDOUT: store ptr null, ptr %.loc11_24.2.vptr, align 8, !dbg !10
// CHECK:STDOUT: store ptr @"_CBase.MemberInit.$vtable", ptr %.loc11_24.2.vptr, align 8, !dbg !10
// CHECK:STDOUT: %.loc11_23 = load i32, ptr %i.var, align 4, !dbg !11
// CHECK:STDOUT: %.loc11_24.5.m = getelementptr inbounds nuw { ptr, i32 }, ptr %v.var, i32 0, i32 1, !dbg !10
// CHECK:STDOUT: store i32 %.loc11_23, ptr %.loc11_24.5.m, align 4, !dbg !10
@@ -175,7 +203,7 @@ fn Use() {
// CHECK:STDOUT: store i32 5, ptr %.loc12_4.m, align 4, !dbg !12
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 16, ptr %u.var), !dbg !9
// CHECK:STDOUT: %.loc13_24.2.vptr = getelementptr inbounds nuw { ptr, i32 }, ptr %u.var, i32 0, i32 0, !dbg !13
// CHECK:STDOUT: store ptr null, ptr %.loc13_24.2.vptr, align 8, !dbg !13
// CHECK:STDOUT: store ptr @"_CBase.MemberInit.$vtable", ptr %.loc13_24.2.vptr, align 8, !dbg !13
// CHECK:STDOUT: %.loc13_24.6.m = getelementptr inbounds nuw { ptr, i32 }, ptr %u.var, i32 0, i32 1, !dbg !13
// CHECK:STDOUT: store i32 3, ptr %.loc13_24.6.m, align 4, !dbg !13
// CHECK:STDOUT: ret void, !dbg !14
@@ -222,7 +250,7 @@ fn Use() {
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 8, ptr %v.var), !dbg !7
// CHECK:STDOUT: %.loc13_32.2.base = getelementptr inbounds nuw { { ptr } }, ptr %v.var, i32 0, i32 0, !dbg !8
// CHECK:STDOUT: %.loc13_31.2.vptr = getelementptr inbounds nuw { ptr }, ptr %.loc13_32.2.base, i32 0, i32 0, !dbg !9
// CHECK:STDOUT: store ptr null, ptr %.loc13_31.2.vptr, align 8, !dbg !9
// CHECK:STDOUT: store ptr @"_CDerived.Main.$vtable", ptr %.loc13_31.2.vptr, align 8, !dbg !9
// CHECK:STDOUT: ret void, !dbg !10
// CHECK:STDOUT: }
// CHECK:STDOUT: