20
20
#include " swift/SIL/BitDataflow.h"
21
21
#include " swift/SIL/BasicBlockBits.h"
22
22
#include " swift/SIL/DebugUtils.h"
23
+ #include " swift/SIL/BasicBlockDatastructures.h"
23
24
#include " swift/SILOptimizer/PassManager/Transforms.h"
24
25
25
26
using namespace swift ;
@@ -277,34 +278,13 @@ SILInstruction *AnalysisInfo::findNonisolatedBlame(SILInstruction* startInst) {
277
278
SILBasicBlock* firstBlk = startInst->getParent ();
278
279
assert (firstBlk->getParent () == getFunction ());
279
280
280
- // workList for breadth-first search to find one of the closest blocks.
281
- std::deque<SILBasicBlock*> workList;
282
- BasicBlockSet visited (getFunction ());
283
-
284
- // seed the search
285
- workList.push_back (firstBlk);
286
- SILBasicBlock::reverse_iterator cursor = startInst->getReverseIterator ();
287
-
288
- while (!workList.empty ()) {
289
- auto *block = workList.front ();
290
- workList.pop_front ();
281
+ // searches the a block starting at the provided position in reverse
282
+ // order of instructions (i.e., from terminator to first instruction).
283
+ auto searchBlockForNonisolated =
284
+ [&](SILBasicBlock::reverse_iterator cursor) -> SILInstruction * {
285
+ SILBasicBlock *block = cursor->getParent ();
291
286
auto &state = flow[block];
292
287
293
- // if this block doesn't have exiting nonisolation, then there's no
294
- // way we'll find nonisolation in a predecessor.
295
- assert (state.exitSet [State::Nonisolated] && " nonisolation is unreachable!" );
296
-
297
- // If this is the first time we're scanning the start block, then leave
298
- // the cursor alone and do a partial scan. If the block is part of
299
- // a cycle, we want to scan the block entirely on the second visit, so we
300
- // do not count this as a visit.
301
- if (startInst) {
302
- startInst = nullptr ; // make sure second visit scans entirely.
303
- } else {
304
- cursor = block->rbegin ();
305
- visited.insert (block);
306
- }
307
-
308
288
// does this block generate non-isolation?
309
289
if (state.genSet [State::Nonisolated]) {
310
290
auto &data = this ->operator [](block);
@@ -321,16 +301,36 @@ SILInstruction *AnalysisInfo::findNonisolatedBlame(SILInstruction* startInst) {
321
301
}
322
302
}
323
303
324
- for (auto *pred : block->getPredecessorBlocks ()) {
325
- // skip visited
326
- if (visited.contains (pred))
327
- continue ;
304
+ return nullptr ;
305
+ };
306
+
307
+ // whether we should visit a given predecessor block in the search.
308
+ auto shouldVisit = [&](SILBasicBlock *pred) {
309
+ // visit blocks that contribute nonisolation to successors.
310
+ return flow[pred].exitSet [State::Nonisolated];
311
+ };
328
312
329
- // skip blocks that do not contribute nonisolation.
330
- if (flow[pred].exitSet [State::Nonisolated] == false )
331
- continue ;
313
+ // first check if the nonisolated use precedes the start instruction in
314
+ // this same block.
315
+ if (auto *inst = searchBlockForNonisolated (startInst->getReverseIterator ()))
316
+ return inst;
332
317
333
- workList.push_back (pred);
318
+ // Seed a workQueue with the predecessors of this start block to
319
+ // begin a breadth-first search to find one of the closest predecessors.
320
+ BasicBlockWorkqueue workQueue (firstBlk->getFunction ());
321
+ for (auto *pred : firstBlk->getPredecessorBlocks ())
322
+ if (shouldVisit (pred))
323
+ workQueue.push (pred);
324
+
325
+ while (auto *block = workQueue.pop ()) {
326
+ // do we have a nonisolated use here?
327
+ if (auto *inst = searchBlockForNonisolated (block->rbegin ()))
328
+ return inst;
329
+
330
+ // otherwise keep looking
331
+ for (auto *pred : block->getPredecessorBlocks ()) {
332
+ if (shouldVisit (pred))
333
+ workQueue.pushIfNotVisited (pred);
334
334
}
335
335
}
336
336
0 commit comments