@@ -90,28 +90,21 @@ SILInstruction *ValueLifetimeAnalysis::findLastUserInBlock(SILBasicBlock *bb) {
90
90
llvm_unreachable (" Expected to find use of value in block!" );
91
91
}
92
92
93
- bool ValueLifetimeAnalysis::computeFrontier (FrontierImpl &frontier, Mode mode,
94
- DeadEndBlocks *deBlocks) {
93
+ // FIXME: remove the visitBlock callback once DeadEndBlocks is removed.
94
+ void ValueLifetimeAnalysis::computeLifetime (
95
+ llvm::function_ref<bool (SILBasicBlock *)> visitBlock,
96
+ llvm::function_ref<void(SILInstruction *)> visitLastUser,
97
+ llvm::function_ref<void(SILBasicBlock *predBB, SILBasicBlock *succBB)>
98
+ visitBoundaryEdge) {
95
99
assert (!isAliveAtBeginOfBlock (getFunction ()->getEntryBlock ()) &&
96
100
" Can't compute frontier for def which does not dominate all uses" );
97
101
98
- bool noCriticalEdges = true ;
99
-
100
- // Exit-blocks from the lifetime region. The value is live at the end of
101
- // a predecessor block but not in the frontier block itself.
102
- BasicBlockSetVector<16 > frontierBlocks (getFunction ());
103
-
104
- // Blocks where the value is live at the end of the block and which have
105
- // a frontier block as successor.
106
- BasicBlockSetVector<16 > liveOutBlocks (getFunction ());
107
-
108
102
// / The lifetime ends if we have a live block and a not-live successor.
109
103
for (SILBasicBlock *bb : liveBlocks) {
110
- if (deBlocks && deBlocks-> isDeadEnd (bb))
104
+ if (! visitBlock (bb))
111
105
continue ;
112
106
113
107
bool liveInSucc = false ;
114
- bool deadInSucc = false ;
115
108
bool usedAndRedefinedInSucc = false ;
116
109
for (const SILSuccessor &succ : bb->getSuccessors ()) {
117
110
if (isAliveAtBeginOfBlock (succ)) {
@@ -128,63 +121,120 @@ bool ValueLifetimeAnalysis::computeFrontier(FrontierImpl &frontier, Mode mode,
128
121
" blocks" );
129
122
usedAndRedefinedInSucc = true ;
130
123
}
131
- } else if (!deBlocks || !deBlocks->isDeadEnd (succ)) {
132
- deadInSucc = true ;
133
124
}
134
125
}
135
126
if (usedAndRedefinedInSucc) {
136
127
// Here, the basic block bb uses the value and later redefines the value.
137
128
// Therefore, this value's lifetime ends after its last use preceding the
138
129
// re-definition of the value.
139
- //
140
- // We know that we can not have a SILArgument here since the SILArgument
141
- // dominates all instructions in the same block.
142
130
auto ii = defValue.get <SILInstruction *>()->getReverseIterator ();
143
131
for (; ii != bb->rend (); ++ii) {
144
132
if (userSet.count (&*ii)) {
145
- frontier. push_back (&*std::next (ii) );
133
+ visitLastUser (&*ii );
146
134
break ;
147
135
}
148
136
}
149
137
assert (ii != bb->rend () &&
150
138
" There must be a user in bb before definition" );
151
139
}
152
- if (!liveInSucc) {
153
- // The value is not live in any of the successor blocks. This means the
154
- // block contains a last use of the value. The next instruction after
155
- // the last use is part of the frontier.
156
- SILInstruction *lastUser = findLastUserInBlock (bb);
157
- if (!isa<TermInst>(lastUser)) {
158
- frontier.push_back (&*std::next (lastUser->getIterator ()));
159
- continue ;
160
- }
161
- // In case the last user is a TermInst there is no further instruction in
162
- // the block which can be the frontier. Instead we add all successor
163
- // blocks to the frontier (see below).
164
- // If the TermInst exits the function (e.g. 'return' or 'throw'), there
165
- // are no successors and we have to bail.
166
- if (!deadInSucc) {
167
- assert (cast<TermInst>(lastUser)->isFunctionExiting () &&
168
- " The final using TermInst must have successors" );
169
- assert (mode != AllowToModifyCFG &&
170
- " Cannot bail if the mode is AllowToModifyCFG" );
171
- return false ;
172
- }
173
- }
174
- if (deadInSucc) {
175
- if (mode == UsersMustPostDomDef)
176
- return false ;
177
-
178
- // The value is not live in some of the successor blocks.
179
- liveOutBlocks.insert (bb);
140
+ if (liveInSucc) {
180
141
for (const SILSuccessor &succ : bb->getSuccessors ()) {
181
- if (!isAliveAtBeginOfBlock (succ)) {
182
- // It's an "exit" edge from the lifetime region.
183
- frontierBlocks.insert (succ);
184
- }
142
+ if (!isAliveAtBeginOfBlock (succ))
143
+ visitBoundaryEdge (bb, succ);
185
144
}
145
+ } else {
146
+ // The value is not live in any of the successor blocks. This means the
147
+ // block contains a last use of the value.
148
+ visitLastUser (findLastUserInBlock (bb));
186
149
}
187
150
}
151
+ }
152
+
153
+ // Compute a LifetimeBoundary.
154
+ //
155
+ // Precondition: no critical edges.
156
+ void ValueLifetimeAnalysis::computeLifetimeBoundary (
157
+ ValueLifetimeBoundary &boundary) {
158
+ auto visitBlock = [&](SILBasicBlock *) { return true ; };
159
+ auto visitLastUser = [&](SILInstruction *lastUser) {
160
+ boundary.lastUsers .push_back (lastUser);
161
+ };
162
+ auto visitBoundaryEdge = [&](SILBasicBlock *, SILBasicBlock *succBB) {
163
+ boundary.boundaryEdges .push_back (succBB);
164
+ };
165
+ computeLifetime (visitBlock, visitLastUser, visitBoundaryEdge);
166
+ }
167
+
168
+ // FIXME: There is no need for a Mode within the algorithm once critical edges
169
+ // are universally prohibited.
170
+ //
171
+ // FIXME: DeadEndBlocks does not affect value lifetime. It
172
+ // should be completely removed and handled by the client.
173
+ bool ValueLifetimeAnalysis::computeFrontier (FrontierImpl &frontier, Mode mode,
174
+ DeadEndBlocks *deBlocks) {
175
+ bool noCriticalEdges = true ;
176
+
177
+ // Exit-blocks from the lifetime region. The value is live at the end of
178
+ // a predecessor block but not in the frontier block itself.
179
+ BasicBlockSetVector<16 > frontierBlocks (getFunction ());
180
+
181
+ // Blocks where the value is live at the end of the block and which have
182
+ // a frontier block as successor.
183
+ BasicBlockSetVector<16 > liveOutBlocks (getFunction ());
184
+
185
+ auto visitBlock = [&](SILBasicBlock *bb) {
186
+ return !deBlocks || !deBlocks->isDeadEnd (bb);
187
+ };
188
+
189
+ bool foundInvalidLastUser = false ;
190
+ auto visitLastUser = [&](SILInstruction *lastUser) {
191
+ if (!isa<TermInst>(lastUser)) {
192
+ // The next instruction after the last use is part of the frontier.
193
+ frontier.push_back (&*std::next (lastUser->getIterator ()));
194
+ return ;
195
+ }
196
+ // FIXME: DeadObjectElimination and StackPromotion don't currently handle
197
+ // last use terminators, for no good reason. Fix them, then remove the silly
198
+ // UsersMustPostDomDef mode.
199
+ if (mode == UsersMustPostDomDef) {
200
+ foundInvalidLastUser = true ;
201
+ return ;
202
+ }
203
+ // The last user is a TermInst, and the value is not live into any successor
204
+ // blocks (the usedAndRedefinedInSucc case is never a terminator). Since
205
+ // there is no further instruction in the block which can be the
206
+ // frontier, add all successor blocks to the frontier.
207
+ auto *termBB = lastUser->getParent ();
208
+ for (const SILSuccessor &succ : termBB->getSuccessors ()) {
209
+ assert (!isAliveAtBeginOfBlock (succ)
210
+ && " out-of-sync with computeLifetime" );
211
+
212
+ if (deBlocks && deBlocks->isDeadEnd (succ))
213
+ continue ;
214
+
215
+ // The successor's first instruction will be added to the frontier. Fake
216
+ // this block as live-out so edge splitting works.
217
+ liveOutBlocks.insert (termBB);
218
+ frontierBlocks.insert (succ);
219
+ }
220
+ };
221
+ auto visitBoundaryEdge = [&](SILBasicBlock *predBB, SILBasicBlock *succBB) {
222
+ if (deBlocks && deBlocks->isDeadEnd (succBB))
223
+ return ;
224
+
225
+ if (mode == UsersMustPostDomDef) {
226
+ foundInvalidLastUser = true ;
227
+ return ;
228
+ }
229
+ liveOutBlocks.insert (predBB);
230
+ frontierBlocks.insert (succBB);
231
+ };
232
+
233
+ // Populate frontierBlocks and call visitLastUser().
234
+ computeLifetime (visitBlock, visitLastUser, visitBoundaryEdge);
235
+ if (foundInvalidLastUser)
236
+ return false ;
237
+
188
238
// Handle "exit" edges from the lifetime region.
189
239
BasicBlockSet unhandledFrontierBlocks (getFunction ());
190
240
bool unhandledFrontierBlocksFound = false ;
0 commit comments