@@ -98,19 +98,19 @@ struct State {
98
98
SILBasicBlock *userBlock);
99
99
100
100
// / Once we have marked all of our producing blocks.
101
- bool checkPredsForDoubleConsume (BranchPropagatedUser consumingUser,
101
+ void checkPredsForDoubleConsume (BranchPropagatedUser consumingUser,
102
102
SILBasicBlock *userBlock);
103
- bool checkPredsForDoubleConsume (SILBasicBlock *userBlock);
103
+ void checkPredsForDoubleConsume (SILBasicBlock *userBlock);
104
104
105
105
// / Once we have setup all of our consuming/non-consuming blocks and have
106
106
// / validated that all intra-block dataflow is safe, perform the inter-block
107
107
// / dataflow.
108
- bool performDataflow (DeadEndBlocks &deBlocks);
108
+ void performDataflow (DeadEndBlocks &deBlocks);
109
109
110
110
// / After we have performed the dataflow, check the end state of our dataflow
111
111
// / for validity. If this is a linear typed value, return true. Return false
112
112
// / otherwise.
113
- bool checkDataflowEndState (DeadEndBlocks &deBlocks);
113
+ void checkDataflowEndState (DeadEndBlocks &deBlocks);
114
114
};
115
115
116
116
} // end anonymous namespace
@@ -166,8 +166,7 @@ void State::initializeAllNonConsumingUses(
166
166
167
167
void State::initializeAllConsumingUses (
168
168
ArrayRef<BranchPropagatedUser> consumingUses,
169
- SmallVectorImpl<std::pair<BranchPropagatedUser, SILBasicBlock *>>
170
- &predsToAddToWorklist) {
169
+ SmallVectorImpl<BrPropUserAndBlockPair> &predsToAddToWorklist) {
171
170
for (BranchPropagatedUser user : consumingUses) {
172
171
SILBasicBlock *userBlock = user.getParent ();
173
172
@@ -271,41 +270,58 @@ void State::checkForSameBlockUseAfterFree(BranchPropagatedUser consumingUser,
271
270
return ;
272
271
}
273
272
274
- bool State::checkPredsForDoubleConsume (BranchPropagatedUser consumingUser,
273
+ void State::checkPredsForDoubleConsume (BranchPropagatedUser consumingUser,
275
274
SILBasicBlock *userBlock) {
276
275
if (!blocksWithConsumingUses.count (userBlock))
277
- return false ;
276
+ return ;
277
+
278
+ // Check if this is a block that we have already visited. This means that we
279
+ // had a back edge of some sort. Double check that we haven't missed any
280
+ // successors.
281
+ if (visitedBlocks.count (userBlock)) {
282
+ for (auto *succ : userBlock->getSuccessorBlocks ()) {
283
+ if (!visitedBlocks.count (succ)) {
284
+ successorBlocksThatMustBeVisited.insert (succ);
285
+ }
286
+ }
287
+ }
278
288
279
289
error.handleOverConsume ([&] {
280
290
llvm::errs () << " Function: '" << value->getFunction ()->getName () << " '\n "
281
291
<< " Found over consume?!\n "
282
292
<< " Value: " << *value << " User: " << *consumingUser
283
293
<< " Block: bb" << userBlock->getDebugID () << " \n\n " ;
284
294
});
285
-
286
- // If we reached this point, then we did not assert, but we did flag an
287
- // error. Return true so we continue the walk.
288
- return true ;
289
295
}
290
296
291
- bool State::checkPredsForDoubleConsume (SILBasicBlock *userBlock) {
297
+ void State::checkPredsForDoubleConsume (SILBasicBlock *userBlock) {
292
298
if (!blocksWithConsumingUses.count (userBlock))
293
- return false ;
299
+ return ;
300
+
301
+ // Check if this is a block that we have already visited. This means that we
302
+ // had a back edge of some sort. Double check that we haven't missed any
303
+ // successors.
304
+ if (visitedBlocks.count (userBlock)) {
305
+ for (auto *succ : userBlock->getSuccessorBlocks ()) {
306
+ if (!visitedBlocks.count (succ)) {
307
+ successorBlocksThatMustBeVisited.insert (succ);
308
+ }
309
+ }
310
+ }
294
311
295
312
error.handleOverConsume ([&] {
296
313
llvm::errs () << " Function: '" << value->getFunction ()->getName () << " '\n "
297
314
<< " Found over consume?!\n "
298
315
<< " Value: " << *value << " Block: bb"
299
316
<< userBlock->getDebugID () << " \n\n " ;
300
317
});
301
- return true ;
302
318
}
303
319
304
320
// ===----------------------------------------------------------------------===//
305
321
// Dataflow
306
322
// ===----------------------------------------------------------------------===//
307
323
308
- bool State::performDataflow (DeadEndBlocks &deBlocks) {
324
+ void State::performDataflow (DeadEndBlocks &deBlocks) {
309
325
LLVM_DEBUG (llvm::dbgs () << " Beginning to check dataflow constraints\n " );
310
326
// Until the worklist is empty...
311
327
while (!worklist.empty ()) {
@@ -366,11 +382,7 @@ bool State::performDataflow(DeadEndBlocks &deBlocks) {
366
382
// 2. We add the predecessor to the worklist if we have not visited it yet.
367
383
for (auto *predBlock : block->getPredecessorBlocks ()) {
368
384
// Check if we have an over consume.
369
- if (checkPredsForDoubleConsume (predBlock)) {
370
- // If we were to assert, it is handled inside check preds for double
371
- // consume. So just return false so that we bail.
372
- return false ;
373
- }
385
+ checkPredsForDoubleConsume (predBlock);
374
386
375
387
if (visitedBlocks.count (predBlock)) {
376
388
continue ;
@@ -380,15 +392,9 @@ bool State::performDataflow(DeadEndBlocks &deBlocks) {
380
392
worklist.push_back (predBlock);
381
393
}
382
394
}
383
-
384
- return true ;
385
395
}
386
396
387
- bool State::checkDataflowEndState (DeadEndBlocks &deBlocks) {
388
- // Make sure that we visited all successor blocks that we needed to visit to
389
- // make sure we didn't leak.
390
- bool doesntHaveAnyLeaks = true ;
391
-
397
+ void State::checkDataflowEndState (DeadEndBlocks &deBlocks) {
392
398
if (!successorBlocksThatMustBeVisited.empty ()) {
393
399
// If we are asked to store any leaking blocks, put them in the leaking
394
400
// blocks array.
@@ -412,13 +418,12 @@ bool State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
412
418
413
419
// Otherwise... see if we have any other failures. This signals the user
414
420
// wants us to tell it where to insert compensating destroys.
415
- doesntHaveAnyLeaks = false ;
416
421
}
417
422
418
423
// Make sure that we do not have any lifetime ending uses left to visit that
419
424
// are not transitively unreachable blocks.... so return early.
420
425
if (blocksWithNonConsumingUses.empty ()) {
421
- return doesntHaveAnyLeaks ;
426
+ return ;
422
427
}
423
428
424
429
// If we do have remaining blocks, then these non lifetime ending uses must be
@@ -439,12 +444,7 @@ bool State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
439
444
}
440
445
llvm::errs () << " \n " ;
441
446
});
442
- return false ;
443
447
}
444
-
445
- // If all of our remaining blocks were dead uses, then return true. We are
446
- // good.
447
- return doesntHaveAnyLeaks;
448
448
}
449
449
450
450
// ===----------------------------------------------------------------------===//
@@ -506,19 +506,17 @@ LinearLifetimeError swift::valueHasLinearLifetime(
506
506
507
507
// Make sure that the predecessor is not in our blocksWithConsumingUses
508
508
// list.
509
- if (state.checkPredsForDoubleConsume (user, predBlock)) {
510
- return state.error ;
511
- }
509
+ state.checkPredsForDoubleConsume (user, predBlock);
512
510
513
511
if (!state.visitedBlocks .insert (predBlock).second )
514
512
continue ;
513
+
515
514
state.worklist .push_back (predBlock);
516
515
}
517
516
518
517
// Now that our algorithm is completely prepared, run the
519
518
// dataflow... If we find a failure, return false.
520
- if (!state.performDataflow (deBlocks))
521
- return state.error ;
519
+ state.performDataflow (deBlocks);
522
520
523
521
// ...and then check that the end state shows that we have a valid linear
524
522
// typed value.
0 commit comments