Skip to content

Commit 9039587

Browse files
authored
Merge pull request #15888 from slavapestov/sil-link-fewer-vtables
Deserialize fewer vtables in -Onone
2 parents 8fa65a8 + 9a40305 commit 9039587

File tree

5 files changed

+67
-102
lines changed

5 files changed

+67
-102
lines changed

lib/SIL/Linker.cpp

Lines changed: 18 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -58,41 +58,11 @@ bool SILLinkerVisitor::processFunction(SILFunction *F) {
5858
return true;
5959
}
6060

61-
/// Deserialize the VTable mapped to C if it exists and all SIL the VTable
62-
/// transitively references.
63-
///
64-
/// This method assumes that the caller made sure that no vtable existed in
65-
/// Mod.
66-
SILVTable *SILLinkerVisitor::processClassDecl(const ClassDecl *C) {
67-
// If we are not linking anything, bail.
68-
if (Mode == LinkingMode::LinkNone)
69-
return nullptr;
70-
71-
// Attempt to load the VTable from the SerializedSILLoader. If we
72-
// fail... bail...
73-
SILVTable *Vtbl = Loader->lookupVTable(C);
74-
if (!Vtbl)
75-
return nullptr;
76-
77-
// Otherwise, add all the vtable functions in Vtbl to the function
78-
// processing list...
79-
for (auto &E : Vtbl->getEntries())
80-
Worklist.push_back(E.Implementation);
81-
82-
// And then transitively deserialize all SIL referenced by those functions.
83-
process();
84-
85-
// Return the deserialized Vtbl.
86-
return Vtbl;
87-
}
88-
61+
/// Deserialize the given VTable all SIL the VTable transitively references.
8962
bool SILLinkerVisitor::linkInVTable(ClassDecl *D) {
9063
// Attempt to lookup the Vtbl from the SILModule.
9164
SILVTable *Vtbl = Mod.lookUpVTable(D);
92-
93-
// If the SILModule does not have the VTable, attempt to deserialize the
94-
// VTable. If we fail to do that as well, bail.
95-
if (!Vtbl || !(Vtbl = Loader->lookupVTable(D->getName())))
65+
if (!Vtbl)
9666
return false;
9767

9868
// Ok we found our VTable. Visit each function referenced by the VTable. If
@@ -120,16 +90,17 @@ bool SILLinkerVisitor::visitApplyInst(ApplyInst *AI) {
12090
performFuncDeserialization |= visitApplySubstitutions(
12191
sig->getSubstitutionMap(AI->getSubstitutions()));
12292
}
123-
124-
// Ok we have a function ref inst, grab the callee.
125-
SILFunction *Callee = AI->getReferencedFunction();
126-
if (!Callee)
127-
return performFuncDeserialization;
12893

129-
if (isLinkAll() ||
130-
hasSharedVisibility(Callee->getLinkage())) {
131-
addFunctionToWorklist(Callee);
132-
return true;
94+
return performFuncDeserialization;
95+
}
96+
97+
bool SILLinkerVisitor::visitTryApplyInst(TryApplyInst *TAI) {
98+
bool performFuncDeserialization = false;
99+
100+
if (auto sig = TAI->getCallee()->getType().castTo<SILFunctionType>()
101+
->getGenericSignature()) {
102+
performFuncDeserialization |= visitApplySubstitutions(
103+
sig->getSubstitutionMap(TAI->getSubstitutions()));
133104
}
134105

135106
return performFuncDeserialization;
@@ -144,16 +115,6 @@ bool SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) {
144115
sig->getSubstitutionMap(PAI->getSubstitutions()));
145116
}
146117

147-
SILFunction *Callee = PAI->getReferencedFunction();
148-
if (!Callee)
149-
return performFuncDeserialization;
150-
151-
if (isLinkAll() ||
152-
hasSharedVisibility(Callee->getLinkage())) {
153-
addFunctionToWorklist(Callee);
154-
return true;
155-
}
156-
157118
return performFuncDeserialization;
158119
}
159120

@@ -353,6 +314,9 @@ bool SILLinkerVisitor::visitInitExistentialRefInst(
353314
}
354315

355316
bool SILLinkerVisitor::visitAllocRefInst(AllocRefInst *ARI) {
317+
if (!isLinkAll())
318+
return false;
319+
356320
// Grab the class decl from the alloc ref inst.
357321
ClassDecl *D = ARI->getType().getClassOrBoundGenericClass();
358322
if (!D)
@@ -362,6 +326,9 @@ bool SILLinkerVisitor::visitAllocRefInst(AllocRefInst *ARI) {
362326
}
363327

364328
bool SILLinkerVisitor::visitMetatypeInst(MetatypeInst *MI) {
329+
if (!isLinkAll())
330+
return false;
331+
365332
CanType instTy = MI->getType().castTo<MetatypeType>().getInstanceType();
366333
ClassDecl *C = instTy.getClassOrBoundGenericClass();
367334
if (!C)

lib/SIL/Linker.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class SILLinkerVisitor : public SILInstructionVisitor<SILLinkerVisitor, bool> {
6464
bool visitSILInstruction(SILInstruction *I) { return false; }
6565

6666
bool visitApplyInst(ApplyInst *AI);
67+
bool visitTryApplyInst(TryApplyInst *TAI);
6768
bool visitPartialApplyInst(PartialApplyInst *PAI);
6869
bool visitFunctionRefInst(FunctionRefInst *FRI);
6970
bool visitProtocolConformance(ProtocolConformanceRef C,

lib/SIL/SILModule.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -614,9 +614,7 @@ SILVTable *SILModule::lookUpVTable(const ClassDecl *C) {
614614
return R->second;
615615

616616
// If that fails, try to deserialize it. If that fails, return nullptr.
617-
SILVTable *Vtbl =
618-
SILLinkerVisitor(*this, getSILLoader(), SILModule::LinkingMode::LinkAll)
619-
.processClassDecl(C);
617+
SILVTable *Vtbl = getSILLoader()->lookupVTable(C);
620618
if (!Vtbl)
621619
return nullptr;
622620

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
1+
public func unknown() {}
12

2-
public protocol P {
3-
func doSomething()
4-
}
5-
6-
@_silgen_name("unknown") public
7-
func unknown() -> ()
8-
9-
@_fixed_layout
10-
public class Y : P {
11-
@inlinable
12-
public func doAnotherThing() {
3+
public class Class {
4+
@inlinable public class func firstMethod() {
135
unknown()
146
}
157

16-
@inlinable
17-
public func doSomething() {
18-
doAnotherThing()
19-
}
20-
@inlinable
21-
public init() {}
8+
@inlinable public class func secondMethod() {}
9+
10+
@inlinable public class func thirdMethod() {}
2211
}
Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,42 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend %S/Inputs/vtable_deserialization_input.swift -o %t/Swift.swiftmodule -emit-module -parse-as-library -parse-stdlib -module-link-name swiftCore -module-name Swift
3-
// RUN: %target-swift-frontend %s -emit-sil -O -I %t -o - | %FileCheck %s
4-
5-
import Swift
6-
7-
@usableFromInline
8-
@inlinable
9-
func WhatShouldIDoImBored<T : P>(_ t : T) {
10-
t.doSomething()
11-
}
12-
13-
@inline(__always)
14-
func MakeItNotAGlobal() -> Y {
15-
let x = Y()
16-
WhatShouldIDoImBored(x)
17-
return x
18-
}
19-
20-
21-
// Make sure all abstractions have been removed and everything inlined into top_level_method.
22-
// CHECK-LABEL: sil @main
23-
// CHECK: bb0({{.*}}):
24-
// CHECK: [[UNKNOWN:%.*]] = function_ref @unknown
25-
// CHECK: apply [[UNKNOWN]]
26-
// CHECK: integer_literal
27-
// CHECK: return
28-
MakeItNotAGlobal()
29-
30-
// Make sure our vtable/witness tables are properly deserialized.
31-
// CHECK: sil_vtable Y {
32-
// CHECK: sil_witness_table public_external Y: P module Swift {
2+
// RUN: %target-swift-frontend %S/Inputs/vtable_deserialization_input.swift -emit-module-path %t/vtable_deserialization_input.swiftmodule -emit-module
3+
// RUN: %target-swift-frontend %s -emit-sil -I %t | %FileCheck %s
4+
// RUN: %target-swift-frontend %s -emit-sil -O -I %t | %FileCheck %s --check-prefix=OPT
5+
6+
import vtable_deserialization_input
7+
8+
// Make sure we devirtualized the call and inlined the method body.
9+
// CHECK: function_ref @$S28vtable_deserialization_input5ClassC11firstMethodyyFZ
10+
// OPT: function_ref @$S28vtable_deserialization_input7unknownyyF
11+
Class.firstMethod()
12+
13+
14+
// For now, we also deserialize the body of firstMethod(), even though it
15+
// is not transparent.
16+
// CHECK-LABEL: sil public_external [serialized] @$S28vtable_deserialization_input5ClassC11firstMethodyyFZ : $@convention(method) (@thick Class.Type) -> () {
17+
// OPT-LABEL: sil public_external @$S28vtable_deserialization_input5ClassC11firstMethodyyFZ : $@convention(method) (@thick Class.Type) -> () {
18+
19+
// The other two methods should not be deserialized in the mandatory
20+
// pipeline.
21+
22+
// CHECK-LABEL: sil [serialized] @$S28vtable_deserialization_input5ClassC12secondMethodyyFZ : $@convention(method) (@thick Class.Type) -> (){{$}}
23+
// OPT-LABEL: sil public_external @$S28vtable_deserialization_input5ClassC12secondMethodyyFZ : $@convention(method) (@thick Class.Type) -> () {
24+
25+
// CHECK-LABEL: sil [serialized] @$S28vtable_deserialization_input5ClassC11thirdMethodyyFZ : $@convention(method) (@thick Class.Type) -> (){{$}}
26+
// OPT-LABEL: sil public_external @$S28vtable_deserialization_input5ClassC11thirdMethodyyFZ : $@convention(method) (@thick Class.Type) -> () {
27+
28+
// Make sure we deserialized the vtable.
29+
30+
// CHECK: sil_vtable [serialized] Class {
31+
// CHECK-NEXT: #Class.firstMethod!1: (Class.Type) -> () -> () : @$S28vtable_deserialization_input5ClassC11firstMethodyyFZ
32+
// CHECK-NEXT: #Class.secondMethod!1: (Class.Type) -> () -> () : @$S28vtable_deserialization_input5ClassC12secondMethodyyFZ
33+
// CHECK-NEXT: #Class.thirdMethod!1: (Class.Type) -> () -> () : @$S28vtable_deserialization_input5ClassC11thirdMethodyyFZ
34+
// CHECK-NEXT: #Class.deinit!deallocator: @$S28vtable_deserialization_input5ClassCfD
35+
// CHECK-NEXT: }
36+
37+
// OPT: sil_vtable Class {
38+
// OPT-NEXT: #Class.firstMethod!1: (Class.Type) -> () -> () : @$S28vtable_deserialization_input5ClassC11firstMethodyyFZ
39+
// OPT-NEXT: #Class.secondMethod!1: (Class.Type) -> () -> () : @$S28vtable_deserialization_input5ClassC12secondMethodyyFZ
40+
// OPT-NEXT: #Class.thirdMethod!1: (Class.Type) -> () -> () : @$S28vtable_deserialization_input5ClassC11thirdMethodyyFZ
41+
// OPT-NEXT: #Class.deinit!deallocator: @$S28vtable_deserialization_input5ClassCfD
42+
// OPT-NEXT: }

0 commit comments

Comments
 (0)