mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[ownership] Add a new class BorrowScopeIntroducingValue that enables code to work abstractly with values that introduce a new borrow scope.
The idea is that this can be used to work with things like load_borrow, begin_borrow, SILFunctionArgument, results of begin_apply(in the future) and the like in a generic way using exhaustive switches to make sure this code stays up to date. I refactored code in SemanticARCOpts and some utilities in OwnershipUtils.cpp to use these new APIs. The code looks a lot nicer and should be quite easy to expand to handle new borrow introducers (e.x.: end_apply).
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#define SWIFT_SIL_OWNERSHIPUTILS_H
|
||||
|
||||
#include "swift/Basic/LLVM.h"
|
||||
#include "swift/SIL/BranchPropagatedUser.h"
|
||||
#include "swift/SIL/SILArgument.h"
|
||||
#include "swift/SIL/SILInstruction.h"
|
||||
#include "swift/SIL/SILValue.h"
|
||||
@@ -164,10 +165,152 @@ bool isOwnershipForwardingInst(SILInstruction *i);
|
||||
|
||||
bool isGuaranteedForwardingInst(SILInstruction *i);
|
||||
|
||||
struct BorrowScopeIntroducerKind {
|
||||
using UnderlyingKindTy = std::underlying_type<ValueKind>::type;
|
||||
|
||||
/// Enum we use for exhaustive pattern matching over borrow scope introducers.
|
||||
enum Kind : UnderlyingKindTy {
|
||||
LoadBorrow = UnderlyingKindTy(ValueKind::LoadBorrowInst),
|
||||
BeginBorrow = UnderlyingKindTy(ValueKind::BeginBorrowInst),
|
||||
SILFunctionArgument = UnderlyingKindTy(ValueKind::SILFunctionArgument),
|
||||
};
|
||||
|
||||
static Optional<BorrowScopeIntroducerKind> get(ValueKind kind) {
|
||||
switch (kind) {
|
||||
default:
|
||||
return None;
|
||||
case ValueKind::LoadBorrowInst:
|
||||
return BorrowScopeIntroducerKind(LoadBorrow);
|
||||
case ValueKind::BeginBorrowInst:
|
||||
return BorrowScopeIntroducerKind(BeginBorrow);
|
||||
case ValueKind::SILFunctionArgument:
|
||||
return BorrowScopeIntroducerKind(SILFunctionArgument);
|
||||
}
|
||||
}
|
||||
|
||||
Kind value;
|
||||
|
||||
BorrowScopeIntroducerKind(Kind newValue) : value(newValue) {}
|
||||
BorrowScopeIntroducerKind(const BorrowScopeIntroducerKind &other)
|
||||
: value(other.value) {}
|
||||
operator Kind() const { return value; }
|
||||
|
||||
/// Is this a borrow scope that begins and ends within the same function and
|
||||
/// thus is guaranteed to have an "end_scope" instruction.
|
||||
///
|
||||
/// In contrast, borrow scopes that are non-local (e.x. from
|
||||
/// SILFunctionArguments) rely a construct like a SILFunction as the begin/end
|
||||
/// of the scope.
|
||||
bool isLocalScope() const {
|
||||
switch (value) {
|
||||
case BorrowScopeIntroducerKind::BeginBorrow:
|
||||
case BorrowScopeIntroducerKind::LoadBorrow:
|
||||
return true;
|
||||
case BorrowScopeIntroducerKind::SILFunctionArgument:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("Covered switch isnt covered?!");
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream &os) const;
|
||||
LLVM_ATTRIBUTE_DEPRECATED(void dump() const, "only for use in the debugger");
|
||||
};
|
||||
|
||||
llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
|
||||
BorrowScopeIntroducerKind kind);
|
||||
|
||||
/// A higher level construct for working with values that represent the
|
||||
/// introduction of a new borrow scope.
|
||||
///
|
||||
/// DISCUSSION: A "borrow introducer" is a SILValue that represents the
|
||||
/// beginning of a borrow scope that the ownership verifier validates. The idea
|
||||
/// is this API allows one to work in a generic way with all of the various
|
||||
/// introducers.
|
||||
///
|
||||
/// Some examples of borrow introducers: guaranteed SILFunctionArgument,
|
||||
/// LoadBorrow, BeginBorrow, guaranteed BeginApply results.
|
||||
///
|
||||
/// NOTE: It is assumed that if a borrow introducer is a value of a
|
||||
/// SILInstruction with multiple results, that the all of the SILInstruction's
|
||||
/// guaranteed results are borrow introducers. In practice this means that
|
||||
/// borrow introducers can not have guaranteed results that are not creating a
|
||||
/// new borrow scope. No such instructions exist today.
|
||||
struct BorrowScopeIntroducingValue {
|
||||
BorrowScopeIntroducerKind kind;
|
||||
SILValue value;
|
||||
|
||||
BorrowScopeIntroducingValue(LoadBorrowInst *lbi)
|
||||
: kind(BorrowScopeIntroducerKind::LoadBorrow), value(lbi) {}
|
||||
BorrowScopeIntroducingValue(BeginBorrowInst *bbi)
|
||||
: kind(BorrowScopeIntroducerKind::BeginBorrow), value(bbi) {}
|
||||
BorrowScopeIntroducingValue(SILFunctionArgument *arg)
|
||||
: kind(BorrowScopeIntroducerKind::SILFunctionArgument), value(arg) {
|
||||
assert(arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed);
|
||||
}
|
||||
|
||||
BorrowScopeIntroducingValue(SILValue v)
|
||||
: kind(*BorrowScopeIntroducerKind::get(v->getKind())), value(v) {
|
||||
assert(v.getOwnershipKind() == ValueOwnershipKind::Guaranteed);
|
||||
}
|
||||
|
||||
/// If value is a borrow introducer return it after doing some checks.
|
||||
static Optional<BorrowScopeIntroducingValue> get(SILValue value) {
|
||||
auto kind = BorrowScopeIntroducerKind::get(value->getKind());
|
||||
if (!kind || value.getOwnershipKind() != ValueOwnershipKind::Guaranteed)
|
||||
return None;
|
||||
return BorrowScopeIntroducingValue(*kind, value);
|
||||
}
|
||||
|
||||
/// If this value is introducing a local scope, gather all local end scope
|
||||
/// instructions and append them to \p scopeEndingInsts. Asserts if this is
|
||||
/// called with a scope that is not local.
|
||||
///
|
||||
/// NOTE: To determine if a scope is a local scope, call
|
||||
/// BorrowScopeIntoducingValue::isLocalScope().
|
||||
void getLocalScopeEndingInstructions(
|
||||
SmallVectorImpl<SILInstruction *> &scopeEndingInsts) const;
|
||||
|
||||
/// If this value is introducing a local scope, gather all local end scope
|
||||
/// instructions and pass them individually to visitor. Asserts if this is
|
||||
/// called with a scope that is not local.
|
||||
///
|
||||
/// The intention is that this method can be used instead of
|
||||
/// BorrowScopeIntroducingValue::getLocalScopeEndingInstructions() to avoid
|
||||
/// introducing an intermediate array when one needs to transform the
|
||||
/// instructions before storing them.
|
||||
///
|
||||
/// NOTE: To determine if a scope is a local scope, call
|
||||
/// BorrowScopeIntoducingValue::isLocalScope().
|
||||
void visitLocalScopeEndingInstructions(
|
||||
function_ref<void(SILInstruction *)> visitor) const;
|
||||
|
||||
bool isLocalScope() const { return kind.isLocalScope(); }
|
||||
|
||||
/// Returns true if the passed in set of instructions is completely within the
|
||||
/// lifetime of this borrow introducer.
|
||||
///
|
||||
/// NOTE: Scratch space is used internally to this method to store the end
|
||||
/// borrow scopes if needed.
|
||||
bool areInstructionsWithinScope(
|
||||
ArrayRef<BranchPropagatedUser> instructions,
|
||||
SmallVectorImpl<BranchPropagatedUser> &scratchSpace,
|
||||
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
|
||||
DeadEndBlocks &deadEndBlocks) const;
|
||||
|
||||
private:
|
||||
/// Internal constructor for failable static constructor. Please do not expand
|
||||
/// its usage since it assumes the code passed in is well formed.
|
||||
BorrowScopeIntroducingValue(BorrowScopeIntroducerKind kind, SILValue value)
|
||||
: kind(kind), value(value) {}
|
||||
};
|
||||
|
||||
/// Look up through the def-use chain of \p inputValue, recording any "borrow"
|
||||
/// introducers that we find into \p out.
|
||||
bool getUnderlyingBorrowIntroducers(SILValue inputValue,
|
||||
SmallVectorImpl<SILValue> &out);
|
||||
/// introducing values that we find into \p out. If at any point, we find a
|
||||
/// point in the chain we do not understand, we bail and return false. If we are
|
||||
/// able to understand all of the def-use graph, we know that we have found all
|
||||
/// of the borrow introducing values, we return true.
|
||||
bool getUnderlyingBorrowIntroducingValues(
|
||||
SILValue inputValue, SmallVectorImpl<BorrowScopeIntroducingValue> &out);
|
||||
|
||||
} // namespace swift
|
||||
|
||||
|
||||
Reference in New Issue
Block a user