Skip to content

Commit 425221e

Browse files
authored
Merge pull request #19173 from gottesmm/pr-0290cd4323dba0b496df6aaa44c48ee171f647fa
[sil-ownership] Tighten up the verification of guaranteed phi arguments.
2 parents eb75ad8 + 42498ad commit 425221e

File tree

5 files changed

+557
-40
lines changed

5 files changed

+557
-40
lines changed

lib/SIL/LinearLifetimeChecker.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ void State::initializeAllNonConsumingUses(
148148
// dataflow, we only need the last non-consuming use to show that all
149149
// consuming uses post dominate both.
150150
//
151-
// We begin by checking if the first use is a cond_br use from the previous
152-
// block. In such a case, we always use the already stored value and
153-
// continue.
151+
// We begin by checking if the second use is a cond_br use from the previous
152+
// block. In such a case, we always use the already stored value and since
153+
// it is guaranteed to be later than the cond_br use.
154154
if (user.isCondBranchUser()) {
155155
continue;
156156
}
@@ -179,6 +179,7 @@ bool State::initializeAllConsumingUses(
179179
ArrayRef<BranchPropagatedUser> consumingUses,
180180
SmallVectorImpl<std::pair<BranchPropagatedUser, SILBasicBlock *>>
181181
&predsToAddToWorklist) {
182+
bool noErrors = true;
182183
for (BranchPropagatedUser user : consumingUses) {
183184
SILBasicBlock *userBlock = user.getParent();
184185

@@ -187,13 +188,13 @@ bool State::initializeAllConsumingUses(
187188
// if we successfully associated user with userBlock.
188189
if (!initializeConsumingUse(user, userBlock)) {
189190
// We already handled the error.
190-
return handleError([] {});
191+
noErrors &= handleError([] {});
191192
}
192193

193194
// Then check if the given block has a use after free.
194195
if (checkForSameBlockUseAfterFree(user, userBlock)) {
195196
// We already handled the error.
196-
return handleError([] {});
197+
noErrors &= handleError([] {});
197198
}
198199

199200
// If this user is in the same block as the value, do not visit
@@ -210,7 +211,7 @@ bool State::initializeAllConsumingUses(
210211
}
211212
}
212213

213-
return true;
214+
return noErrors;
214215
}
215216

216217
bool State::initializeConsumingUse(BranchPropagatedUser consumingUser,

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ static bool isOwnershipForwardingValueKind(SILNodeKind K) {
9898
case SILNodeKind::SelectEnumInst:
9999
case SILNodeKind::SwitchEnumInst:
100100
case SILNodeKind::CheckedCastBranchInst:
101+
case SILNodeKind::BranchInst:
102+
case SILNodeKind::CondBranchInst:
101103
case SILNodeKind::DestructureStructInst:
102104
case SILNodeKind::DestructureTupleInst:
103105
return true;
@@ -795,6 +797,16 @@ OwnershipCompatibilityUseChecker::visitReturnInst(ReturnInst *RI) {
795797

796798
OwnershipUseCheckerResult
797799
OwnershipCompatibilityUseChecker::visitEndBorrowInst(EndBorrowInst *I) {
800+
// If we are checking a subobject, make sure that we are from a guaranteed
801+
// basic block argument.
802+
if (isCheckingSubObject()) {
803+
auto *phiArg = cast<SILPHIArgument>(Op.get());
804+
(void)phiArg;
805+
assert(phiArg->getOwnershipKind() == ValueOwnershipKind::Guaranteed &&
806+
"Expected an end_borrow paired with an argument.");
807+
return {true, UseLifetimeConstraint::MustBeLive};
808+
}
809+
798810
/// An end_borrow is modeled as invalidating the guaranteed value preventing
799811
/// any further uses of the value.
800812
return {compatibleWithOwnership(ValueOwnershipKind::Guaranteed),
@@ -1438,6 +1450,7 @@ void SILValueOwnershipChecker::gatherUsers(
14381450
// users since we verify against our base.
14391451
auto OwnershipKind = Value.getOwnershipKind();
14401452
bool IsGuaranteed = OwnershipKind == ValueOwnershipKind::Guaranteed;
1453+
bool IsOwned = OwnershipKind == ValueOwnershipKind::Owned;
14411454

14421455
if (IsGuaranteed && isGuaranteedForwardingValue(Value))
14431456
return;
@@ -1485,27 +1498,37 @@ void SILValueOwnershipChecker::gatherUsers(
14851498
}
14861499
}
14871500

1488-
// If our base value is not guaranteed or our intermediate value is not an
1489-
// ownership forwarding inst, continue. We do not want to visit any
1490-
// subobjects recursively.
1491-
if (!IsGuaranteed || !isGuaranteedForwardingInst(User)) {
1492-
// Do a check if any of our users are begin_borrows. If we find such a
1493-
// use, then we want to include the end_borrow associated with the
1494-
// begin_borrow in our NonLifetimeEndingUser lists.
1495-
//
1496-
// For correctness reasons we use indices to make sure that we can append
1497-
// to NonLifetimeEndingUsers without needing to deal with iterator
1498-
// invalidation.
1499-
SmallVector<SILInstruction *, 4> endBorrowInsts;
1500-
for (unsigned i : indices(NonLifetimeEndingUsers)) {
1501-
if (auto *bbi = dyn_cast<BeginBorrowInst>(
1502-
NonLifetimeEndingUsers[i].getInst())) {
1503-
copy(bbi->getEndBorrows(), std::back_inserter(ImplicitRegularUsers));
1501+
// If our base value is not guaranteed, we do not to try to visit
1502+
// subobjects.
1503+
if (!IsGuaranteed) {
1504+
// But if we are owned, check if we have any end_borrows. We
1505+
// need to treat these as sub-scope users. We can rely on the
1506+
// end_borrow to prevent recursion.
1507+
if (IsOwned) {
1508+
// Do a check if any of our users are begin_borrows. If we find such a
1509+
// use, then we want to include the end_borrow associated with the
1510+
// begin_borrow in our NonLifetimeEndingUser lists.
1511+
//
1512+
// For correctness reasons we use indices to make sure that we can
1513+
// append to NonLifetimeEndingUsers without needing to deal with
1514+
// iterator invalidation.
1515+
SmallVector<SILInstruction *, 4> endBorrowInsts;
1516+
for (unsigned i : indices(NonLifetimeEndingUsers)) {
1517+
if (auto *bbi = dyn_cast<BeginBorrowInst>(
1518+
NonLifetimeEndingUsers[i].getInst())) {
1519+
copy(bbi->getEndBorrows(),
1520+
std::back_inserter(ImplicitRegularUsers));
1521+
}
15041522
}
15051523
}
15061524
continue;
15071525
}
15081526

1527+
// If we are guaranteed, but are not a guaranteed forwarding inst,
1528+
// just continue. This user is just treated as a normal use.
1529+
if (!isGuaranteedForwardingInst(User))
1530+
continue;
1531+
15091532
// At this point, we know that we must have a forwarded subobject. Since the
15101533
// base type is guaranteed, we know that the subobject is either guaranteed
15111534
// or trivial. We now split into two cases, if the user is a terminator or
@@ -1537,9 +1560,8 @@ void SILValueOwnershipChecker::gatherUsers(
15371560
}
15381561

15391562
// Otherwise if we have a terminator, add any as uses any end_borrow to
1540-
// ensure that the subscope is completely enclsed within the super
1541-
// scope. all of the arguments to the work list. We require all of our
1542-
// arguments to be either trivial or guaranteed.
1563+
// ensure that the subscope is completely enclsed within the super scope. We
1564+
// require all of our arguments to be either trivial or guaranteed.
15431565
for (auto &Succ : TI->getSuccessors()) {
15441566
auto *BB = Succ.getBB();
15451567

@@ -1552,7 +1574,7 @@ void SILValueOwnershipChecker::gatherUsers(
15521574
//
15531575
// TODO: We could ignore this error and emit a more specific error on the
15541576
// actual terminator.
1555-
for (auto *BBArg : BB->getArguments()) {
1577+
for (auto *BBArg : BB->getPHIArguments()) {
15561578
// *NOTE* We do not emit an error here since we want to allow for more
15571579
// specific errors to be found during use_verification.
15581580
//
@@ -1569,8 +1591,16 @@ void SILValueOwnershipChecker::gatherUsers(
15691591
if (BBArgOwnershipKind == ValueOwnershipKind::Trivial)
15701592
continue;
15711593

1572-
// Otherwise,
1573-
copy(BBArg->getUses(), std::back_inserter(Users));
1594+
// Otherwise add all end_borrow users for this BBArg to the
1595+
// implicit regular user list. We know that BBArg must be
1596+
// completely joint post-dominated by these users, so we use
1597+
// them to ensure that all of BBArg's uses are completely
1598+
// enclosed within the end_borrow of this argument.
1599+
for (auto *op : BBArg->getUses()) {
1600+
if (auto *ebi = dyn_cast<EndBorrowInst>(op->getUser())) {
1601+
ImplicitRegularUsers.push_back(ebi);
1602+
}
1603+
}
15741604
}
15751605
}
15761606
}

0 commit comments

Comments
 (0)