Skip to content

Commit 0f5625d

Browse files
committed
Fix a SIL optimizer verification failure complaining about a not up-to-date dominator tree.
In some cases the ClosureSpecializer did not invalidate the dominator tree, although it changes the CFG. This could happen if during analysis critical CFG edges are broken, but at the end no functions are specialized.
1 parent 78e9497 commit 0f5625d

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

lib/SILOptimizer/IPO/ClosureSpecializer.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ void ClosureSpecCloner::populateCloned() {
784784
namespace {
785785

786786
class SILClosureSpecializerTransform : public SILFunctionTransform {
787-
void gatherCallSites(SILFunction *Caller,
787+
bool gatherCallSites(SILFunction *Caller,
788788
llvm::SmallVectorImpl<ClosureInfo*> &ClosureCandidates,
789789
llvm::DenseSet<FullApplySite> &MultipleClosureAI);
790790
bool specialize(SILFunction *Caller,
@@ -839,7 +839,7 @@ void SILClosureSpecializerTransform::run() {
839839
invalidateAnalysis(SILAnalysis::InvalidationKind::Everything);
840840
}
841841

842-
void SILClosureSpecializerTransform::gatherCallSites(
842+
bool SILClosureSpecializerTransform::gatherCallSites(
843843
SILFunction *Caller,
844844
llvm::SmallVectorImpl<ClosureInfo*> &ClosureCandidates,
845845
llvm::DenseSet<FullApplySite> &MultipleClosureAI) {
@@ -848,6 +848,8 @@ void SILClosureSpecializerTransform::gatherCallSites(
848848
// make sure that we do not handle call sites with multiple closure arguments.
849849
llvm::DenseSet<FullApplySite> VisitedAI;
850850

851+
bool CFGChanged = false;
852+
851853
// For each basic block BB in Caller...
852854
for (auto &BB : *Caller) {
853855

@@ -918,7 +920,7 @@ void SILClosureSpecializerTransform::gatherCallSites(
918920
// We could fix this by inserting new arguments more carefully, or
919921
// changing how we model dynamic Self altogether.
920922
if (mayBindDynamicSelf(ApplyCallee))
921-
return;
923+
return CFGChanged;
922924

923925
// Ok, we know that we can perform the optimization but not whether or
924926
// not the optimization is profitable. Find the index of the argument
@@ -991,12 +993,15 @@ void SILClosureSpecializerTransform::gatherCallSites(
991993
}
992994
if (CInfo) {
993995
ValueLifetimeAnalysis VLA(CInfo->Closure, UsePoints);
994-
VLA.computeFrontier(CInfo->LifetimeFrontier,
995-
ValueLifetimeAnalysis::AllowToModifyCFG);
996+
if (!VLA.computeFrontier(CInfo->LifetimeFrontier,
997+
ValueLifetimeAnalysis::AllowToModifyCFG)) {
998+
CFGChanged = true;
999+
}
9961000
ClosureCandidates.push_back(CInfo);
9971001
}
9981002
}
9991003
}
1004+
return CFGChanged;
10001005
}
10011006

10021007
bool SILClosureSpecializerTransform::specialize(SILFunction *Caller,
@@ -1008,7 +1013,9 @@ bool SILClosureSpecializerTransform::specialize(SILFunction *Caller,
10081013
// ApplyInsts. Check the profitability of specializing the closure argument.
10091014
llvm::SmallVector<ClosureInfo*, 8> ClosureCandidates;
10101015
llvm::DenseSet<FullApplySite> MultipleClosureAI;
1011-
gatherCallSites(Caller, ClosureCandidates, MultipleClosureAI);
1016+
if (gatherCallSites(Caller, ClosureCandidates, MultipleClosureAI)) {
1017+
invalidateAnalysis(SILAnalysis::InvalidationKind::Branches);
1018+
}
10121019

10131020
bool Changed = false;
10141021
for (auto *CInfo : ClosureCandidates) {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -sil-verify-without-invalidation -enable-sil-verify-all -loop-unroll -closure-specialize %s
2+
3+
// Test if the ClosureSpecializer correctly invalidates the dominator tree
4+
// even if there are no functions specialized.
5+
// The test just checks if the compiler does not crash.
6+
// First running LoopUnroll creates the dominator tree, which should then be
7+
// invalidated by the ClosureSpecializer.
8+
// If this is not done correctly the verification will complain that the
9+
// dominator tree is not up to date.
10+
11+
import Builtin
12+
import Swift
13+
14+
sil @closure : $@convention(thin) () -> ()
15+
16+
sil @use_closure : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
17+
18+
sil hidden [noinline] @use_closure2 : $@convention(thin) (@owned @callee_owned () -> (), @owned @callee_owned () -> ()) -> () {
19+
bb0(%0 : $@callee_owned () -> (), %1 : $@callee_owned () -> ()):
20+
%2 = apply %0() : $@callee_owned () -> ()
21+
%3 = apply %1() : $@callee_owned () -> ()
22+
%4 = tuple ()
23+
return %3 : $()
24+
}
25+
26+
sil @insert_release_in_liferange_exit_block : $@convention(thin) () -> () {
27+
bb0:
28+
%2 = function_ref @closure : $@convention(thin) () -> ()
29+
%3 = partial_apply %2() : $@convention(thin) () -> ()
30+
%8 = function_ref @use_closure : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
31+
%5 = partial_apply %8(%3) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
32+
33+
// There is a critical edge from bb0 to bb2 which is broken by ValueLifetimeAnalysis.
34+
cond_br undef, bb2, bb1
35+
36+
bb1:
37+
strong_retain %3 : $@callee_owned () -> ()
38+
strong_retain %3 : $@callee_owned () -> ()
39+
%10 = function_ref @use_closure2 : $@convention(thin) (@owned @callee_owned () -> (), @owned @callee_owned () -> ()) -> ()
40+
41+
// Passing two closures actually prevents closure specialization.
42+
%17 = apply %10(%3, %3) : $@convention(thin) (@owned @callee_owned () -> (), @owned @callee_owned () -> ()) -> ()
43+
br bb2
44+
45+
bb2:
46+
strong_release %5 : $@callee_owned () -> ()
47+
%11 = tuple ()
48+
return %11 : $()
49+
}

0 commit comments

Comments
 (0)