blob: 6e47743ba33101517e1cbe5a53c5632bb221f5ed [file] [log] [blame]
//===--- AliasAnalysis.cpp - SIL Alias Analysis ---------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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-aa"
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/Projection.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILValue.h"
#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h"
#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h"
#include "swift/SILOptimizer/Analysis/ValueTracking.h"
#include "swift/SILOptimizer/PassManager/PassManager.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;
// The AliasAnalysis Cache must not grow beyond this size.
// We limit the size of the AA cache to 2**14 because we want to limit the
// memory usage of this cache.
static const int AliasAnalysisMaxCacheSize = 16384;
//===----------------------------------------------------------------------===//
// AA Debugging
//===----------------------------------------------------------------------===//
#ifndef NDEBUG
namespace {
enum class AAKind : unsigned {
None=0,
BasicAA=1,
TypedAccessTBAA=2,
All=3,
};
} // end anonymous namespace
static llvm::cl::opt<AAKind>
DebugAAKinds("aa-kind", llvm::cl::desc("Alias Analysis Kinds:"),
llvm::cl::init(AAKind::All),
llvm::cl::values(clEnumValN(AAKind::None,
"none",
"Do not perform any AA"),
clEnumValN(AAKind::BasicAA,
"basic-aa",
"basic-aa"),
clEnumValN(AAKind::TypedAccessTBAA,
"typed-access-tb-aa",
"typed-access-tb-aa"),
clEnumValN(AAKind::All,
"all",
"all")));
static inline bool shouldRunAA() {
return unsigned(AAKind(DebugAAKinds));
}
static inline bool shouldRunTypedAccessTBAA() {
return unsigned(AAKind(DebugAAKinds)) & unsigned(AAKind::TypedAccessTBAA);
}
static inline bool shouldRunBasicAA() {
return unsigned(AAKind(DebugAAKinds)) & unsigned(AAKind::BasicAA);
}
#endif
//===----------------------------------------------------------------------===//
// Utilities
//===----------------------------------------------------------------------===//
using AliasResult = AliasAnalysis::AliasResult;
llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, AliasResult R) {
switch (R) {
case AliasResult::NoAlias: return OS << "NoAlias";
case AliasResult::MayAlias: return OS << "MayAlias";
case AliasResult::PartialAlias: return OS << "PartialAlias";
case AliasResult::MustAlias: return OS << "MustAlias";
}
llvm_unreachable("Unhandled AliasResult in switch.");
}
// Return the address of the directly accessed memory. If either the address is
// unknown, or any other memory is accessed via indirection, return an invalid
// SILValue.
SILValue getDirectlyAccessedMemory(SILInstruction *User) {
if (auto *LI = dyn_cast<LoadInst>(User)) {
return LI->getOperand();
}
if (auto *SI = dyn_cast<StoreInst>(User)) {
return SI->getDest();
}
return SILValue();
}
//===----------------------------------------------------------------------===//
// Unequal Base Object AA
//===----------------------------------------------------------------------===//
/// Return true if the given SILArgument is an argument to the first BB of a
/// function.
static bool isFunctionArgument(SILValue V) {
return isa<SILFunctionArgument>(V);
}
/// Return true if V is an object that at compile time can be uniquely
/// identified.
static bool isIdentifiableObject(SILValue V) {
if (isa<AllocationInst>(V) || isa<LiteralInst>(V))
return true;
if (isExclusiveArgument(V))
return true;
return false;
}
/// Return true if V1 and V2 are distinct objects that can be uniquely
/// identified at compile time.
static bool areDistinctIdentifiableObjects(SILValue V1, SILValue V2) {
// Do both values refer to the same global variable?
if (auto *GA1 = dyn_cast<GlobalAddrInst>(V1)) {
if (auto *GA2 = dyn_cast<GlobalAddrInst>(V2)) {
return GA1->getReferencedGlobal() != GA2->getReferencedGlobal();
}
}
if (isIdentifiableObject(V1) && isIdentifiableObject(V2))
return V1 != V2;
return false;
}
/// Returns true if both values are equal or yield the address of the same
/// global variable.
static bool isSameValueOrGlobal(SILValue V1, SILValue V2) {
if (V1 == V2)
return true;
// Do both values refer to the same global variable?
if (auto *GA1 = dyn_cast<GlobalAddrInst>(V1)) {
if (auto *GA2 = dyn_cast<GlobalAddrInst>(V2)) {
return GA1->getReferencedGlobal() == GA2->getReferencedGlobal();
}
}
return false;
}
/// Is this a literal which we know cannot refer to a global object?
///
/// FIXME: function_ref?
static bool isLocalLiteral(SILValue V) {
switch (V->getKind()) {
case ValueKind::IntegerLiteralInst:
case ValueKind::FloatLiteralInst:
case ValueKind::StringLiteralInst:
return true;
default:
return false;
}
}
/// Is this a value that can be unambiguously identified as being defined at the
/// function level.
static bool isIdentifiedFunctionLocal(SILValue V) {
return isa<AllocationInst>(*V) || isExclusiveArgument(V) || isLocalLiteral(V);
}
/// Returns true if we can prove that the two input SILValues which do not equal
/// cannot alias.
static bool aliasUnequalObjects(SILValue O1, SILValue O2) {
assert(O1 != O2 && "This function should only be called on unequal values.");
// If O1 and O2 do not equal and they are both values that can be statically
// and uniquely identified, they cannot alias.
if (areDistinctIdentifiableObjects(O1, O2)) {
LLVM_DEBUG(llvm::dbgs() << " Found two unequal identified "
"objects.\n");
return true;
}
// Function arguments can't alias with things that are known to be
// unambiguously identified at the function level.
//
// Note that both function arguments must be identified. For example, an @in
// argument may be an interior pointer into a box that is passed separately as
// @owned. We must consider uses on the @in argument as potential uses of the
// @owned object.
if ((isFunctionArgument(O1) && isIdentifiedFunctionLocal(O2)) ||
(isFunctionArgument(O2) && isIdentifiedFunctionLocal(O1))) {
LLVM_DEBUG(llvm::dbgs() << " Found unequal function arg and "
"identified function local!\n");
return true;
}
// We failed to prove that the two objects are different.
return false;
}
//===----------------------------------------------------------------------===//
// Projection Address AA
//===----------------------------------------------------------------------===//
/// Uses a bunch of ad-hoc rules to disambiguate a GEP instruction against
/// another pointer. We know that V1 is a GEP, but we don't know anything about
/// V2. O1, O2 are getUnderlyingObject of V1, V2 respectively.
AliasResult AliasAnalysis::aliasAddressProjection(SILValue V1, SILValue V2,
SILValue O1, SILValue O2) {
// If V2 is also a gep instruction with a must-alias or not-aliasing base
// pointer, figure out if the indices of the GEPs tell us anything about the
// derived pointers.
if (!Projection::isAddressProjection(V2)) {
// Ok, V2 is not an address projection. See if V2 after stripping casts
// aliases O1. If so, then we know that V2 must partially alias V1 via a
// must alias relation on O1. This ensures that given an alloc_stack and a
// gep from that alloc_stack, we say that they partially alias.
if (isSameValueOrGlobal(O1, stripCasts(V2)))
return AliasResult::PartialAlias;
return AliasResult::MayAlias;
}
assert(!Projection::isAddressProjection(O1) &&
"underlying object may not be a projection");
assert(!Projection::isAddressProjection(O2) &&
"underlying object may not be a projection");
// Do the base pointers alias?
AliasResult BaseAlias = aliasInner(O1, O2);
// If the underlying objects are not aliased, the projected values are also
// not aliased.
if (BaseAlias == AliasResult::NoAlias)
return AliasResult::NoAlias;
// Let's do alias checking based on projections.
auto V1Path = ProjectionPath::getProjectionPath(O1, V1);
auto V2Path = ProjectionPath::getProjectionPath(O2, V2);
// getUnderlyingPath and findAddressProjectionPathBetweenValues disagree on
// what the base pointer of the two values are. Be conservative and return
// MayAlias.
//
// FIXME: The only way this should happen realistically is if there are
// casts in between two projection instructions. getUnderlyingObject will
// ignore that, while findAddressProjectionPathBetweenValues wont. The two
// solutions are to make address projections variadic (something on the wee
// horizon) or enable Projection to represent a cast as a special sort of
// projection.
if (!V1Path || !V2Path)
return AliasResult::MayAlias;
auto R = V1Path->computeSubSeqRelation(*V2Path);
// If all of the projections are equal (and they have the same base pointer),
// the two GEPs must be the same.
if (BaseAlias == AliasResult::MustAlias &&
R == SubSeqRelation_t::Equal)
return AliasResult::MustAlias;
// The two GEPs do not alias if they are accessing different fields, even if
// we don't know the base pointers. Different fields should not overlap.
//
// TODO: Replace this with a check on the computed subseq relation. See the
// TODO in computeSubSeqRelation.
if (V1Path->hasNonEmptySymmetricDifference(V2Path.getValue()))
return AliasResult::NoAlias;
// If one of the GEPs is a super path of the other then they partially
// alias.
if (BaseAlias == AliasResult::MustAlias &&
isStrictSubSeqRelation(R))
return AliasResult::PartialAlias;
// We failed to prove anything. Be conservative and return MayAlias.
return AliasResult::MayAlias;
}
//===----------------------------------------------------------------------===//
// TBAA
//===----------------------------------------------------------------------===//
/// Is this an instruction that can act as a type "oracle" allowing typed access
/// TBAA to know what the real types associated with the SILInstruction are.
static bool isTypedAccessOracle(SILInstruction *I) {
switch (I->getKind()) {
case SILInstructionKind::RefElementAddrInst:
case SILInstructionKind::RefTailAddrInst:
case SILInstructionKind::StructElementAddrInst:
case SILInstructionKind::TupleElementAddrInst:
case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
case SILInstructionKind::LoadInst:
case SILInstructionKind::StoreInst:
case SILInstructionKind::AllocStackInst:
case SILInstructionKind::AllocBoxInst:
case SILInstructionKind::ProjectBoxInst:
case SILInstructionKind::DeallocStackInst:
case SILInstructionKind::DeallocBoxInst:
return true;
default:
return false;
}
}
/// Return true if the given value is an instruction or block argument that is
/// known to produce a nonaliasing address with respect to TBAA rules (i.e. the
/// pointer is not type punned). The only way to produce an aliasing typed
/// address is with pointer_to_address (via UnsafePointer) or
/// unchecked_addr_cast (via Builtin.reinterpretCast). Consequently, if the
/// given value is directly derived from a memory location, it cannot
/// alias. Call arguments also cannot alias because they must follow \@in, @out,
/// @inout, or \@in_guaranteed conventions.
static bool isAccessedAddressTBAASafe(SILValue V) {
if (!V->getType().isAddress())
return false;
SILValue accessedAddress = getTypedAccessAddress(V);
if (isa<SILFunctionArgument>(accessedAddress))
return true;
if (auto *PtrToAddr = dyn_cast<PointerToAddressInst>(accessedAddress))
return PtrToAddr->isStrict();
switch (accessedAddress->getKind()) {
default:
return false;
case ValueKind::AllocStackInst:
case ValueKind::ProjectBoxInst:
case ValueKind::RefElementAddrInst:
case ValueKind::RefTailAddrInst:
return true;
}
}
/// Look at the origin/user ValueBase of V to see if any of them are
/// TypedAccessOracle which enable one to ascertain via undefined behavior the
/// "true" type of the instruction.
static SILType findTypedAccessType(SILValue V) {
assert(V->getType().isAddress());
// First look at the origin of V and see if we have any instruction that is a
// typed oracle.
// TODO: MultiValueInstruction
if (auto *I = dyn_cast<SingleValueInstruction>(V))
if (isTypedAccessOracle(I))
return V->getType();
// Then look at any uses of V that potentially could act as a typed access
// oracle.
for (auto Use : V->getUses())
if (isTypedAccessOracle(Use->getUser()))
return V->getType();
// Otherwise return an empty SILType
return SILType();
}
SILType swift::computeTBAAType(SILValue V) {
if (isAccessedAddressTBAASafe(V))
return findTypedAccessType(V);
// FIXME: add ref_element_addr check here. TBAA says that objects cannot be
// type punned.
return SILType();
}
static bool typedAccessTBAABuiltinTypesMayAlias(SILType LTy, SILType RTy) {
assert(LTy != RTy && "LTy should have already been shown to not equal RTy to "
"call this function.");
// If either of our types are raw pointers, they may alias any builtin.
if (LTy.is<BuiltinRawPointerType>() || RTy.is<BuiltinRawPointerType>())
return true;
// At this point, we have 3 possibilities:
//
// 1. (Pointer, Scalar): A pointer to a pointer can never alias a scalar.
//
// 2. (Pointer, Pointer): If we have two pointers to pointers, since we know
// that the two values do not equal due to previous AA calculations, one must
// be a native object and the other is an unknown object type (i.e. an objc
// object) which cannot alias.
//
// 3. (Scalar, Scalar): If we have two scalar pointers, since we know that the
// types are already not equal, we know that they cannot alias. For those
// unfamiliar even though BuiltinIntegerType/BuiltinFloatType are single
// classes, the AST represents each integer/float of different bit widths as
// different types, so equality of SILTypes allows us to know that they have
// different bit widths.
//
// Thus we can just return false since in none of the aforementioned cases we
// cannot alias, so return false.
return false;
}
/// return True if the types \p LTy and \p RTy may alias.
///
/// Currently this only implements typed access based TBAA. See the TBAA section
/// in the SIL reference manual.
static bool typedAccessTBAAMayAlias(SILType LTy, SILType RTy,
const SILFunction &F) {
#ifndef NDEBUG
if (!shouldRunTypedAccessTBAA())
return true;
#endif
// If the two types are the same they may alias.
if (LTy == RTy)
return true;
// Typed access based TBAA only occurs on pointers. If we reach this point and
// do not have a pointer, be conservative and return that the two types may
// alias.
if (!LTy.isAddress() || !RTy.isAddress())
return true;
// If the types have unbound generic arguments then we don't know
// the possible range of the type. A type such as $Array<Int> may
// alias $Array<T>. Right now we are conservative and we assume
// that $UnsafeMutablePointer<T> and $Int may alias.
if (LTy.hasArchetype() || RTy.hasArchetype())
return true;
// If either type is a protocol type, we don't know the underlying type so
// return may alias.
//
// FIXME: We could be significantly smarter here by using the protocol
// hierarchy.
if (LTy.isAnyExistentialType() || RTy.isAnyExistentialType())
return true;
// If either type is an address only type, bail so we are conservative.
if (LTy.isAddressOnly(F) || RTy.isAddressOnly(F))
return true;
// If both types are builtin types, handle them separately.
if (LTy.is<BuiltinType>() && RTy.is<BuiltinType>())
return typedAccessTBAABuiltinTypesMayAlias(LTy, RTy);
// Otherwise, we know that at least one of our types is not a builtin
// type. If we have a builtin type, canonicalize it on the right.
if (LTy.is<BuiltinType>())
std::swap(LTy, RTy);
// If RTy is a builtin raw pointer type, it can alias anything.
if (RTy.is<BuiltinRawPointerType>())
return true;
ClassDecl *LTyClass = LTy.getClassOrBoundGenericClass();
// The Builtin reference types can alias any class instance.
if (LTyClass) {
if (RTy.is<BuiltinNativeObjectType>() ||
RTy.is<BuiltinBridgeObjectType>()) {
return true;
}
}
auto &Mod = F.getModule();
// If one type is an aggregate and it contains the other type then the record
// reference may alias the aggregate reference.
if (LTy.aggregateContainsRecord(RTy, Mod, F.getTypeExpansionContext()) ||
RTy.aggregateContainsRecord(LTy, Mod, F.getTypeExpansionContext()))
return true;
// FIXME: All the code following could be made significantly more aggressive
// by saying that aggregates of the same type that do not contain each other
// cannot alias.
// Tuples do not alias non-tuples.
bool LTyTT = LTy.is<TupleType>();
bool RTyTT = RTy.is<TupleType>();
if ((LTyTT && !RTyTT) || (!LTyTT && RTyTT))
return false;
// Structs do not alias non-structs.
StructDecl *LTyStruct = LTy.getStructOrBoundGenericStruct();
StructDecl *RTyStruct = RTy.getStructOrBoundGenericStruct();
if ((LTyStruct && !RTyStruct) || (!LTyStruct && RTyStruct))
return false;
// Enums do not alias non-enums.
EnumDecl *LTyEnum = LTy.getEnumOrBoundGenericEnum();
EnumDecl *RTyEnum = RTy.getEnumOrBoundGenericEnum();
if ((LTyEnum && !RTyEnum) || (!LTyEnum && RTyEnum))
return false;
// Classes do not alias non-classes.
ClassDecl *RTyClass = RTy.getClassOrBoundGenericClass();
if ((LTyClass && !RTyClass) || (!LTyClass && RTyClass))
return false;
// Classes with separate class hierarchies do not alias.
if (!LTy.isBindableToSuperclassOf(RTy) && !RTy.isBindableToSuperclassOf(LTy))
return false;
// Otherwise be conservative and return that the two types may alias.
return true;
}
bool AliasAnalysis::typesMayAlias(SILType T1, SILType T2,
const SILFunction &F) {
// Both types need to be valid.
if (!T2 || !T1)
return true;
// Check if we've already computed the TBAA relation.
auto Key = std::make_pair(T1, T2);
auto Res = TypesMayAliasCache.find(Key);
if (Res != TypesMayAliasCache.end()) {
return Res->second;
}
bool MA = typedAccessTBAAMayAlias(T1, T2, F);
TypesMayAliasCache[Key] = MA;
return MA;
}
//===----------------------------------------------------------------------===//
// Entry Points
//===----------------------------------------------------------------------===//
/// The main AA entry point. Performs various analyses on V1, V2 in an attempt
/// to disambiguate the two values.
AliasResult AliasAnalysis::alias(SILValue V1, SILValue V2,
SILType TBAAType1, SILType TBAAType2) {
AliasKeyTy Key = toAliasKey(V1, V2, TBAAType1, TBAAType2);
// Check if we've already computed this result.
auto It = AliasCache.find(Key);
if (It != AliasCache.end()) {
return It->second;
}
// Flush the cache if the size of the cache is too large.
if (AliasCache.size() > AliasAnalysisMaxCacheSize) {
AliasCache.clear();
AliasValueBaseToIndex.clear();
// Key is no longer valid as we cleared the AliasValueBaseToIndex.
Key = toAliasKey(V1, V2, TBAAType1, TBAAType2);
}
// Calculate the aliasing result and store it in the cache.
auto Result = aliasInner(V1, V2, TBAAType1, TBAAType2);
AliasCache[Key] = Result;
return Result;
}
/// Get the underlying object, looking through init_enum_data_addr and
/// init_existential_addr.
static SILValue stripInitEnumAndExistentialAddr(SILValue v) {
while (isa<InitEnumDataAddrInst>(v) || isa<InitExistentialAddrInst>(v)) {
v = getUnderlyingObject(cast<SingleValueInstruction>(v)->getOperand(0));
}
return v;
}
/// The main AA entry point. Performs various analyses on V1, V2 in an attempt
/// to disambiguate the two values.
AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
SILType TBAAType1,
SILType TBAAType2) {
#ifndef NDEBUG
// If alias analysis is disabled, always return may alias.
if (!shouldRunAA())
return AliasResult::MayAlias;
#endif
// If the two values equal, quickly return must alias.
if (isSameValueOrGlobal(V1, V2))
return AliasResult::MustAlias;
LLVM_DEBUG(llvm::dbgs() << "ALIAS ANALYSIS:\n V1: " << *V1
<< " V2: " << *V2);
// If this is SILUndef, return may alias.
if (!V1->getFunction())
return AliasResult::MayAlias;
// Pass in both the TBAA types so we can perform typed access TBAA and the
// actual types of V1, V2 so we can perform class based TBAA.
if (!typesMayAlias(TBAAType1, TBAAType2, *V1->getFunction()))
return AliasResult::NoAlias;
#ifndef NDEBUG
if (!shouldRunBasicAA())
return AliasResult::MayAlias;
#endif
// Strip off any casts on V1, V2.
V1 = stripCasts(V1);
V2 = stripCasts(V2);
LLVM_DEBUG(llvm::dbgs() << " After Cast Stripping V1:" << *V1);
LLVM_DEBUG(llvm::dbgs() << " After Cast Stripping V2:" << *V2);
// Ok, we need to actually compute an Alias Analysis result for V1, V2. Begin
// by finding the "base" of V1, V2 by stripping off all casts and GEPs.
SILValue O1 = getUnderlyingObject(V1);
SILValue O2 = getUnderlyingObject(V2);
LLVM_DEBUG(llvm::dbgs() << " Underlying V1:" << *O1);
LLVM_DEBUG(llvm::dbgs() << " Underlying V2:" << *O2);
// If the underlying objects are not equal, see if we can prove that they
// cannot be the same object. If we can, return No Alias.
// For this we even look through init_enum_data_addr and init_existential_addr.
SILValue StrippedO1 = stripInitEnumAndExistentialAddr(O1);
SILValue StrippedO2 = stripInitEnumAndExistentialAddr(O2);
if (StrippedO1 != StrippedO2 && aliasUnequalObjects(StrippedO1, StrippedO2))
return AliasResult::NoAlias;
// Ok, either O1, O2 are the same or we could not prove anything based off of
// their inequality.
// Next: ask escape analysis. This catches cases where we compare e.g. a
// non-escaping pointer with another (maybe escaping) pointer. Escape analysis
// uses the connection graph to check if the pointers may point to the same
// content.
//
// canPointToSameMemory must take the original pointers used for memory
// access, not the underlying object, because objects projections can be
// modeled by escape analysis as different content, and canPointToSameMemory
// assumes that only the pointer itself may be accessed here, not any other
// address that can be derived from this pointer.
if (!EA->canPointToSameMemory(V1, V2)) {
LLVM_DEBUG(llvm::dbgs() << " Found not-aliased objects based on "
"escape analysis\n");
return AliasResult::NoAlias;
}
// Now we climb up use-def chains and attempt to do tricks based off of GEPs.
// First if one instruction is a gep and the other is not, canonicalize our
// inputs so that V1 always is the instruction containing the GEP.
if (!Projection::isAddressProjection(V1) &&
Projection::isAddressProjection(V2)) {
std::swap(V1, V2);
std::swap(O1, O2);
}
// If V1 is an address projection, attempt to use information from the
// aggregate type tree to disambiguate it from V2.
if (Projection::isAddressProjection(V1)) {
AliasResult Result = aliasAddressProjection(V1, V2, O1, O2);
if (Result != AliasResult::MayAlias)
return Result;
}
// We could not prove anything. Be conservative and return that V1, V2 may
// alias.
return AliasResult::MayAlias;
}
bool AliasAnalysis::canApplyDecrementRefCount(FullApplySite FAS, SILValue Ptr) {
// If the connection graph is invalid due to a very large function, we also
// skip all other tests, which might take significant time for a very large
// function.
// This is a workaround for some quadratic complexity in ARCSequenceOpt.
// TODO: remove this check once ARCSequenceOpt is retired or the quadratic
// behavior is fixed.
auto *conGraph = EA->getConnectionGraph(FAS.getFunction());
if (!conGraph->isValid())
return true;
// Treat applications of no-return functions as decrementing ref counts. This
// causes the apply to become a sink barrier for ref count increments.
if (FAS.isCalleeNoReturn())
return true;
/// If the pointer cannot escape to the function we are done.
if (!EA->canEscapeTo(Ptr, FAS))
return false;
FunctionSideEffects ApplyEffects;
SEA->getCalleeEffects(ApplyEffects, FAS);
auto &GlobalEffects = ApplyEffects.getGlobalEffects();
if (ApplyEffects.mayReadRC() || GlobalEffects.mayRelease())
return true;
/// The function has no unidentified releases, so let's look at the arguments
// in detail.
for (unsigned Idx = 0, End = FAS.getNumArguments(); Idx < End; ++Idx) {
auto &ArgEffect = ApplyEffects.getParameterEffects()[Idx];
if (ArgEffect.mayRelease()) {
// The function may release this argument, so check if the pointer can
// escape to it.
if (EA->mayReleaseContent(FAS.getArgument(Idx), Ptr))
return true;
}
}
return false;
}
bool AliasAnalysis::canBuiltinDecrementRefCount(BuiltinInst *BI, SILValue Ptr) {
for (SILValue Arg : BI->getArguments()) {
// Exclude some types of arguments where Ptr can never escape to.
if (isa<MetatypeInst>(Arg))
continue;
if (Arg->getType().is<BuiltinIntegerType>())
continue;
// A builtin can only release an object if it can escape to one of the
// builtin's arguments. 'EscapeAnalysis::mayReleaseContent()' expects 'Arg'
// to be an owned reference and disallows addresses. Conservatively handle
// address type arguments as and conservatively treat all other values
// potential owned references.
if (Arg->getType().isAddress() || EA->mayReleaseContent(Arg, Ptr))
return true;
}
return false;
}
// If the deinit for releasedReference can release any values used by User, then
// this is an interference. (The retains that originally forced liveness of
// those values may have already been eliminated). Note that we only care about
// avoiding a dangling pointer. The memory side affects of Release are
// unordered.
//
// \p releasedReference must be a value that directly contains the references
// being released. It cannot be an address or other kind of pointer that
// indirectly releases a reference. Otherwise, the escape analysis query is
// invalid.
bool AliasAnalysis::mayValueReleaseInterfereWithInstruction(
SILInstruction *User, SILValue releasedReference) {
assert(!releasedReference->getType().isAddress()
&& "an address is never a reference");
// If this instruction can not read or write any memory. Its OK.
if (!User->mayReadOrWriteMemory())
return false;
// Get a pointer to the memory directly accessed by 'Users' (either via an
// address or heap reference operand). If additional memory may be indirectly
// accessed by 'User', such as via an inout argument, then stop here because
// mayReleaseContent can only reason about one level of memory access.
//
// TODO: Handle @inout arguments by iterating over the apply arguments. For
// each argument find out if any reachable content can be released. This is
// slightly more involved than mayReleaseContent because it needs to check all
// connection graph nodes reachable from accessedPointer that don't pass
// through another stored reference.
SILValue accessedPointer = getDirectlyAccessedMemory(User);
if (!accessedPointer)
return true;
// If releasedReference can reach the first refcounted object reachable from
// accessedPointer, then releasing it early may destroy the object accessed by
// accessedPointer. Access to any objects beyond the first released refcounted
// object are irrelevant--they must already have sufficient refcount that they
// won't be released when releasing Ptr.
return EA->mayReleaseContent(releasedReference, accessedPointer);
}
void AliasAnalysis::initialize(SILPassManager *PM) {
SEA = PM->getAnalysis<SideEffectAnalysis>();
EA = PM->getAnalysis<EscapeAnalysis>();
}
SILAnalysis *swift::createAliasAnalysis(SILModule *M) {
return new AliasAnalysis(M);
}
AliasKeyTy AliasAnalysis::toAliasKey(SILValue V1, SILValue V2,
SILType Type1, SILType Type2) {
size_t idx1 = AliasValueBaseToIndex.getIndex(V1);
assert(idx1 != std::numeric_limits<size_t>::max() &&
"~0 index reserved for empty/tombstone keys");
size_t idx2 = AliasValueBaseToIndex.getIndex(V2);
assert(idx2 != std::numeric_limits<size_t>::max() &&
"~0 index reserved for empty/tombstone keys");
void *t1 = Type1.getOpaqueValue();
void *t2 = Type2.getOpaqueValue();
return {idx1, idx2, t1, t2};
}