@@ -491,7 +491,7 @@ struct UseState {
491
491
} // namespace
492
492
493
493
// ===----------------------------------------------------------------------===//
494
- // MARK: Liveness Processor
494
+ // MARK: Global Block State
495
495
// ===----------------------------------------------------------------------===//
496
496
497
497
namespace {
@@ -522,181 +522,8 @@ struct BlockState {
522
522
: userUp(userUp), isInitDown(isInitDown) {}
523
523
};
524
524
525
- // / Post process the found liveness and emit errors if needed. TODO: Better
526
- // / name.
527
- struct LivenessChecker {
528
- MarkMustCheckInst *markedAddress;
529
- FieldSensitiveAddressPrunedLiveness &liveness;
530
- SmallBitVector livenessVector;
531
- bool hadAnyErrorUsers = false ;
532
- SmallPtrSetImpl<SILInstruction *> &inoutTermUsers;
533
- BlockState::Map &blockToState;
534
-
535
- DiagnosticEmitter &diagnosticEmitter;
536
-
537
- LivenessChecker (MarkMustCheckInst *markedAddress,
538
- FieldSensitiveAddressPrunedLiveness &liveness,
539
- SmallPtrSetImpl<SILInstruction *> &inoutTermUsers,
540
- BlockState::Map &blockToState,
541
- DiagnosticEmitter &diagnosticEmitter)
542
- : markedAddress(markedAddress), liveness(liveness),
543
- inoutTermUsers (inoutTermUsers), blockToState(blockToState),
544
- diagnosticEmitter(diagnosticEmitter) {}
545
-
546
- // / Returns true if we emitted any errors.
547
- bool
548
- compute (SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
549
- &takeUpInsts,
550
- SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
551
- &takeDownInsts);
552
-
553
- void clear () {
554
- livenessVector.clear ();
555
- hadAnyErrorUsers = false ;
556
- }
557
-
558
- std::pair<bool , bool > testInstVectorLiveness (
559
- SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
560
- &takeInsts);
561
- };
562
-
563
525
} // namespace
564
526
565
- std::pair<bool , bool > LivenessChecker::testInstVectorLiveness (
566
- SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
567
- &takeInsts) {
568
- bool emittedDiagnostic = false ;
569
- bool foundSingleBlockTakeDueToInitDown = false ;
570
-
571
- for (auto takeInstAndValue : takeInsts) {
572
- LLVM_DEBUG (llvm::dbgs () << " Checking: " << *takeInstAndValue.first );
573
-
574
- // Check if we are in the boundary...
575
- liveness.isWithinBoundary (takeInstAndValue.first , livenessVector);
576
-
577
- // If the bit vector does not contain any set bits, then we know that we did
578
- // not have any boundary violations for any leaf node of our root value.
579
- if (!livenessVector.any ()) {
580
- // TODO: Today, we don't tell the user the actual field itself where the
581
- // violation occured and just instead just shows the two instructions. We
582
- // could be more specific though...
583
- LLVM_DEBUG (llvm::dbgs () << " Not within the boundary.\n " );
584
- continue ;
585
- }
586
- LLVM_DEBUG (llvm::dbgs ()
587
- << " Within the boundary! Emitting an error\n " );
588
-
589
- // Ok, we have an error and via the bit vector know which specific leaf
590
- // elements of our root type were within the per field boundary. We need to
591
- // go find the next reachable use that overlap with its sub-element. We only
592
- // emit a single error per use even if we get multiple sub elements that
593
- // match it. That helps reduce the amount of errors.
594
- //
595
- // DISCUSSION: It is important to note that this follows from the separation
596
- // of concerns behind this pass: we have simplified how we handle liveness
597
- // by losing this information. That being said, since we are erroring it is
598
- // ok that we are taking a little more time since we are not going to
599
- // codegen this code.
600
- //
601
- // That being said, set the flag that we saw at least one error, so we can
602
- // exit early after this loop.
603
- hadAnyErrorUsers = true ;
604
-
605
- // B/c of the separation of concerns with our liveness, we now need to walk
606
- // blocks to go find the specific later takes that are reachable from this
607
- // take. It is ok that we are doing a bit more work here since we are going
608
- // to exit and not codegen.
609
- auto *errorUser = takeInstAndValue.first ;
610
-
611
- // Before we do anything, grab the state for our errorUser's block from the
612
- // blockState and check if it is an init block. If so, we have no further
613
- // work to do since we already found correctness due to our single basic
614
- // block check. So, we have nothing further to do.
615
- if (blockToState.find (errorUser->getParent ())->second .isInitDown ) {
616
- // Set the flag that we saw an init down so that our assert later that we
617
- // actually emitted an error doesn't trigger.
618
- foundSingleBlockTakeDueToInitDown = true ;
619
- continue ;
620
- }
621
-
622
- BasicBlockWorklist worklist (errorUser->getFunction ());
623
- for (auto *succBlock : errorUser->getParent ()->getSuccessorBlocks ())
624
- worklist.pushIfNotVisited (succBlock);
625
-
626
- LLVM_DEBUG (llvm::dbgs () << " Performing forward traversal from errorUse "
627
- " looking for the cause of liveness!\n " );
628
-
629
- while (auto *block = worklist.pop ()) {
630
- LLVM_DEBUG (llvm::dbgs ()
631
- << " Visiting block: bb" << block->getDebugID () << " \n " );
632
- auto iter = blockToState.find (block);
633
- if (iter == blockToState.end ()) {
634
- LLVM_DEBUG (llvm::dbgs () << " No State! Skipping!\n " );
635
- for (auto *succBlock : block->getSuccessorBlocks ())
636
- worklist.pushIfNotVisited (succBlock);
637
- continue ;
638
- }
639
-
640
- auto *blockUser = iter->second .userUp ;
641
-
642
- if (blockUser) {
643
- LLVM_DEBUG (llvm::dbgs () << " Found userUp: " << *blockUser);
644
- auto info = liveness.isInterestingUser (blockUser);
645
- // Make sure that it overlaps with our range...
646
- if (info.second ->contains (*info.second )) {
647
- LLVM_DEBUG (llvm::dbgs () << " Emitted diagnostic for it!\n " );
648
- // and if it does... emit our diagnostic and continue to see if we
649
- // find errors along other paths.
650
- // if (invalidUsesWithDiagnostics.insert(errorUser
651
- bool isConsuming =
652
- info.first ==
653
- FieldSensitiveAddressPrunedLiveness::LifetimeEndingUse;
654
- diagnosticEmitter.emitAddressDiagnostic (
655
- markedAddress, blockUser, errorUser, isConsuming,
656
- inoutTermUsers.count (blockUser));
657
- emittedDiagnostic = true ;
658
- continue ;
659
- }
660
- }
661
-
662
- // Otherwise, add successors and continue! We didn't overlap with this
663
- // use.
664
- LLVM_DEBUG (llvm::dbgs () << " Does not overlap at the type level, no "
665
- " diagnostic! Visiting successors!\n " );
666
- for (auto *succBlock : block->getSuccessorBlocks ())
667
- worklist.pushIfNotVisited (succBlock);
668
- }
669
- }
670
-
671
- return {emittedDiagnostic, foundSingleBlockTakeDueToInitDown};
672
- }
673
-
674
- bool LivenessChecker::compute (
675
- SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
676
- &takeUpInsts,
677
- SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
678
- &takeDownInsts) {
679
- // Then revisit our takes, this time checking if we are within the boundary
680
- // and if we are, emit an error.
681
- LLVM_DEBUG (llvm::dbgs () << " Checking takes for errors!\n " );
682
- bool emittedDiagnostic = false ;
683
- bool foundSingleBlockTakeDueToInitDown = false ;
684
-
685
- auto pair = testInstVectorLiveness (takeUpInsts);
686
- emittedDiagnostic |= pair.first ;
687
- foundSingleBlockTakeDueToInitDown |= pair.second ;
688
-
689
- pair = testInstVectorLiveness (takeDownInsts);
690
- emittedDiagnostic |= pair.first ;
691
- foundSingleBlockTakeDueToInitDown |= pair.second ;
692
-
693
- // If we emitted an error user, we should always emit at least one
694
- // diagnostic. If we didn't there is a bug in the implementation.
695
- assert (!hadAnyErrorUsers || emittedDiagnostic ||
696
- foundSingleBlockTakeDueToInitDown);
697
- return hadAnyErrorUsers;
698
- }
699
-
700
527
// ===----------------------------------------------------------------------===//
701
528
// MARK: Forward Declaration of Main Checker
702
529
// ===----------------------------------------------------------------------===//
@@ -1471,6 +1298,174 @@ void BlockSummaries::initializeLiveness(
1471
1298
}
1472
1299
}
1473
1300
1301
+ // ===----------------------------------------------------------------------===//
1302
+ // MARK: Global Dataflow
1303
+ // ===----------------------------------------------------------------------===//
1304
+
1305
+ namespace {
1306
+
1307
+ // / Post process the found liveness and emit errors if needed. TODO: Better
1308
+ // / name.
1309
+ struct GlobalDataflow {
1310
+ BlockSummaries &summaries;
1311
+ FieldSensitiveAddressPrunedLiveness &liveness;
1312
+ SmallPtrSetImpl<SILInstruction *> &inoutTermInstUsers;
1313
+ SmallBitVector livenessVector;
1314
+ bool hadAnyErrorUsers = false ;
1315
+
1316
+ GlobalDataflow (BlockSummaries &summaries,
1317
+ FieldSensitiveAddressPrunedLiveness &liveness,
1318
+ SmallPtrSetImpl<SILInstruction *> &inoutTermInstUsers)
1319
+ : summaries(summaries), liveness(liveness),
1320
+ inoutTermInstUsers (inoutTermInstUsers) {}
1321
+
1322
+ // / Returns true if we emitted any errors.
1323
+ bool compute ();
1324
+
1325
+ void clear () {
1326
+ livenessVector.clear ();
1327
+ hadAnyErrorUsers = false ;
1328
+ }
1329
+
1330
+ std::pair<bool , bool > testInstVectorLiveness (
1331
+ SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
1332
+ &instsToTest);
1333
+ BlockState::Map &getBlockToState () const { return summaries.blockToState ; }
1334
+ };
1335
+
1336
+ } // namespace
1337
+
1338
+ std::pair<bool , bool > GlobalDataflow::testInstVectorLiveness (
1339
+ SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
1340
+ &instsToTest) {
1341
+ bool emittedDiagnostic = false ;
1342
+ bool foundSingleBlockTakeDueToInitDown = false ;
1343
+
1344
+ for (auto takeInstAndValue : instsToTest) {
1345
+ LLVM_DEBUG (llvm::dbgs () << " Checking: " << *takeInstAndValue.first );
1346
+
1347
+ // Check if we are in the boundary...
1348
+ liveness.isWithinBoundary (takeInstAndValue.first , livenessVector);
1349
+
1350
+ // If the bit vector does not contain any set bits, then we know that we did
1351
+ // not have any boundary violations for any leaf node of our root value.
1352
+ if (!livenessVector.any ()) {
1353
+ // TODO: Today, we don't tell the user the actual field itself where the
1354
+ // violation occured and just instead just shows the two instructions. We
1355
+ // could be more specific though...
1356
+ LLVM_DEBUG (llvm::dbgs () << " Not within the boundary.\n " );
1357
+ continue ;
1358
+ }
1359
+ LLVM_DEBUG (llvm::dbgs ()
1360
+ << " Within the boundary! Emitting an error\n " );
1361
+
1362
+ // Ok, we have an error and via the bit vector know which specific leaf
1363
+ // elements of our root type were within the per field boundary. We need to
1364
+ // go find the next reachable use that overlap with its sub-element. We only
1365
+ // emit a single error per use even if we get multiple sub elements that
1366
+ // match it. That helps reduce the amount of errors.
1367
+ //
1368
+ // DISCUSSION: It is important to note that this follows from the separation
1369
+ // of concerns behind this pass: we have simplified how we handle liveness
1370
+ // by losing this information. That being said, since we are erroring it is
1371
+ // ok that we are taking a little more time since we are not going to
1372
+ // codegen this code.
1373
+ //
1374
+ // That being said, set the flag that we saw at least one error, so we can
1375
+ // exit early after this loop.
1376
+ hadAnyErrorUsers = true ;
1377
+
1378
+ // B/c of the separation of concerns with our liveness, we now need to walk
1379
+ // blocks to go find the specific later takes that are reachable from this
1380
+ // take. It is ok that we are doing a bit more work here since we are going
1381
+ // to exit and not codegen.
1382
+ auto *errorUser = takeInstAndValue.first ;
1383
+
1384
+ // Before we do anything, grab the state for our errorUser's block from the
1385
+ // blockState and check if it is an init block. If so, we have no further
1386
+ // work to do since we already found correctness due to our single basic
1387
+ // block check. So, we have nothing further to do.
1388
+ if (getBlockToState ().find (errorUser->getParent ())->second .isInitDown ) {
1389
+ // Set the flag that we saw an init down so that our assert later that we
1390
+ // actually emitted an error doesn't trigger.
1391
+ foundSingleBlockTakeDueToInitDown = true ;
1392
+ continue ;
1393
+ }
1394
+
1395
+ BasicBlockWorklist worklist (errorUser->getFunction ());
1396
+ for (auto *succBlock : errorUser->getParent ()->getSuccessorBlocks ())
1397
+ worklist.pushIfNotVisited (succBlock);
1398
+
1399
+ LLVM_DEBUG (llvm::dbgs () << " Performing forward traversal from errorUse "
1400
+ " looking for the cause of liveness!\n " );
1401
+
1402
+ while (auto *block = worklist.pop ()) {
1403
+ LLVM_DEBUG (llvm::dbgs ()
1404
+ << " Visiting block: bb" << block->getDebugID () << " \n " );
1405
+ auto iter = getBlockToState ().find (block);
1406
+ if (iter == getBlockToState ().end ()) {
1407
+ LLVM_DEBUG (llvm::dbgs () << " No State! Skipping!\n " );
1408
+ for (auto *succBlock : block->getSuccessorBlocks ())
1409
+ worklist.pushIfNotVisited (succBlock);
1410
+ continue ;
1411
+ }
1412
+
1413
+ auto *blockUser = iter->second .userUp ;
1414
+
1415
+ if (blockUser) {
1416
+ LLVM_DEBUG (llvm::dbgs () << " Found userUp: " << *blockUser);
1417
+ auto info = liveness.isInterestingUser (blockUser);
1418
+ // Make sure that it overlaps with our range...
1419
+ if (info.second ->contains (*info.second )) {
1420
+ LLVM_DEBUG (llvm::dbgs () << " Emitted diagnostic for it!\n " );
1421
+ // and if it does... emit our diagnostic and continue to see if we
1422
+ // find errors along other paths.
1423
+ // if (invalidUsesWithDiagnostics.insert(errorUser
1424
+ bool isConsuming =
1425
+ info.first ==
1426
+ FieldSensitiveAddressPrunedLiveness::LifetimeEndingUse;
1427
+ summaries.diagnosticEmitter .emitAddressDiagnostic (
1428
+ summaries.markedAddress , blockUser, errorUser, isConsuming,
1429
+ inoutTermInstUsers.count (blockUser));
1430
+ emittedDiagnostic = true ;
1431
+ continue ;
1432
+ }
1433
+ }
1434
+
1435
+ // Otherwise, add successors and continue! We didn't overlap with this
1436
+ // use.
1437
+ LLVM_DEBUG (llvm::dbgs () << " Does not overlap at the type level, no "
1438
+ " diagnostic! Visiting successors!\n " );
1439
+ for (auto *succBlock : block->getSuccessorBlocks ())
1440
+ worklist.pushIfNotVisited (succBlock);
1441
+ }
1442
+ }
1443
+
1444
+ return {emittedDiagnostic, foundSingleBlockTakeDueToInitDown};
1445
+ }
1446
+
1447
+ bool GlobalDataflow::compute () {
1448
+ // Then revisit our takes, this time checking if we are within the boundary
1449
+ // and if we are, emit an error.
1450
+ LLVM_DEBUG (llvm::dbgs () << " Checking takes for errors!\n " );
1451
+ bool emittedDiagnostic = false ;
1452
+ bool foundSingleBlockTakeDueToInitDown = false ;
1453
+
1454
+ auto pair = testInstVectorLiveness (summaries.takeUpInsts );
1455
+ emittedDiagnostic |= pair.first ;
1456
+ foundSingleBlockTakeDueToInitDown |= pair.second ;
1457
+
1458
+ pair = testInstVectorLiveness (summaries.takeDownInsts );
1459
+ emittedDiagnostic |= pair.first ;
1460
+ foundSingleBlockTakeDueToInitDown |= pair.second ;
1461
+
1462
+ // If we emitted an error user, we should always emit at least one
1463
+ // diagnostic. If we didn't there is a bug in the implementation.
1464
+ assert (!hadAnyErrorUsers || emittedDiagnostic ||
1465
+ foundSingleBlockTakeDueToInitDown);
1466
+ return hadAnyErrorUsers;
1467
+ }
1468
+
1474
1469
// ===----------------------------------------------------------------------===//
1475
1470
// MARK: Main Pass Implementation
1476
1471
// ===----------------------------------------------------------------------===//
@@ -1649,19 +1644,17 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
1649
1644
FieldSensitiveAddressPrunedLiveness liveness (fn, markedAddress,
1650
1645
&discoveredBlocks);
1651
1646
SmallPtrSet<SILInstruction *, 8 > inoutTermUsers;
1652
-
1653
1647
summaries.initializeLiveness (liveness, inoutTermUsers);
1654
1648
1655
1649
// If we have multiple blocks in the function, now run the global pruned
1656
1650
// liveness dataflow.
1657
1651
if (std::next (fn->begin ()) != fn->end ()) {
1658
1652
// Then compute the takes that are within the cumulative boundary of
1659
1653
// liveness that we have computed. If we find any, they are the errors ones.
1660
- LivenessChecker emitter (markedAddress, liveness, inoutTermUsers,
1661
- summaries.blockToState , diagnosticEmitter);
1654
+ GlobalDataflow emitter (summaries, liveness, inoutTermUsers);
1662
1655
1663
1656
// If we had any errors, we do not want to modify the SIL... just bail.
1664
- if (emitter.compute (summaries. takeUpInsts , summaries. takeDownInsts )) {
1657
+ if (emitter.compute ()) {
1665
1658
// TODO: Remove next line.
1666
1659
valuesWithDiagnostics.insert (markedAddress);
1667
1660
return true ;
0 commit comments