Skip to content

Commit 573df89

Browse files
committed
Fix BorrowingOperand more.
Don't allow an owned call argument to be considered a valid BorrowingOperand. More generally, make sure there is a perfect equivalence between valid BorrowingOperand and the corresponding OperandOwnership kind.
1 parent faedffa commit 573df89

File tree

6 files changed

+26
-34
lines changed

6 files changed

+26
-34
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ struct BorrowedValue;
255255
/// borrowed and thus the incoming value must implicitly be borrowed until the
256256
/// user's corresponding end scope instruction.
257257
///
258+
/// Invariant: For a given operand, BorrowingOperand is valid iff
259+
/// it has OperandOwnership::Borrow or OperandOwnership::Reborrow.
260+
///
258261
/// NOTE: We do not require that the guaranteed scope be represented by a
259262
/// guaranteed value in the same function: see begin_apply. In such cases, we
260263
/// require instead an end_* instruction to mark the end of the scope's region.
@@ -264,10 +267,14 @@ struct BorrowingOperand {
264267

265268
BorrowingOperand(Operand *op)
266269
: op(op), kind(BorrowingOperandKind::get(op->getUser()->getKind())) {
267-
if (kind == BorrowingOperandKind::Branch
268-
&& op->get().getOwnershipKind() != OwnershipKind::Guaranteed) {
270+
auto ownership = op->getOperandOwnership();
271+
if (ownership != OperandOwnership::Borrow
272+
&& ownership != OperandOwnership::Reborrow) {
273+
// consuming applies and branch arguments are not borrowing operands.
269274
kind = BorrowingOperandKind::Invalid;
275+
return;
270276
}
277+
assert(kind != BorrowingOperandKind::Invalid && "missing case");
271278
}
272279
BorrowingOperand(const BorrowingOperand &other)
273280
: op(other.op), kind(other.kind) {}
@@ -284,28 +291,7 @@ struct BorrowingOperand {
284291
const Operand *operator->() const { return op; }
285292
Operand *operator->() { return op; }
286293

287-
operator bool() const { return kind != BorrowingOperandKind::Invalid && op; }
288-
289-
/// If \p op is a borrow introducing operand return it after doing some
290-
/// checks.
291-
static BorrowingOperand get(Operand *op) {
292-
auto *user = op->getUser();
293-
auto kind = BorrowingOperandKind::get(user->getKind());
294-
if (!kind)
295-
return {nullptr, kind};
296-
297-
if (kind == BorrowingOperandKind::Branch
298-
&& op->get().getOwnershipKind() != OwnershipKind::Guaranteed) {
299-
return {nullptr, BorrowingOperandKind::Invalid};
300-
}
301-
return {op, kind};
302-
}
303-
304-
/// If \p op is a borrow introducing operand return it after doing some
305-
/// checks.
306-
static BorrowingOperand get(const Operand *op) {
307-
return get(const_cast<Operand *>(op));
308-
}
294+
operator bool() const { return kind != BorrowingOperandKind::Invalid; }
309295

310296
/// If this borrowing operand results in the underlying value being borrowed
311297
/// over a region of code instead of just for a single instruction, visit
@@ -347,8 +333,14 @@ struct BorrowingOperand {
347333
llvm_unreachable("Covered switch isn't covered?!");
348334
}
349335

350-
/// Return true if the user instruction introduces a borrow scope? This is
351-
/// true for both reborrows and nested borrows.
336+
/// Return true if the user instruction defines a borrowed value that
337+
/// introduces a borrow scope and therefore may be reborrowed. This is true
338+
/// for both reborrows and nested borrows.
339+
///
340+
/// Note that begin_apply does create a borrow scope, and may define
341+
/// guaranteed value within that scope. The difference is that those yielded
342+
/// values do not themselves introduce a borrow scope. In other words, they
343+
/// cannot be reborrowed.
352344
///
353345
/// If true, the visitBorrowIntroducingUserResults() can be called to acquire
354346
/// each BorrowedValue that introduces a new borrow scopes.
@@ -599,7 +591,7 @@ struct BorrowedValue {
599591
&foundReborrows) const {
600592
bool foundAnyReborrows = false;
601593
for (auto *op : value->getUses()) {
602-
if (auto borrowingOperand = BorrowingOperand::get(op)) {
594+
if (auto borrowingOperand = BorrowingOperand(op)) {
603595
if (borrowingOperand.isReborrow()) {
604596
foundReborrows.push_back(
605597
{value->getParentBlock(), op->getOperandNumber()});

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ bool swift::checkOperandOwnershipInvariants(const Operand *operand) {
2424
OperandOwnership opOwnership = operand->getOperandOwnership();
2525
if (opOwnership == OperandOwnership::Borrow) {
2626
// Must be a valid BorrowingOperand.
27-
return bool(BorrowingOperand::get(operand));
27+
return bool(BorrowingOperand(const_cast<Operand *>(operand)));
2828
}
2929
return true;
3030
}

lib/SIL/Verifier/LinearLifetimeChecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ void State::checkForSameBlockUseAfterFree(Operand *consumingUse,
314314
}) == userBlock->end()) {
315315
continue;
316316
}
317-
} else if (auto borrowingOperand = BorrowingOperand::get(nonConsumingUse)) {
317+
} else if (auto borrowingOperand = BorrowingOperand(nonConsumingUse)) {
318318
assert(borrowingOperand.isReborrow());
319319
// a reborrow is expected to be consumed by the same phi.
320320
continue;

lib/SIL/Verifier/SILOwnershipVerifier.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers(
244244
// regular users so we can ensure that the borrow scope operand's scope is
245245
// completely within the owned value's scope. If we do not have a borrow
246246
// scope operand, just continue, we are done.
247-
auto initialScopedOperand = BorrowingOperand::get(op);
247+
auto initialScopedOperand = BorrowingOperand(op);
248248
if (!initialScopedOperand) {
249249
continue;
250250
}
@@ -348,7 +348,7 @@ bool SILValueOwnershipChecker::gatherUsers(
348348
// Ok, our operand does not consume guaranteed values. Check if it is a
349349
// BorrowScopeOperand and if so, add its end scope instructions as
350350
// implicit regular users of our value.
351-
if (auto scopedOperand = BorrowingOperand::get(op)) {
351+
if (auto scopedOperand = BorrowingOperand(op)) {
352352
assert(!scopedOperand.isReborrow());
353353

354354
std::function<void(Operand *)> onError = [&](Operand *op) {

lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ static bool tryJoinIfDestroyConsumingUseInSameBlock(
473473
// we need to only find scopes that end within the region in between the
474474
// singleConsumingUse (the original forwarded use) and the destroy_value. In
475475
// such a case, we must bail!
476-
if (auto operand = BorrowingOperand::get(use))
476+
if (auto operand = BorrowingOperand(use))
477477
if (!operand.visitScopeEndingUses([&](Operand *endScopeUse) {
478478
// Return false if we did see the relevant end scope instruction
479479
// in the block. That means that we are going to exit early and

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ static void eliminateReborrowsOfRecursiveBorrows(
508508
// Otherwise, we have a reborrow. For now our reborrows must be
509509
// phis. Add our owned value as a new argument of that phi along our
510510
// edge and undef along all other edges.
511-
auto borrowingOp = BorrowingOperand::get(use);
511+
auto borrowingOp = BorrowingOperand(use);
512512
auto *brInst = cast<BranchInst>(borrowingOp.op->getUser());
513513
auto *newBorrowedPhi = brInst->getArgForOperand(*borrowingOp);
514514
auto *newBasePhi =
@@ -572,7 +572,7 @@ rewriteReborrows(SILValue newBorrowedValue,
572572
// Otherwise, we have a reborrow. For now our reborrows must be
573573
// phis. Add our owned value as a new argument of that phi along our
574574
// edge and undef along all other edges.
575-
auto borrowingOp = BorrowingOperand::get(use);
575+
auto borrowingOp = BorrowingOperand(use);
576576
auto *brInst = cast<BranchInst>(borrowingOp.op->getUser());
577577
auto *newBorrowedPhi = brInst->getArgForOperand(*borrowingOp);
578578
auto *newBasePhi =

0 commit comments

Comments
 (0)