Skip to content

Fix EscapeAnalysis::mayReleaseContent #36046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 47 additions & 2 deletions include/swift/SILOptimizer/Analysis/EscapeAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -989,8 +989,13 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
/// The allocator for the connection graphs in Function2ConGraph.
llvm::SpecificBumpPtrAllocator<FunctionInfo> Allocator;

// TODO: Use per-function caches, at least for Resilient types, to use Maximal
// expansion.

/// Cache for isPointer().
PointerKindCache pointerKindCache;
/// Cache for checking the aggregate pointerness of class properties.
PointerKindCache classPropertiesKindCache;

SILModule *M;

Expand All @@ -1014,6 +1019,12 @@ class EscapeAnalysis : public BottomUpIPAnalysis {

PointerKind findCachedPointerKind(SILType Ty, const SILFunction &F) const;

PointerKind findClassPropertiesPointerKind(SILType Ty,
const SILFunction &F) const;

PointerKind findCachedClassPropertiesKind(SILType Ty,
const SILFunction &F) const;

// Returns true if the type \p Ty must be a reference or must transitively
// contain a reference and no other pointer or address type.
bool hasReferenceOnly(SILType Ty, const SILFunction &F) const {
Expand Down Expand Up @@ -1114,6 +1125,10 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
bool canEscapeToUsePoint(SILValue value, SILInstruction *usePoint,
ConnectionGraph *conGraph);

/// Common implementation for mayReleaseReferenceContent and
/// mayReleaseAddressContent.
bool mayReleaseContent(SILValue releasedPtr, SILValue liveAddress);

friend struct ::CGForDotView;

public:
Expand Down Expand Up @@ -1163,8 +1178,38 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
bool canEscapeTo(SILValue V, DestroyValueInst *DVI);

/// Return true if \p releasedReference deinitialization may release memory
/// pointed to by \p accessedAddress.
bool mayReleaseContent(SILValue releasedReference, SILValue accessedAddress);
/// pointed to by \p liveAddress.
///
/// This determines whether a direct release of \p releasedReference, such as
/// destroy_value or strong_release may release memory pointed to by \p
/// liveAddress. It can also be used to determine whether passing a
/// reference-type call argument may release \p liveAddress.
///
/// This does not distinguish between a call that releases \p
/// releasedReference directly, vs. a call that releases one of indirect
/// references.The side effects of releasing any object reachable from \p
/// releasedReference are a strict subset of the side effects of directly
/// releasing the parent reference.
bool mayReleaseReferenceContent(SILValue releasedReference,
SILValue liveAddress) {
assert(!releasedReference->getType().isAddress() &&
"expected a potentially nontrivial value, not an address");
return mayReleaseContent(releasedReference, liveAddress);
}

/// Return true if accessing memory at \p accessedAddress may release memory
/// pointed to by \p liveAddress.
///
/// This makes sense for determining whether accessing indirect call argument
/// \p accessedAddress may release memory pointed to by \p liveAddress.
///
/// "Access" to the memory can be any release of a reference pointed to by \p
/// accessedAddress, so '@in' and '@inout' are handled the same.
bool mayReleaseAddressContent(SILValue accessedAddress,
SILValue liveAddress) {
assert(accessedAddress->getType().isAddress() && "expected an address");
return mayReleaseContent(accessedAddress, liveAddress);
}

/// Returns true if the pointers \p V1 and \p V2 can possibly point to the
/// same memory.
Expand Down
34 changes: 25 additions & 9 deletions lib/SILOptimizer/Analysis/AliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,8 +723,18 @@ bool AliasAnalysis::canApplyDecrementRefCount(FullApplySite FAS, SILValue Ptr) {
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;
auto arg = FAS.getArgument(Idx);
if (arg->getType().isAddress()) {
// Handle indirect argument as if they are a release to any references
// pointed to by the argument's address.
if (EA->mayReleaseAddressContent(arg, Ptr))
return true;
} else {
// Handle direct arguments as if they are a direct release of the
// reference (just like a destroy_value).
if (EA->mayReleaseReferenceContent(arg, Ptr))
return true;
}
}
}
return false;
Expand All @@ -740,12 +750,18 @@ bool AliasAnalysis::canBuiltinDecrementRefCount(BuiltinInst *BI, SILValue Ptr) {
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;
// builtin's arguments.
if (Arg->getType().isAddress()) {
// Handle indirect argument as if they are a release to any references
// pointed to by the argument's address.
if (EA->mayReleaseAddressContent(Arg, Ptr))
return true;
} else {
// Handle direct arguments as if they are a direct release of the
// reference (just like a destroy_value).
if (EA->mayReleaseReferenceContent(Arg, Ptr))
return true;
}
}
return false;
}
Expand Down Expand Up @@ -788,7 +804,7 @@ bool AliasAnalysis::mayValueReleaseInterfereWithInstruction(
// 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);
return EA->mayReleaseReferenceContent(releasedReference, accessedPointer);
}

void AliasAnalysis::initialize(SILPassManager *PM) {
Expand Down
Loading