12
12
13
13
#define DEBUG_TYPE " sil-ownership-verifier"
14
14
15
+ #include " TransitivelyUnreachableBlocks.h"
15
16
#include " swift/AST/ASTContext.h"
16
17
#include " swift/AST/AnyFunctionRef.h"
17
18
#include " swift/AST/Decl.h"
38
39
#include " llvm/ADT/StringSet.h"
39
40
#include " llvm/Support/CommandLine.h"
40
41
#include " llvm/Support/Debug.h"
42
+ #include < algorithm>
41
43
42
44
using namespace swift ;
43
45
@@ -1043,6 +1045,10 @@ class SILValueOwnershipChecker {
1043
1045
// / The module that we are in.
1044
1046
SILModule &Mod;
1045
1047
1048
+ // / A cache of unreachable function blocks that we use to determine if we can
1049
+ // / ignore "leaks".
1050
+ const TransitivelyUnreachableBlocksInfo &TUB;
1051
+
1046
1052
// / The value whose ownership we will check.
1047
1053
SILValue Value;
1048
1054
@@ -1065,7 +1071,10 @@ class SILValueOwnershipChecker {
1065
1071
llvm::SmallPtrSet<SILBasicBlock *, 8 > SuccessorBlocksThatMustBeVisited;
1066
1072
1067
1073
public:
1068
- SILValueOwnershipChecker (SILModule &M, SILValue V) : Mod(M), Value(V) {}
1074
+ SILValueOwnershipChecker (SILModule &M,
1075
+ const TransitivelyUnreachableBlocksInfo &TUB,
1076
+ SILValue V)
1077
+ : Mod(M), TUB(TUB), Value(V) {}
1069
1078
1070
1079
~SILValueOwnershipChecker () = default ;
1071
1080
SILValueOwnershipChecker (SILValueOwnershipChecker &) = delete ;
@@ -1084,6 +1093,7 @@ class SILValueOwnershipChecker {
1084
1093
private:
1085
1094
bool checkUses ();
1086
1095
void checkDataflow ();
1096
+ void checkDataflowEndConditions ();
1087
1097
void
1088
1098
gatherUsers (llvm::SmallVectorImpl<SILInstruction *> &LifetimeEndingUsers,
1089
1099
llvm::SmallVectorImpl<SILInstruction *> &NonLifetimeEndingUsers);
@@ -1106,6 +1116,8 @@ class SILValueOwnershipChecker {
1106
1116
SILBasicBlock *UserBlock);
1107
1117
1108
1118
bool checkValueWithoutLifetimeEndingUses ();
1119
+
1120
+ bool checkFunctionArgWithoutLifetimeEndingUses (SILFunctionArgument *Arg);
1109
1121
};
1110
1122
1111
1123
} // end anonymous namespace
@@ -1248,8 +1260,8 @@ void SILValueOwnershipChecker::uniqueNonLifetimeEndingUsers(
1248
1260
}
1249
1261
}
1250
1262
1251
- static bool checkFunctionArgWithoutLifetimeEndingUses (SILFunctionArgument *Arg,
1252
- SILModule &Mod ) {
1263
+ bool SILValueOwnershipChecker:: checkFunctionArgWithoutLifetimeEndingUses (
1264
+ SILFunctionArgument *Arg ) {
1253
1265
switch (Arg->getOwnershipKind ()) {
1254
1266
case ValueOwnershipKind::Guaranteed:
1255
1267
case ValueOwnershipKind::Unowned:
@@ -1262,6 +1274,9 @@ static bool checkFunctionArgWithoutLifetimeEndingUses(SILFunctionArgument *Arg,
1262
1274
break ;
1263
1275
}
1264
1276
1277
+ if (TUB.isUnreachable (Arg->getParent ()))
1278
+ return true ;
1279
+
1265
1280
llvm::errs () << " Function: '" << Arg->getFunction ()->getName () << " '\n "
1266
1281
<< " Owned function parameter without life "
1267
1282
" ending uses!\n "
@@ -1274,7 +1289,7 @@ static bool checkFunctionArgWithoutLifetimeEndingUses(SILFunctionArgument *Arg,
1274
1289
bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses () {
1275
1290
DEBUG (llvm::dbgs () << " No lifetime ending users?! Bailing early.\n " );
1276
1291
if (auto *Arg = dyn_cast<SILFunctionArgument>(Value)) {
1277
- if (checkFunctionArgWithoutLifetimeEndingUses (Arg, Mod )) {
1292
+ if (checkFunctionArgWithoutLifetimeEndingUses (Arg)) {
1278
1293
return true ;
1279
1294
}
1280
1295
}
@@ -1290,6 +1305,17 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses() {
1290
1305
if (Value.getOwnershipKind () == ValueOwnershipKind::Unowned)
1291
1306
return true ;
1292
1307
1308
+ if (auto *ParentBlock = Value->getParentBlock ()) {
1309
+ if (TUB.isUnreachable (ParentBlock)) {
1310
+ DEBUG (llvm::dbgs () << " Ignoring transitively unreachable value "
1311
+ << " without users!\n "
1312
+ << " Function: '" << Value->getFunction ()->getName ()
1313
+ << " '\n "
1314
+ << " Value: " << *Value << ' \n ' );
1315
+ return true ;
1316
+ }
1317
+ }
1318
+
1293
1319
if (!isValueAddressOrTrivial (Value, Mod)) {
1294
1320
llvm::errs () << " Function: '" << Value->getFunction ()->getName () << " '\n "
1295
1321
<< " Non trivial values, non address values, and non "
@@ -1425,6 +1451,12 @@ bool SILValueOwnershipChecker::checkUses() {
1425
1451
llvm_unreachable (" triggering standard assertion failure routine" );
1426
1452
}
1427
1453
1454
+ // If this user is in the same block as the value, do not visit
1455
+ // predecessors. We must be extra tolerant here since we allow for
1456
+ // unreachable code.
1457
+ if (UserBlock == Value->getParentBlock ())
1458
+ continue ;
1459
+
1428
1460
// Then for each predecessor of this block...
1429
1461
for (auto *Pred : UserBlock->getPredecessorBlocks ()) {
1430
1462
// If this block is not a block that we have already put on the list, add
@@ -1491,15 +1523,23 @@ void SILValueOwnershipChecker::checkDataflow() {
1491
1523
// users.
1492
1524
BlocksWithNonLifetimeEndingUses.erase (BB);
1493
1525
1494
- // Ok, now we know that we do not have an overconsume. So now we need to
1495
- // update our state for our successors to make sure by the end of the
1496
- // traversal we visit them.
1526
+ // Ok, now we know that we do not have an overconsume. If this block does
1527
+ // not end in a no return function, we need to update our state for our
1528
+ // successors to make sure by the end of the traversal we visit them.
1529
+ //
1530
+ // We must consider such no-return blocks since we may be running during
1531
+ // SILGen before NoReturn folding has run.
1497
1532
for (SILBasicBlock *SuccBlock : BB->getSuccessorBlocks ()) {
1498
1533
// If we already visited the successor, there is nothing to do since we
1499
1534
// already visited the successor.
1500
1535
if (VisitedBlocks.count (SuccBlock))
1501
1536
continue ;
1502
1537
1538
+ // Then check if the successor is a transitively unreachable block. In
1539
+ // such a case, we ignore it since we are going to leak along that path.
1540
+ if (TUB.isUnreachable (SuccBlock))
1541
+ continue ;
1542
+
1503
1543
// Otherwise, add the successor to our SuccessorBlocksThatMustBeVisited
1504
1544
// set to ensure that we assert if we do not visit it by the end of the
1505
1545
// algorithm.
@@ -1530,6 +1570,7 @@ void SILValueOwnershipChecker::checkDataflow() {
1530
1570
if (VisitedBlocks.count (PredBlock)) {
1531
1571
continue ;
1532
1572
}
1573
+
1533
1574
VisitedBlocks.insert (PredBlock);
1534
1575
Worklist.push_back (PredBlock);
1535
1576
}
@@ -1601,8 +1642,15 @@ void SILInstruction::verifyOperandOwnership() const {
1601
1642
#endif
1602
1643
}
1603
1644
1604
- void SILValue::verifyOwnership (SILModule &Mod) const {
1645
+ void SILValue::verifyOwnership (SILModule &Mod,
1646
+ TransitivelyUnreachableBlocksInfo *TUB) const {
1605
1647
#ifndef NDEBUG
1606
- SILValueOwnershipChecker (Mod, *this ).check ();
1648
+ if (TUB) {
1649
+ SILValueOwnershipChecker (Mod, *TUB, *this ).check ();
1650
+ } else {
1651
+ PostOrderFunctionInfo NewPOFI ((*this )->getFunction ());
1652
+ TransitivelyUnreachableBlocksInfo TUB (NewPOFI);
1653
+ SILValueOwnershipChecker (Mod, TUB, *this ).check ();
1654
+ }
1607
1655
#endif
1608
1656
}
0 commit comments