Skip to content

Commit 4d9e1b0

Browse files
authored
Merge pull request #14740 from shajrawi/devirt_inline
2 parents fab3c18 + b0fdadb commit 4d9e1b0

File tree

5 files changed

+87
-17
lines changed

5 files changed

+87
-17
lines changed

include/swift/SILOptimizer/Utils/Devirtualize.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,17 @@ DevirtualizationResult tryDevirtualizeApply(ApplySite AI,
7070
bool canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA);
7171
bool isNominalTypeWithUnboundGenericParameters(SILType Ty, SILModule &M);
7272
bool canDevirtualizeClassMethod(FullApplySite AI, SILType ClassInstanceType,
73-
OptRemark::Emitter *ORE = nullptr);
73+
OptRemark::Emitter *ORE = nullptr,
74+
bool isEffectivelyFinalMethod = false);
7475
SILFunction *getTargetClassMethod(SILModule &M, SILType ClassOrMetatypeType,
7576
MethodInst *MI);
7677
DevirtualizationResult devirtualizeClassMethod(FullApplySite AI,
7778
SILValue ClassInstance,
7879
OptRemark::Emitter *ORE);
79-
DevirtualizationResult tryDevirtualizeClassMethod(FullApplySite AI,
80-
SILValue ClassInstance,
81-
OptRemark::Emitter *ORE);
80+
DevirtualizationResult
81+
tryDevirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance,
82+
OptRemark::Emitter *ORE,
83+
bool isEffectivelyFinalMethod = false);
8284
DevirtualizationResult
8385
tryDevirtualizeWitnessMethod(ApplySite AI, OptRemark::Emitter *ORE);
8486
}

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,8 @@ SILFunction *swift::getTargetClassMethod(SILModule &M,
496496
/// return true if it is possible to devirtualize, false - otherwise.
497497
bool swift::canDevirtualizeClassMethod(FullApplySite AI,
498498
SILType ClassOrMetatypeType,
499-
OptRemark::Emitter *ORE) {
499+
OptRemark::Emitter *ORE,
500+
bool isEffectivelyFinalMethod) {
500501

501502
DEBUG(llvm::dbgs() << " Trying to devirtualize : " << *AI.getInstruction());
502503

@@ -519,6 +520,15 @@ bool swift::canDevirtualizeClassMethod(FullApplySite AI,
519520
return false;
520521
}
521522

523+
// We need to disable the “effectively final” opt if a function is inlinable
524+
if (isEffectivelyFinalMethod &&
525+
F->getResilienceExpansion() == ResilienceExpansion::Minimal) {
526+
DEBUG(llvm::dbgs() << " FAIL: Could not optimize function because "
527+
"it is an effectively-final inlinable: "
528+
<< F->getName() << "\n");
529+
return false;
530+
}
531+
522532
// Mandatory inlining does class method devirtualization. I'm not sure if this
523533
// is really needed, but some test rely on this.
524534
// So even for Onone functions we have to do it if the SILStage is raw.
@@ -701,10 +711,12 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI,
701711
return std::make_pair(ResultValue, NewAI);
702712
}
703713

704-
DevirtualizationResult swift::tryDevirtualizeClassMethod(FullApplySite AI,
705-
SILValue ClassInstance,
706-
OptRemark::Emitter *ORE) {
707-
if (!canDevirtualizeClassMethod(AI, ClassInstance->getType(), ORE))
714+
DevirtualizationResult
715+
swift::tryDevirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance,
716+
OptRemark::Emitter *ORE,
717+
bool isEffectivelyFinalMethod) {
718+
if (!canDevirtualizeClassMethod(AI, ClassInstance->getType(), ORE,
719+
isEffectivelyFinalMethod))
708720
return std::make_pair(nullptr, FullApplySite());
709721
return devirtualizeClassMethod(AI, ClassInstance, ORE);
710722
}
@@ -1025,7 +1037,8 @@ DevirtualizationResult swift::tryDevirtualizeApply(ApplySite AI,
10251037
auto *CD = ClassType.getClassOrBoundGenericClass();
10261038

10271039
if (isEffectivelyFinalMethod(FAS, ClassType, CD, CHA))
1028-
return tryDevirtualizeClassMethod(FAS, Instance, ORE);
1040+
return tryDevirtualizeClassMethod(FAS, Instance, ORE,
1041+
true /*isEffectivelyFinalMethod*/);
10291042

10301043
// Try to check if the exact dynamic type of the instance is statically
10311044
// known.
@@ -1091,7 +1104,9 @@ bool swift::canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA)
10911104
auto *CD = ClassType.getClassOrBoundGenericClass();
10921105

10931106
if (isEffectivelyFinalMethod(AI, ClassType, CD, CHA))
1094-
return canDevirtualizeClassMethod(AI, Instance->getType());
1107+
return canDevirtualizeClassMethod(AI, Instance->getType(),
1108+
nullptr /*ORE*/,
1109+
true /*isEffectivelyFinalMethod*/);
10951110

10961111
// Try to check if the exact dynamic type of the instance is statically
10971112
// known.

test/IRGen/big_types_corner_cases.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ public class BigClass {
9595
}
9696

9797
// CHECK-LABEL: define{{( protected)?}} hidden swiftcc void @"$S22big_types_corner_cases8BigClassC03useE6Struct0aH0yAA0eH0V_tF"(%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}), %T22big_types_corner_cases8BigClassC* swiftself)
98-
// CHECK: getelementptr inbounds %T22big_types_corner_cases8BigClassC, %T22big_types_corner_cases8BigClassC*
99-
// CHECK: call void @"$SSqWy
10098
// CHECK: [[BITCAST:%.*]] = bitcast i8* {{.*}} to void (%T22big_types_corner_cases9BigStructV*, %swift.refcounted*)*
10199
// CHECK: call swiftcc void [[BITCAST]](%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}) %0, %swift.refcounted* swiftself
102100
// CHECK: ret void
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -devirtualizer | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
import Swift
7+
import SwiftShims
8+
9+
class X
10+
{
11+
private func ping() -> Int
12+
@objc deinit
13+
init()
14+
}
15+
16+
class Y : X
17+
{
18+
@objc deinit
19+
override init()
20+
}
21+
22+
sil [serialized] @_TFC14devirt_access21X4pingfS0_FT_Si : $@convention(method) (@guaranteed X) -> Int
23+
sil public_external [transparent] @_TFSi33_convertFromBuiltinIntegerLiteralfMSiFBi2048_Si : $@convention(thin) (Builtin.Int2048, @thin Int.Type) -> Int
24+
sil @_TFC14devirt_access21Xd : $@convention(method) (@guaranteed X) -> @owned Builtin.NativeObject
25+
sil @_TFC14devirt_access21XD : $@convention(method) (@guaranteed X) -> ()
26+
sil @_TFC14devirt_access21XcfMS0_FT_S0_ : $@convention(method) (@owned X) -> @owned X
27+
sil @_TFC14devirt_access21XCfMS0_FT_S0_ : $@convention(thin) (@thick X.Type) -> @owned X
28+
sil @_TFC14devirt_access21Yd : $@convention(method) (@guaranteed Y) -> @owned Builtin.NativeObject
29+
sil @_TFC14devirt_access21YD : $@convention(method) (@guaranteed Y) -> ()
30+
sil @_TFC14devirt_access21YcfMS0_FT_S0_ : $@convention(method) (@owned Y) -> @owned Y
31+
sil @_TFC14devirt_access21YCfMS0_FT_S0_ : $@convention(thin) (@thick Y.Type) -> @owned Y
32+
33+
//CHECK-LABEL: sil @Case
34+
//CHECK-NOT: function_ref @_TFC14devirt_access21X4pingfS0_FT_Si
35+
//CHECK: class_method
36+
//CHECK: apply
37+
//CHECK: return
38+
sil @Case : $@convention(thin) (@owned Y) -> Int {
39+
bb0(%0 : $Y):
40+
debug_value %0 : $Y, let, name "a" // id: %1
41+
strong_retain %0 : $Y // id: %2
42+
%3 = upcast %0 : $Y to $X // users: %4, %5
43+
%4 = class_method %3 : $X, #X.ping!1 : (X) -> () -> Int, $@convention(method) (@guaranteed X) -> Int // user: %5
44+
%5 = apply %4(%3) : $@convention(method) (@guaranteed X) -> Int // user: %7
45+
strong_release %0 : $Y // id: %6
46+
return %5 : $Int // id: %7
47+
}
48+
49+
sil_vtable X {
50+
#X.ping!1: @_TFC14devirt_access21X4pingfS0_FT_Si // devirt_access2.X.ping (devirt_access2.X)() -> Swift.Int
51+
#X.init!initializer.1: @_TFC14devirt_access21XcfMS0_FT_S0_ // devirt_access2.X.init (devirt_access2.X.Type)() -> devirt_access2.X
52+
}
53+
54+
sil_vtable Y {
55+
#X.ping!1: @_TFC14devirt_access21X4pingfS0_FT_Si // devirt_access2.X.ping (devirt_access2.X)() -> Swift.Int
56+
#X.init!initializer.1: @_TFC14devirt_access21YcfMS0_FT_S0_ // devirt_access2.Y.init (devirt_access2.Y.Type)() -> devirt_access2.Y
57+
}

test/sil-func-extractor/basic.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,8 @@
5656

5757
// EXTRACT-NOW-LABEL: sil [serialized] @$S5basic7VehicleC3nowSiyF : $@convention(method) (@guaranteed Vehicle) -> Int {
5858
// EXTRACT-NOW: bb0
59-
// EXTRACT-NOW: ref_element_addr
60-
// EXTRACT-NOW-NEXT: begin_access [read] [dynamic]
61-
// EXTRACT-NOW-NEXT: load
62-
// EXTRACT-NOW-NEXT: end_access
59+
// EXTRACT-NOW: class_method
60+
// EXTRACT-NOW-NEXT: apply
6361
// EXTRACT-NOW-NEXT: return
6462

6563
public struct X {

0 commit comments

Comments
 (0)