Files
swift-mirror/lib/SIL/Verifier/ReborrowVerifier.cpp
Michael Gottesman 63e43b6b2f [ownership] Rename BorrowingOperand::visitLocalEndScope{Instruction,Use}s(Operand *)
This originally trafficked in Instructions and for some reason the name was
never changed.

I also changed the result type to be a bool and added the ability for the passed
in closure to signal failure (and iteration stop) by returning false. This also
makes it possible to use visitLocalEndScopeUses in if statements which can be
useful.
2020-11-25 21:54:47 -08:00

96 lines
3.6 KiB
C++

//===--- ReborrowVerifier.cpp ---------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-reborrow-checker"
#include "ReborrowVerifierPrivate.h"
using namespace swift;
bool ReborrowVerifier::verifyReborrowLifetime(SILPhiArgument *phiArg,
SILValue baseVal) {
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
bool result = false;
SmallVector<Operand *, 4> phiArgUses(phiArg->getUses());
// Verify whether the guaranteed phi arg lies within the lifetime of the base
// value.
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
// newErrorBuilder is consumed at the end of the checkValue function.
// Copy initial state from errorBuilder everytime
LinearLifetimeChecker::ErrorBuilder newErrorBuilder = errorBuilder;
SmallVector<Operand *, 4> baseValConsumingUses(baseVal->getConsumingUses());
// If the baseValue has no consuming uses, there is nothing more to verify
if (baseValConsumingUses.empty())
return false;
auto linearLifetimeResult = checker.checkValue(baseVal, baseValConsumingUses,
phiArgUses, newErrorBuilder);
result |= linearLifetimeResult.getFoundError();
return result;
}
void ReborrowVerifier::verifyReborrows(BorrowingOperand initialScopedOperand,
SILValue value) {
SmallVector<std::tuple<Operand *, SILValue>, 4> worklist;
// Initialize the worklist with borrow lifetime ending uses
initialScopedOperand.visitLocalEndScopeUses([&](Operand *op) {
worklist.emplace_back(op, value);
return true;
});
while (!worklist.empty()) {
Operand *borrowLifetimeEndOp;
SILValue baseVal;
std::tie(borrowLifetimeEndOp, baseVal) = worklist.pop_back_val();
auto *borrowLifetimeEndUser = borrowLifetimeEndOp->getUser();
auto borrowingOperand = BorrowingOperand::get(borrowLifetimeEndOp);
if (!borrowingOperand || !borrowingOperand->isReborrow())
continue;
if (isVisitedOp(borrowLifetimeEndOp, baseVal))
continue;
// Process reborrow
auto *branchInst = cast<BranchInst>(borrowLifetimeEndUser);
for (auto *succBlock : branchInst->getSuccessorBlocks()) {
auto *phiArg = cast<SILPhiArgument>(
succBlock->getArgument(borrowLifetimeEndOp->getOperandNumber()));
assert(phiArg->getOwnershipKind() == OwnershipKind::Guaranteed);
SILValue newBaseVal = baseVal;
// If the previous base value was also passed as a phi arg, that will be
// the new base value.
for (auto *arg : succBlock->getArguments()) {
if (arg->getIncomingPhiValue(branchInst->getParent()) == baseVal) {
newBaseVal = arg;
break;
}
}
if (isVisitedPhiArg(phiArg, newBaseVal))
continue;
addVisitedPhiArg(phiArg, newBaseVal);
verifyReborrowLifetime(phiArg, newBaseVal);
// Find the scope ending uses of the guaranteed phi arg and add it to the
// worklist.
auto scopedValue = BorrowedValue::get(phiArg);
assert(scopedValue.hasValue());
scopedValue->visitLocalScopeEndingUses([&](Operand *op) {
addVisitedOp(op, newBaseVal);
worklist.emplace_back(op, newBaseVal);
});
}
}
}