@@ -18,6 +18,7 @@ using namespace swift;
18
18
19
19
void ValueLifetimeAnalysis::propagateLiveness () {
20
20
assert (liveBlocks.empty () && " frontier computed twice" );
21
+ assert (!userSet.count (defValue) && " definition cannot be its own use" );
21
22
22
23
auto defBB = defValue->getParentBlock ();
23
24
llvm::SmallVector<SILBasicBlock *, 64 > worklist;
@@ -42,13 +43,16 @@ void ValueLifetimeAnalysis::propagateLiveness() {
42
43
numUsersBeforeDef--;
43
44
}
44
45
46
+ // Initialize the hasUsersBeforeDef field.
47
+ hasUsersBeforeDef = numUsersBeforeDef > 0 ;
48
+
45
49
// Now propagate liveness backwards until we hit the block that defines the
46
50
// value.
47
51
while (!worklist.empty ()) {
48
52
auto *bb = worklist.pop_back_val ();
49
53
50
54
// Don't go beyond the definition.
51
- if (bb == defBB && numUsersBeforeDef == 0 )
55
+ if (bb == defBB && !hasUsersBeforeDef )
52
56
continue ;
53
57
54
58
for (SILBasicBlock *Pred : bb->getPredecessorBlocks ()) {
@@ -93,13 +97,34 @@ bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode,
93
97
94
98
bool liveInSucc = false ;
95
99
bool deadInSucc = false ;
100
+ bool usedAndRedefinedInSucc = false ;
96
101
for (const SILSuccessor &succ : bb->getSuccessors ()) {
97
102
if (isAliveAtBeginOfBlock (succ)) {
98
103
liveInSucc = true ;
104
+ if (succ == defValue->getParent ()) {
105
+ // Here, the basic block bb uses the value but also redefines the
106
+ // value inside bb. The new value could be used by the successors
107
+ // of succ and therefore could be live at the end of succ as well.
108
+ usedAndRedefinedInSucc = true ;
109
+ }
99
110
} else if (!deBlocks || !deBlocks->isDeadEnd (succ)) {
100
111
deadInSucc = true ;
101
112
}
102
113
}
114
+ if (usedAndRedefinedInSucc) {
115
+ // Here, the basic block bb uses the value and later redefines the value.
116
+ // Therefore, this value's lifetime ends after its last use preceding the
117
+ // re-definition of the value.
118
+ auto ii = defValue->getReverseIterator ();
119
+ for (; ii != bb->rend (); ++ii) {
120
+ if (userSet.count (&*ii)) {
121
+ frontier.push_back (&*std::next (ii));
122
+ break ;
123
+ }
124
+ }
125
+ assert (ii != bb->rend () &&
126
+ " There must be a user in bb before definition" );
127
+ }
103
128
if (!liveInSucc) {
104
129
// The value is not live in any of the successor blocks. This means the
105
130
// block contains a last use of the value. The next instruction after
@@ -141,15 +166,17 @@ bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode,
141
166
}
142
167
}
143
168
if (needSplit) {
144
- if (mode == DontModifyCFG)
145
- return false ;
146
169
// We need to split the critical edge to create a frontier instruction.
147
170
unhandledFrontierBlocks.insert (frontierBB);
148
171
} else {
149
172
// The first instruction of the exit-block is part of the frontier.
150
173
frontier.push_back (&*frontierBB->begin ());
151
174
}
152
175
}
176
+ if (unhandledFrontierBlocks.size () == 0 ) {
177
+ return true ;
178
+ }
179
+
153
180
// Split critical edges from the lifetime region to not yet handled frontier
154
181
// blocks.
155
182
for (SILBasicBlock *frontierPred : liveOutBlocks) {
@@ -163,12 +190,17 @@ bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode,
163
190
164
191
for (unsigned i = 0 , e = succBlocks.size (); i != e; ++i) {
165
192
if (unhandledFrontierBlocks.count (succBlocks[i])) {
166
- assert (mode == AllowToModifyCFG);
167
193
assert (isCriticalEdge (term, i) && " actually not a critical edge?" );
194
+ noCriticalEdges = false ;
195
+ if (mode != AllowToModifyCFG) {
196
+ // If the CFG need not be modified, just record the critical edge and
197
+ // continue.
198
+ this ->criticalEdges .push_back ({term, i});
199
+ continue ;
200
+ }
168
201
SILBasicBlock *newBlock = splitEdge (term, i);
169
202
// The single terminator instruction is part of the frontier.
170
203
frontier.push_back (&*newBlock->begin ());
171
- noCriticalEdges = false ;
172
204
}
173
205
}
174
206
}
0 commit comments