blob: 6024de614bb216c1af03031bd6d41ed0476fd9ed [file] [log] [blame]
//===--- 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);
});
}
}
}