Skip to content

Commit ac19579

Browse files
authored
Merge pull request #11319 from swiftix/swift-4.0-branch
[4.0] [sil-devirtualizer] Fix a bug in devirtualization of methods that never return
2 parents 4da8347 + 8c133fb commit ac19579

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,15 @@ static FullApplySite speculateMonomorphicTarget(FullApplySite AI,
150150
SILArgument *Arg =
151151
Continue->createPHIArgument(AI.getType(), ValueOwnershipKind::Owned);
152152
if (!isa<TryApplyInst>(AI)) {
153-
IdenBuilder.createBranch(AI.getLoc(), Continue,
154-
ArrayRef<SILValue>(IdenAI.getInstruction()));
155-
VirtBuilder.createBranch(AI.getLoc(), Continue,
156-
ArrayRef<SILValue>(VirtAI.getInstruction()));
153+
if (AI.getSubstCalleeType()->isNoReturnFunction()) {
154+
IdenBuilder.createUnreachable(AI.getLoc());
155+
VirtBuilder.createUnreachable(AI.getLoc());
156+
} else {
157+
IdenBuilder.createBranch(AI.getLoc(), Continue,
158+
ArrayRef<SILValue>(IdenAI.getInstruction()));
159+
VirtBuilder.createBranch(AI.getLoc(), Continue,
160+
ArrayRef<SILValue>(VirtAI.getInstruction()));
161+
}
157162
}
158163

159164
// Remove the old Apply instruction.

test/SILOptimizer/devirt_speculative.sil

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@
33
sil_stage canonical
44

55
import Builtin
6+
import Swift
67

78
@objc class MyNSObject {}
89
private class Base : MyNSObject {
910
override init()
1011
@inline(never) func foo()
12+
@inline(never) func exit() -> Never
1113
}
1214

1315
private class Sub : Base {
1416
override init()
1517
@inline(never) override func foo()
18+
@inline(never) override func exit() -> Never
1619
}
1720

1821
sil private [noinline] @_TBaseFooFun : $@convention(method) (@guaranteed Base) -> () {
@@ -27,12 +30,19 @@ bb0(%0 : $Sub):
2730
return %1 : $()
2831
}
2932

33+
34+
sil @Base_exit : $@convention(method) (@guaranteed Base) -> Never
35+
36+
sil @Sub_exit : $@convention(method) (@guaranteed Sub) -> Never
37+
3038
sil_vtable Base {
3139
#Base.foo!1: _TBaseFooFun
40+
#Base.exit!1: Base_exit
3241
}
3342

3443
sil_vtable Sub {
3544
#Base.foo!1: _TSubFooFun
45+
#Base.exit!1: Sub_exit
3646
}
3747

3848
sil @test_objc_ancestry : $@convention(thin) (@guaranteed Base) -> () {
@@ -124,3 +134,23 @@ bb0(%0: $Base2):
124134
%3 = tuple()
125135
return %3 : $()
126136
}
137+
138+
// Check that NoReturn functions are devirtualized properly.
139+
// The new apply should be followed by an unreachable instruction
140+
// instead of a branch instruction.
141+
// CHECK-LABEL: sil{{.*}}test_devirt_of_noreturn_function
142+
// CHECK: checked_cast_br
143+
// CHECK: function_ref @Base_exit
144+
// CHECK-NEXT: apply
145+
// CHECK-NEXT: unreachable
146+
// CHECK: checked_cast_br
147+
// CHECK: function_ref @Sub_exit
148+
// CHECK-NEXT: apply
149+
// CHECK-NEXT: unreachable
150+
sil hidden [noinline] @test_devirt_of_noreturn_function : $@convention(thin) (@owned Base) -> () {
151+
bb0(%0 : $Base):
152+
%2 = class_method %0 : $Base, #Base.exit!1 : (Base) -> () -> Never, $@convention(method) (@guaranteed Base) -> Never
153+
%3 = apply %2(%0) : $@convention(method) (@guaranteed Base) -> Never
154+
unreachable
155+
}
156+

0 commit comments

Comments
 (0)