Files
swift-mirror/lib/SILAnalysis/ValueTracking.cpp
Andrew Trick a174aa4dfe Add AST and SILGen support for Builtin.isUnique.
Preparation to fix <rdar://problem/18151694> Add Builtin.checkUnique
to avoid lost Array copies.

This adds the following new builtins:

    isUnique : <T> (inout T[?]) -> Int1
    isUniqueOrPinned : <T> (inout T[?]) -> Int1

These builtins take an inout object reference and return a
boolean. Passing the reference inout forces the optimizer to preserve
a retain distinct from what’s required to maintain lifetime for any of
the reference's source-level copies, because the called function is
allowed to replace the reference, thereby releasing the referent.

Before this change, the API entry points for uniqueness checking
already took an inout reference. However, after full inlining, it was
possible for two source-level variables that reference the same object
to appear to be the same variable from the optimizer's perspective
because an address to the variable was longer taken at the point of
checking uniqueness. Consequently the optimizer could remove
"redundant" copies which were actually needed to implement
copy-on-write semantics. With a builtin, the variable whose reference
is being checked for uniqueness appears mutable at the level of an
individual SIL instruction.

The kind of reference count checking that Builtin.isUnique performs
depends on the argument type:

    - Native object types are directly checked by reading the
      strong reference count:
      (Builtin.NativeObject, known native class reference)

    - Objective-C object types require an additional check that the
      dynamic object type uses native swift reference counting:
      (Builtin.UnknownObject, unknown class reference, class existential)

    - Bridged object types allow the dymanic object type check to be
      bypassed based on the pointer encoding:
      (Builtin.BridgeObject)

Any of the above types may also be wrapped in an optional.  If the
static argument type is optional, then a null check is also performed.

Thus, isUnique only returns true for non-null, native swift object
references with a strong reference count of one.

isUniqueOrPinned has the same semantics as isUnique except that it
also returns true if the object is marked pinned regardless of the
reference count. This allows for simultaneous non-structural
modification of multiple subobjects.

In some cases, the standard library can dynamically determine that it
has a native reference even though the static type is a bridge or
unknown object. Unsafe variants of the builtin are available to allow
the additional pointer bit mask and dynamic class lookup to be
bypassed in these cases:

    isUnique_native : <T> (inout T[?]) -> Int1
    isUniqueOrPinned_native : <T> (inout T[?]) -> Int1

These builtins perform an implicit cast to NativeObject before
checking uniqueness. There’s no way at SIL level to cast the address
of a reference, so we need to encapsulate this operation as part of
the builtin.

Swift SVN r27887
2015-04-28 22:54:24 +00:00

666 lines
22 KiB
C++

//===-- ValueTracking.h - SIL Value Tracking Analysis ----------*- C++ -*--===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-value-tracking"
#include "swift/SILAnalysis/ValueTracking.h"
#include "swift/SILAnalysis/SimplifyInstruction.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILValue.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SIL/PatternMatch.h"
#include "llvm/Support/Debug.h"
using namespace swift;
using namespace swift::PatternMatch;
/// Strip off casts/indexing insts/address projections from V until there is
/// nothing left to strip.
/// FIXME: Maybe put this on SILValue?
SILValue swift::getUnderlyingObject(SILValue V) {
while (true) {
SILValue V2 = V.stripCasts().stripAddressProjections().stripIndexingInsts();
if (V2 == V)
return V2;
V = V2;
}
}
/// Returns true if the ValueBase inside V is an apply whose callee is a no read
/// builtin.
static bool isNoReadBuiltinInst(SILValue V) {
auto *BI = dyn_cast<BuiltinInst>(V);
return BI && !BI->mayReadOrWriteMemory();
}
/// Is Inst an instruction which escapes if and only if one of its results
/// escape?
static bool isTransitiveEscapeInst(SILInstruction *Inst) {
switch (Inst->getKind()) {
case ValueKind::AllocBoxInst:
case ValueKind::AllocExistentialBoxInst:
case ValueKind::AllocRefInst:
case ValueKind::AllocRefDynamicInst:
case ValueKind::AllocStackInst:
case ValueKind::AllocValueBufferInst:
case ValueKind::BuiltinInst:
case ValueKind::ApplyInst:
case ValueKind::TryApplyInst:
case ValueKind::WitnessMethodInst:
case ValueKind::CopyAddrInst:
case ValueKind::RetainValueInst:
case ValueKind::DeallocBoxInst:
case ValueKind::DeallocExistentialBoxInst:
case ValueKind::DeallocRefInst:
case ValueKind::DeallocStackInst:
case ValueKind::DeallocValueBufferInst:
case ValueKind::DebugValueAddrInst:
case ValueKind::DebugValueInst:
case ValueKind::DestroyAddrInst:
case ValueKind::ProjectValueBufferInst:
case ValueKind::ReleaseValueInst:
case ValueKind::AutoreleaseValueInst:
case ValueKind::FloatLiteralInst:
case ValueKind::FunctionRefInst:
case ValueKind::IntegerLiteralInst:
case ValueKind::LoadInst:
case ValueKind::LoadWeakInst:
case ValueKind::MetatypeInst:
case ValueKind::ObjCProtocolInst:
case ValueKind::GlobalAddrInst:
case ValueKind::StoreInst:
case ValueKind::StoreWeakInst:
case ValueKind::StringLiteralInst:
case ValueKind::CopyBlockInst:
case ValueKind::StrongReleaseInst:
case ValueKind::StrongPinInst: // Pin handle is independently managed
case ValueKind::StrongRetainAutoreleasedInst:
case ValueKind::StrongRetainInst:
case ValueKind::StrongRetainUnownedInst:
case ValueKind::StrongUnpinInst:
case ValueKind::UnownedReleaseInst:
case ValueKind::UnownedRetainInst:
case ValueKind::IsUniqueInst:
case ValueKind::IsUniqueOrPinnedInst:
case ValueKind::InjectEnumAddrInst:
case ValueKind::DeinitExistentialAddrInst:
case ValueKind::UnreachableInst:
case ValueKind::IsNonnullInst:
case ValueKind::NullClassInst:
case ValueKind::CondFailInst:
case ValueKind::DynamicMethodBranchInst:
case ValueKind::ReturnInst:
case ValueKind::AutoreleaseReturnInst:
case ValueKind::ThrowInst:
case ValueKind::FixLifetimeInst:
return false;
case ValueKind::AddressToPointerInst:
case ValueKind::ValueMetatypeInst:
case ValueKind::BranchInst:
case ValueKind::CheckedCastBranchInst:
case ValueKind::CheckedCastAddrBranchInst:
case ValueKind::ClassMethodInst:
case ValueKind::CondBranchInst:
case ValueKind::ConvertFunctionInst:
case ValueKind::DynamicMethodInst:
case ValueKind::EnumInst:
case ValueKind::IndexAddrInst:
case ValueKind::IndexRawPointerInst:
case ValueKind::InitBlockStorageHeaderInst:
case ValueKind::InitEnumDataAddrInst:
case ValueKind::InitExistentialAddrInst:
case ValueKind::InitExistentialMetatypeInst:
case ValueKind::InitExistentialRefInst:
case ValueKind::ObjCExistentialMetatypeToObjectInst:
case ValueKind::ObjCMetatypeToObjectInst:
case ValueKind::ObjCToThickMetatypeInst:
case ValueKind::UncheckedRefCastInst:
case ValueKind::UncheckedAddrCastInst:
case ValueKind::UncheckedTrivialBitCastInst:
case ValueKind::UncheckedRefBitCastInst:
case ValueKind::MarkDependenceInst:
case ValueKind::OpenExistentialAddrInst:
case ValueKind::OpenExistentialMetatypeInst:
case ValueKind::OpenExistentialRefInst:
case ValueKind::OpenExistentialBoxInst:
case ValueKind::PartialApplyInst:
case ValueKind::PointerToAddressInst:
case ValueKind::PointerToThinFunctionInst:
case ValueKind::ProjectBlockStorageInst:
case ValueKind::ExistentialMetatypeInst:
case ValueKind::RawPointerToRefInst:
case ValueKind::RefElementAddrInst:
case ValueKind::RefToRawPointerInst:
case ValueKind::RefToUnmanagedInst:
case ValueKind::RefToUnownedInst:
case ValueKind::SelectEnumInst:
case ValueKind::SelectEnumAddrInst:
case ValueKind::SelectValueInst:
case ValueKind::StructElementAddrInst:
case ValueKind::StructExtractInst:
case ValueKind::StructInst:
case ValueKind::SuperMethodInst:
case ValueKind::SwitchEnumAddrInst:
case ValueKind::SwitchEnumInst:
case ValueKind::SwitchValueInst:
case ValueKind::UncheckedEnumDataInst:
case ValueKind::UncheckedTakeEnumDataAddrInst:
case ValueKind::ThickToObjCMetatypeInst:
case ValueKind::ThinFunctionToPointerInst:
case ValueKind::ThinToThickFunctionInst:
case ValueKind::TupleElementAddrInst:
case ValueKind::TupleExtractInst:
case ValueKind::TupleInst:
case ValueKind::UnconditionalCheckedCastInst:
case ValueKind::UnconditionalCheckedCastAddrInst:
case ValueKind::UnmanagedToRefInst:
case ValueKind::UnownedToRefInst:
case ValueKind::UpcastInst:
case ValueKind::RefToBridgeObjectInst:
case ValueKind::BridgeObjectToRefInst:
case ValueKind::BridgeObjectToWordInst:
return true;
case ValueKind::AssignInst:
case ValueKind::MarkFunctionEscapeInst:
case ValueKind::MarkUninitializedInst:
llvm_unreachable("Invalid in canonical SIL.");
case ValueKind::SILArgument:
case ValueKind::SILUndef:
llvm_unreachable("These do not use other values.");
}
}
/// Maximum amount of ValueCapture queries.
static unsigned const Threshold = 32;
namespace {
/// Are there any uses that should be ignored as capture uses.
///
/// TODO: Expand this if we ever do the store of pointer analysis mentioned in
/// Basic AA.
enum CaptureException : unsigned {
None=0,
ReturnsCannotCapture=1,
};
} // end anonymous namespace
/// Returns true if V is a value that is used in a manner such that we know its
/// captured or we don't understand whether or not it was captured. In such a
/// case to be conservative, we must assume it is captured.
/// FIXME: Maybe put this on SILValue?
static bool valueMayBeCaptured(SILValue V, CaptureException Exception) {
llvm::SmallVector<Operand *, Threshold> Worklist;
llvm::SmallPtrSet<Operand *, Threshold> Visited;
unsigned Count = 0;
DEBUG(llvm::dbgs() << " Checking for capture.\n");
// All all uses of V to the worklist.
for (auto *UI : V.getUses()) {
// If we have more uses than the threshold, be conservative and bail so we
// don't use too much compile time.
if (Count++ >= Threshold)
return true;
Visited.insert(UI);
Worklist.push_back(UI);
}
// Until the worklist is empty...
while (!Worklist.empty()) {
// Pop off an operand and grab the operand's user...
Operand *Op = Worklist.pop_back_val();
SILInstruction *Inst = Op->getUser();
DEBUG(llvm::dbgs() << " Visiting: " << *Inst);
// If Inst is an instruction with the transitive escape property, V escapes
// if and only if the results of Inst escape as well.
if (isTransitiveEscapeInst(Inst)) {
DEBUG(llvm::dbgs() << " Found transitive escape "
"instruction!\n");
for (auto *UI : Inst->getUses()) {
// If we have more uses than the threshold, be conservative and bail
// so we don't use too much compile time.
if (Count++ >= Threshold)
return true;
if (Visited.insert(UI).second) {
Worklist.push_back(UI);
}
}
continue;
}
// An apply of a builtin that does not read memory can not capture a value.
//
// TODO: Use analysis of the other function perhaps to see if it captures
// memory in some manner?
// TODO: Add in knowledge about how parameters work on swift to make this
// more aggressive.
if (isNoReadBuiltinInst(Inst))
continue;
// Loading from a pointer does not cause it to be captured.
if (isa<LoadInst>(Inst))
continue;
// If we have a store and are storing into the pointer, this is not a
// capture. Otherwise it is safe.
if (auto *SI = dyn_cast<StoreInst>(Inst)) {
if (SI->getDest() == Op->get()) {
continue;
} else {
return true;
}
}
// Deallocation instructions don't capture.
if (isa<DeallocationInst>(Inst))
continue;
// Debug instructions don't capture.
if (isa<DebugValueInst>(Inst) || isa<DebugValueAddrInst>(Inst))
continue;
// RefCountOperations don't capture.
//
// The release case is true since Swift does not allow destructors to
// resurrect objects. This is enforced via a runtime failure.
if (isa<RefCountingInst>(Inst))
continue;
// If we have a return instruction and we are assuming that returns don't
// capture, we are safe.
if (Exception == CaptureException::ReturnsCannotCapture &&
(isa<ReturnInst>(Inst) || isa<AutoreleaseReturnInst>(Inst)))
continue;
// We could not prove that Inst does not capture V. Be conservative and
// return true.
DEBUG(llvm::dbgs() << " Could not prove that inst does not capture "
"V!\n");
return true;
}
// We successfully proved that V is not captured. Return false.
DEBUG(llvm::dbgs() << " V was not captured!\n");
return false;
}
static bool isNoAliasArgument(SILValue V) {
auto *Arg = dyn_cast<SILArgument>(V);
if (!Arg)
return false;
return Arg->isFunctionArg() && V.getType().isAddress();
}
/// Return true if the pointer is to a function-local object that never escapes
/// from the function.
bool swift::isNonEscapingLocalObject(SILValue V) {
// If this is a local allocation, or the result of a no read apply inst (which
// can not affect memory in the caller), check to see if the allocation
// escapes.
if (isa<AllocationInst>(*V) || isNoReadBuiltinInst(V))
return !valueMayBeCaptured(V, CaptureException::ReturnsCannotCapture);
// If this is a no alias argument then it has not escaped before entering the
// function. Check if it escapes inside the function.
if (isNoAliasArgument(V))
return !valueMayBeCaptured(V, CaptureException::ReturnsCannotCapture);
// If this is an enum value. If it or its operand does not escape, it is
// local.
if (auto *EI = dyn_cast<EnumInst>(V))
return !EI->hasOperand() ||
!valueMayBeCaptured(EI->getOperand(),
CaptureException::ReturnsCannotCapture);
// Otherwise we could not prove that V is a non escaping local object. Be
// conservative and return false.
return false;
}
/// Check if the value \p Value is known to be zero, non-zero or unknown.
IsZeroKind swift::isZeroValue(SILValue Value) {
// Inspect integer literals.
if (auto *L = dyn_cast<IntegerLiteralInst>(Value.getDef())) {
if (L->getValue().getZExtValue() == 0)
return IsZeroKind::Zero;
return IsZeroKind::NotZero;
}
// Inspect Structs.
switch (Value.getDef()->getKind()) {
// Bitcast of zero is zero.
case ValueKind::UncheckedTrivialBitCastInst:
// Extracting from a zero class returns a zero.
case ValueKind::StructExtractInst:
return isZeroValue(cast<SILInstruction>(Value.getDef())->getOperand(0));
default:
break;
}
// Inspect casts.
if (auto *BI = dyn_cast<BuiltinInst>(Value.getDef())) {
switch (BI->getBuiltinInfo().ID) {
case BuiltinValueKind::IntToPtr:
case BuiltinValueKind::PtrToInt:
case BuiltinValueKind::ZExt:
return isZeroValue(BI->getArguments()[0]);
case BuiltinValueKind::UDiv:
case BuiltinValueKind::SDiv: {
if (IsZeroKind::Zero == isZeroValue(BI->getArguments()[0]))
return IsZeroKind::Zero;
return IsZeroKind::Unknown;
}
case BuiltinValueKind::Mul:
case BuiltinValueKind::SMulOver:
case BuiltinValueKind::UMulOver: {
IsZeroKind LHS = isZeroValue(BI->getArguments()[0]);
IsZeroKind RHS = isZeroValue(BI->getArguments()[1]);
if (LHS == IsZeroKind::Zero || RHS == IsZeroKind::Zero)
return IsZeroKind::Zero;
return IsZeroKind::Unknown;
}
default:
return IsZeroKind::Unknown;
}
}
// Handle results of XXX_with_overflow arithmetic.
if (auto *T = dyn_cast<TupleExtractInst>(Value.getDef())) {
// Make sure we are extracting the number value and not
// the overflow flag.
if (T->getFieldNo() != 0)
return IsZeroKind::Unknown;
BuiltinInst *BI = dyn_cast<BuiltinInst>(T->getOperand());
if (!BI)
return IsZeroKind::Unknown;
return isZeroValue(BI);
}
//Inspect allocations and pointer literals.
if (isa<StringLiteralInst>(Value.getDef()) ||
isa<AllocationInst>(Value.getDef()) ||
isa<GlobalAddrInst>(Value.getDef()))
return IsZeroKind::NotZero;
return IsZeroKind::Unknown;
}
/// Check if the sign bit of the value \p V is known to be:
/// set (true), not set (false) or unknown (None).
Optional<bool> swift::computeSignBit(SILValue V) {
SILValue Value = V;
while (true) {
auto *Def = Value.getDef();
// Inspect integer literals.
if (auto *L = dyn_cast<IntegerLiteralInst>(Def)) {
if (L->getValue().isNonNegative())
return false;
return true;
}
switch (Def->getKind()) {
// Bitcast of non-negative is non-negative
case ValueKind::UncheckedTrivialBitCastInst:
Value = cast<SILInstruction>(Def)->getOperand(0);
continue;
default:
break;
}
if (auto *BI = dyn_cast<BuiltinInst>(Def)) {
switch (BI->getBuiltinInfo().ID) {
// Sizeof always returns non-negative results.
case BuiltinValueKind::Sizeof:
return false;
// Strideof always returns non-negative results.
case BuiltinValueKind::Strideof:
return false;
// StrideofNonZero always returns positive results.
case BuiltinValueKind::StrideofNonZero:
return false;
// Alignof always returns non-negative results.
case BuiltinValueKind::Alignof:
return false;
// Both operands to AND must have the top bit set for V to.
case BuiltinValueKind::And: {
// Compute the sign bit of the LHS and RHS.
auto Left = computeSignBit(BI->getArguments()[0]);
auto Right = computeSignBit(BI->getArguments()[1]);
// We don't know either's sign bit so we can't
// say anything about the result.
if (!Left && !Right) {
return None;
}
// Now we know that we were able to determine the sign bit
// for at least one of Left/Right. Canonicalize the determined
// sign bit on the left.
if (Right) {
std::swap(Left, Right);
}
// We know we must have at least one result and it must be on
// the Left. If Right is still not None, then get both values
// and AND them together.
if (Right) {
return Left.getValue() && Right.getValue();
}
// Now we know that Right is None and Left has a value. If
// Left's value is true, then we return None as the final
// sign bit depends on the unknown Right value.
if (Left.getValue()) {
return None;
}
// Otherwise, Left must be false and false AND'd with anything
// else yields false.
return false;
}
// At least one operand to OR must have the top bit set.
case BuiltinValueKind::Or: {
// Compute the sign bit of the LHS and RHS.
auto Left = computeSignBit(BI->getArguments()[0]);
auto Right = computeSignBit(BI->getArguments()[1]);
// We don't know either's sign bit so we can't
// say anything about the result.
if (!Left && !Right) {
return None;
}
// Now we know that we were able to determine the sign bit
// for at least one of Left/Right. Canonicalize the determined
// sign bit on the left.
if (Right) {
std::swap(Left, Right);
}
// We know we must have at least one result and it must be on
// the Left. If Right is still not None, then get both values
// and OR them together.
if (Right) {
return Left.getValue() || Right.getValue();
}
// Now we know that Right is None and Left has a value. If
// Left's value is false, then we return None as the final
// sign bit depends on the unknown Right value.
if (!Left.getValue()) {
return None;
}
// Otherwise, Left must be true and true OR'd with anything
// else yields true.
return true;
}
// Only one of the operands to XOR must have the top bit set.
case BuiltinValueKind::Xor: {
// Compute the sign bit of the LHS and RHS.
auto Left = computeSignBit(BI->getArguments()[0]);
auto Right = computeSignBit(BI->getArguments()[1]);
// If either Left or Right is unknown then we can't say
// anything about the sign of the final result since
// XOR does not short-circuit.
if (!Left || !Right) {
return None;
}
// Now we know that both Left and Right must have a value.
// For the sign of the final result to be set, only one
// of Left or Right should be true.
return Left.getValue() != Right.getValue();
}
case BuiltinValueKind::LShr: {
// If count is provably >= 1, then top bit is not set.
auto *ILShiftCount = dyn_cast<IntegerLiteralInst>(BI->getArguments()[1]);
if (ILShiftCount) {
if (ILShiftCount->getValue().isStrictlyPositive()) {
return false;
}
}
// May be top bit is not set in the value being shifted.
Value = BI->getArguments()[0];
continue;
}
// Source and target type sizes are the same.
// S->U conversion can only succeed if
// the sign bit of its operand is 0, i.e. it is >= 0.
// The sign bit of a result is 0 only if the sign
// bit of a source operand is 0.
case BuiltinValueKind::SUCheckedConversion:
Value = BI->getArguments()[0];
continue;
// Source and target type sizes are the same.
// U->S conversion can only succeed if
// the top bit of its operand is 0, i.e.
// it is representable as a signed integer >=0.
// The sign bit of a result is 0 only if the sign
// bit of a source operand is 0.
case BuiltinValueKind::USCheckedConversion:
Value = BI->getArguments()[0];
continue;
// Sign bit of the operand is promoted.
case BuiltinValueKind::SExt:
Value = BI->getArguments()[0];
continue;
// Source type is always smaller than the target type.
// Therefore the sign bit of a result is always 0.
case BuiltinValueKind::ZExt:
return false;
// Sign bit of the operand is promoted.
case BuiltinValueKind::SExtOrBitCast:
Value = BI->getArguments()[0];
continue;
// TODO: If source type size is smaller than the target type
// the result will be always false.
case BuiltinValueKind::ZExtOrBitCast:
Value = BI->getArguments()[0];
continue;
// Inspect casts.
case BuiltinValueKind::IntToPtr:
case BuiltinValueKind::PtrToInt:
Value = BI->getArguments()[0];
continue;
default:
return None;
}
}
return None;
}
}
/// Check if a checked trunc instruction can overflow.
/// Returns false if it can be proven that no overflow can happen.
/// Otherwise returns true.
static bool checkTruncOverflow(BuiltinInst *BI) {
SILValue Left, Right;
if (match(BI, m_CheckedTrunc(m_And(m_SILValue(Left),
m_SILValue(Right))))) {
// [US]ToSCheckedTrunc(And(x, mask)) cannot overflow
// if mask has the following properties:
// Only the first (N-1) bits are allowed to be set, where N is the width
// of the trunc result type.
//
// [US]ToUCheckedTrunc(And(x, mask)) cannot overflow
// if mask has the following properties:
// Only the first N bits are allowed to be set, where N is the width
// of the trunc result type.
if (auto BITy = BI->getType().
getTupleElementType(0).
getAs<BuiltinIntegerType>()) {
unsigned Width = BITy->getFixedWidth();
switch (BI->getBuiltinInfo().ID) {
case BuiltinValueKind::SToSCheckedTrunc:
case BuiltinValueKind::UToSCheckedTrunc:
// If it is a trunc to a signed value
// then sign bit should not be set to avoid overflows.
--Width;
break;
default:
break;
}
if (auto *ILLeft = dyn_cast<IntegerLiteralInst>(Left)) {
APInt Value = ILLeft->getValue();
if (Value.isIntN(Width)) {
return false;
}
}
if (auto *ILRight = dyn_cast<IntegerLiteralInst>(Right)) {
APInt Value = ILRight->getValue();
if (Value.isIntN(Width)) {
return false;
}
}
}
}
return true;
}
/// Check if execution of a given Apply instruction can result in overflows.
/// Returns true if an overflow can happen. Otherwise returns false.
bool swift::canOverflow(BuiltinInst *BI) {
if (simplifyOverflowBuiltinInstruction(BI) != SILValue())
return false;
if (!checkTruncOverflow(BI))
return false;
// Conservatively assume that an overflow can happen
return true;
}