Skip to content

Commit db24e3e

Browse files
committed
Fix crash in EpilogueArcAnalysis
EpilogueARCState for unreachable blocks can be non-existent. Fix the EpilogueARCContext::getState method and its users.
1 parent 8f136f3 commit db24e3e

File tree

3 files changed

+64
-11
lines changed

3 files changed

+64
-11
lines changed

include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,14 @@ class EpilogueARCContext {
8383
/// The exit blocks of the function.
8484
llvm::SmallPtrSet<SILBasicBlock *, 2> ExitBlocks;
8585

86-
EpilogueARCBlockState &getState(SILBasicBlock *BB) {
87-
return IndexToStateMap[*PO->getPONumber(BB)];
86+
/// Returns the EpligoyeARCBlockState for \p BB. If \p BB is unreachable,
87+
/// returns None
88+
Optional<EpilogueARCBlockState *> getState(SILBasicBlock *BB) {
89+
// poNumber will be None for unreachable blocks
90+
auto poNumber = PO->getPONumber(BB);
91+
if (poNumber.hasValue())
92+
return &IndexToStateMap[*poNumber];
93+
return None;
8894
}
8995

9096
/// Return true if this is a function exiting block this epilogue ARC
@@ -113,7 +119,10 @@ class EpilogueARCContext {
113119
}
114120

115121
SILValue getArg(SILBasicBlock *BB) {
116-
SILValue A = getState(BB).LocalArg;
122+
auto state = getState(BB);
123+
if (!state)
124+
return SILValue();
125+
SILValue A = state.getValue()->LocalArg;
117126
if (A)
118127
return A;
119128
return Arg;

lib/SILOptimizer/Analysis/EpilogueARCAnalysis.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ void EpilogueARCContext::initializeDataflow() {
4848
for (auto *X : A->getParent()->getPredecessorBlocks()) {
4949
// Try to find the predecessor edge-value.
5050
SILValue IA = A->getIncomingPhiValue(X);
51-
getState(X).LocalArg = IA;
51+
auto state = getState(X);
52+
if (state.hasValue())
53+
state.getValue()->LocalArg = IA;
5254

5355
// Maybe the edge value is another SILArgument.
5456
ToProcess.push_back(IA);
@@ -64,15 +66,19 @@ bool EpilogueARCContext::convergeDataflow() {
6466
Changed = false;
6567
// Iterate until the data flow converges.
6668
for (SILBasicBlock *B : PO->getPostOrder()) {
67-
auto &BS = getState(B);
69+
// Since the basic block is in PO, it is reachable and will always have a
70+
// state
71+
auto *BS = getState(B).getValue();
6872
// Merge in all the successors.
6973
bool BBSetOut = false;
7074
if (!B->succ_empty()) {
7175
auto Iter = B->succ_begin();
72-
BBSetOut = getState(*Iter).BBSetIn;
76+
// Since the basic block is reachable, its successors are reachable, and
77+
// will always have a state.
78+
BBSetOut = getState(*Iter).getValue()->BBSetIn;
7379
Iter = std::next(Iter);
7480
for (auto E = B->succ_end(); Iter != E; ++Iter) {
75-
BBSetOut &= getState(*Iter).BBSetIn;
81+
BBSetOut &= getState(*Iter).getValue()->BBSetIn;
7682
}
7783
} else if (isExitBlock(B)) {
7884
// We set the BBSetOut for exit blocks.
@@ -100,8 +106,8 @@ bool EpilogueARCContext::convergeDataflow() {
100106
}
101107

102108
// Update BBSetIn.
103-
Changed |= (BS.BBSetIn != BBSetOut);
104-
BS.BBSetIn = BBSetOut;
109+
Changed |= (BS->BBSetIn != BBSetOut);
110+
BS->BBSetIn = BBSetOut;
105111
}
106112
} while (Changed);
107113
return true;
@@ -122,10 +128,12 @@ bool EpilogueARCContext::computeEpilogueARC() {
122128
// not have an epilogue ARC instruction, which means the data flow has
123129
// failed.
124130
auto Iter = B->succ_begin();
125-
auto Base = getState(*Iter).BBSetIn;
131+
// Since basic block B is in PO, its successors will be reachable and will
132+
// always have a state
133+
auto Base = getState(*Iter).getValue()->BBSetIn;
126134
Iter = std::next(Iter);
127135
for (auto E = B->succ_end(); Iter != E; ++Iter) {
128-
if (getState(*Iter).BBSetIn != Base)
136+
if (getState(*Iter).getValue()->BBSetIn != Base)
129137
return false;
130138
}
131139
BBSetOut = Base;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-sil-opt -arc-sequence-opts %s
2+
3+
import Builtin
4+
import Swift
5+
6+
class Klass {
7+
}
8+
9+
// Test to make sure there is no crash in EpilogueArcAnalysis, while querying the state of unreachable block bb1
10+
sil @foo : $@convention(thin) (@owned Klass) -> () {
11+
bb0(%arg : $Klass):
12+
strong_retain %arg : $Klass
13+
%0 = enum $Optional<Klass>, #Optional.none!enumelt
14+
br bb2(%0 : $Optional<Klass>)
15+
16+
bb1: // unreachable
17+
%1 = enum $Optional<Klass>, #Optional.some!enumelt, undef : $Klass
18+
br bb2(%1 : $Optional<Klass>)
19+
20+
bb2(%2 : $Optional<Klass>):
21+
switch_enum %2 : $Optional<Klass>, case #Optional.some!enumelt: bb3, case #Optional.none!enumelt: bb4
22+
23+
bb3:
24+
br bb5
25+
26+
bb4:
27+
br bb5
28+
29+
bb5:
30+
release_value %2 : $Optional<Klass>
31+
strong_release %arg : $Klass
32+
strong_release %arg : $Klass
33+
%res = tuple ()
34+
return %res : $()
35+
}
36+

0 commit comments

Comments
 (0)