mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
AliasAnalysis: use escape analysis for some checks.
One important additional change here is that alias analsyis doesn't assume that inout is not-aliasing anymore
This commit is contained in:
@@ -56,6 +56,7 @@ class SILValue;
|
|||||||
class SILInstruction;
|
class SILInstruction;
|
||||||
class ValueBase;
|
class ValueBase;
|
||||||
class SideEffectAnalysis;
|
class SideEffectAnalysis;
|
||||||
|
class EscapeAnalysis;
|
||||||
|
|
||||||
/// This class is a simple wrapper around an alias analysis cache. This is
|
/// This class is a simple wrapper around an alias analysis cache. This is
|
||||||
/// needed since we do not have an "analysis" infrastructure.
|
/// needed since we do not have an "analysis" infrastructure.
|
||||||
@@ -91,6 +92,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
SILModule *Mod;
|
SILModule *Mod;
|
||||||
SideEffectAnalysis *SEA;
|
SideEffectAnalysis *SEA;
|
||||||
|
EscapeAnalysis *EA;
|
||||||
|
|
||||||
using TBAACacheKey = std::pair<SILType, SILType>;
|
using TBAACacheKey = std::pair<SILType, SILType>;
|
||||||
|
|
||||||
@@ -140,7 +142,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AliasAnalysis(SILModule *M) :
|
AliasAnalysis(SILModule *M) :
|
||||||
SILAnalysis(AnalysisKind::Alias), Mod(M), SEA(nullptr) {}
|
SILAnalysis(AnalysisKind::Alias), Mod(M), SEA(nullptr), EA(nullptr) {}
|
||||||
|
|
||||||
static bool classof(const SILAnalysis *S) {
|
static bool classof(const SILAnalysis *S) {
|
||||||
return S->getKind() == AnalysisKind::Alias;
|
return S->getKind() == AnalysisKind::Alias;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
|
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
|
||||||
#include "swift/SILOptimizer/Analysis/ValueTracking.h"
|
#include "swift/SILOptimizer/Analysis/ValueTracking.h"
|
||||||
#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h"
|
#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h"
|
||||||
|
#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h"
|
||||||
#include "swift/SILOptimizer/Utils/Local.h"
|
#include "swift/SILOptimizer/Utils/Local.h"
|
||||||
#include "swift/SILOptimizer/PassManager/PassManager.h"
|
#include "swift/SILOptimizer/PassManager/PassManager.h"
|
||||||
#include "swift/SIL/Projection.h"
|
#include "swift/SIL/Projection.h"
|
||||||
@@ -175,47 +176,6 @@ static bool isIdentifiedFunctionLocal(SILValue V) {
|
|||||||
return isa<AllocationInst>(*V) || isNoAliasArgument(V) || isLocalLiteral(V);
|
return isa<AllocationInst>(*V) || isNoAliasArgument(V) || isLocalLiteral(V);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if V is a function argument that is not an address implying
|
|
||||||
/// that we do not have the guarantee that it will not alias anything inside the
|
|
||||||
/// function.
|
|
||||||
static bool isAliasingFunctionArgument(SILValue V) {
|
|
||||||
return isFunctionArgument(V) && !V.getType().isAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if V is an apply inst that may read or write to memory.
|
|
||||||
static bool isReadWriteApplyInst(SILValue V) {
|
|
||||||
// See if this is a normal function application.
|
|
||||||
if (auto *AI = dyn_cast<ApplyInst>(V)) {
|
|
||||||
return AI->mayReadOrWriteMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, see if this is a builtin.
|
|
||||||
if (auto *BI = dyn_cast<BuiltinInst>(V)) {
|
|
||||||
return BI->mayReadOrWriteMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we fail, bail...
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if the pointer is one which would have been considered an escape
|
|
||||||
/// by isNonEscapingLocalObject.
|
|
||||||
static bool isEscapeSource(SILValue V) {
|
|
||||||
if (isReadWriteApplyInst(V))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (isAliasingFunctionArgument(V))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// The LoadInst case works since valueMayBeCaptured always assumes stores are
|
|
||||||
// escapes.
|
|
||||||
if (isa<LoadInst>(*V))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// We could not prove anything, be conservative and return false.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if we can prove that the two input SILValues which do not equal
|
/// Returns true if we can prove that the two input SILValues which do not equal
|
||||||
/// can not alias.
|
/// can not alias.
|
||||||
static bool aliasUnequalObjects(SILValue O1, SILValue O2) {
|
static bool aliasUnequalObjects(SILValue O1, SILValue O2) {
|
||||||
@@ -243,16 +203,6 @@ static bool aliasUnequalObjects(SILValue O1, SILValue O2) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If one pointer is the result of an apply or load and the other is a
|
|
||||||
// non-escaping local object within the same function, then we know the object
|
|
||||||
// couldn't escape to a point where the call could return it.
|
|
||||||
if ((isEscapeSource(O1) && isNonEscapingLocalObject(O2)) ||
|
|
||||||
(isEscapeSource(O2) && isNonEscapingLocalObject(O1))) {
|
|
||||||
DEBUG(llvm::dbgs() << " Found unequal escape source and non "
|
|
||||||
"escaping local object!\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We failed to prove that the two objects are different.
|
// We failed to prove that the two objects are different.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -644,6 +594,14 @@ AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
|
|||||||
if (O1 != O2 && aliasUnequalObjects(O1, O2))
|
if (O1 != O2 && aliasUnequalObjects(O1, O2))
|
||||||
return AliasResult::NoAlias;
|
return AliasResult::NoAlias;
|
||||||
|
|
||||||
|
// Ask escape analysis. This catches cases where we compare e.g. a
|
||||||
|
// non-escaping pointer with another pointer.
|
||||||
|
if (!EA->canPointToSameMemory(V1, V2)) {
|
||||||
|
DEBUG(llvm::dbgs() << " Found not-aliased objects based on"
|
||||||
|
"escape analysis\n");
|
||||||
|
return AliasResult::NoAlias;
|
||||||
|
}
|
||||||
|
|
||||||
// Ok, either O1, O2 are the same or we could not prove anything based off of
|
// Ok, either O1, O2 are the same or we could not prove anything based off of
|
||||||
// their inequality. Now we climb up use-def chains and attempt to do tricks
|
// their inequality. Now we climb up use-def chains and attempt to do tricks
|
||||||
// based off of GEPs.
|
// based off of GEPs.
|
||||||
@@ -698,6 +656,7 @@ bool swift::isLetPointer(SILValue V) {
|
|||||||
|
|
||||||
void AliasAnalysis::initialize(SILPassManager *PM) {
|
void AliasAnalysis::initialize(SILPassManager *PM) {
|
||||||
SEA = PM->getAnalysis<SideEffectAnalysis>();
|
SEA = PM->getAnalysis<SideEffectAnalysis>();
|
||||||
|
EA = PM->getAnalysis<EscapeAnalysis>();
|
||||||
}
|
}
|
||||||
|
|
||||||
SILAnalysis *swift::createAliasAnalysis(SILModule *M) {
|
SILAnalysis *swift::createAliasAnalysis(SILModule *M) {
|
||||||
|
|||||||
@@ -238,10 +238,6 @@ sil @use_native_object : $@convention(thin) (Builtin.NativeObject) -> ()
|
|||||||
// CHECK: (0): %0 = argument of bb0 : $*Builtin.NativeObject
|
// CHECK: (0): %0 = argument of bb0 : $*Builtin.NativeObject
|
||||||
// CHECK: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
// CHECK: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
||||||
// CHECK: NoAlias
|
// CHECK: NoAlias
|
||||||
// CHECK: PAIR #11.
|
|
||||||
// CHECK: (0): %0 = argument of bb0 : $*Builtin.NativeObject
|
|
||||||
// CHECK: (0): %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
||||||
// CHECK: NoAlias
|
|
||||||
|
|
||||||
// Test %1 (the aliasing argument)
|
// Test %1 (the aliasing argument)
|
||||||
|
|
||||||
@@ -318,10 +314,6 @@ sil @use_native_object : $@convention(thin) (Builtin.NativeObject) -> ()
|
|||||||
// CHECK-NEXT: (0): %3 = alloc_stack $Builtin.NativeObject
|
// CHECK-NEXT: (0): %3 = alloc_stack $Builtin.NativeObject
|
||||||
// CHECK-NEXT: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
// CHECK-NEXT: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
||||||
// CHECK-NEXT: NoAlias
|
// CHECK-NEXT: NoAlias
|
||||||
// CHECK: PAIR #53.
|
|
||||||
// CHECK-NEXT: (0): %3 = alloc_stack $Builtin.NativeObject
|
|
||||||
// CHECK-NEXT: (0): %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
||||||
// CHECK-NEXT: NoAlias
|
|
||||||
// CHECK: PAIR #57.
|
// CHECK: PAIR #57.
|
||||||
// CHECK-NEXT: (1): %3 = alloc_stack $Builtin.NativeObject
|
// CHECK-NEXT: (1): %3 = alloc_stack $Builtin.NativeObject
|
||||||
// CHECK-NEXT: (0): %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
|
// CHECK-NEXT: (0): %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
|
||||||
@@ -334,10 +326,6 @@ sil @use_native_object : $@convention(thin) (Builtin.NativeObject) -> ()
|
|||||||
// CHECK-NEXT: (1): %3 = alloc_stack $Builtin.NativeObject
|
// CHECK-NEXT: (1): %3 = alloc_stack $Builtin.NativeObject
|
||||||
// CHECK-NEXT: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
// CHECK-NEXT: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
||||||
// CHECK-NEXT: NoAlias
|
// CHECK-NEXT: NoAlias
|
||||||
// CHECK: PAIR #61.
|
|
||||||
// CHECK-NEXT: (1): %3 = alloc_stack $Builtin.NativeObject
|
|
||||||
// CHECK-NEXT: (0): %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
||||||
// CHECK-NEXT: NoAlias
|
|
||||||
|
|
||||||
// Test %5 (the read write apply inst).
|
// Test %5 (the read write apply inst).
|
||||||
|
|
||||||
@@ -373,7 +361,7 @@ sil @use_native_object : $@convention(thin) (Builtin.NativeObject) -> ()
|
|||||||
// CHECK-NEXT: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
// CHECK-NEXT: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
||||||
// CHECK-NEXT: (0): %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
|
// CHECK-NEXT: (0): %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
|
||||||
// CHECK-NEXT: MayAlias
|
// CHECK-NEXT: MayAlias
|
||||||
sil @escapesource_functionlocal_test_escapesource_nonescapinglocal : $@convention(thin) (@inout Builtin.NativeObject, Builtin.NativeObject) -> () {
|
sil @escapesource_functionlocal_test_escapesource_nonescapinglocal : $@convention(thin) (@in Builtin.NativeObject, Builtin.NativeObject) -> () {
|
||||||
bb0(%0 : $*Builtin.NativeObject, %1 : $Builtin.NativeObject):
|
bb0(%0 : $*Builtin.NativeObject, %1 : $Builtin.NativeObject):
|
||||||
%2 = alloc_stack $Builtin.NativeObject
|
%2 = alloc_stack $Builtin.NativeObject
|
||||||
%3 = alloc_stack $Builtin.NativeObject
|
%3 = alloc_stack $Builtin.NativeObject
|
||||||
@@ -515,3 +503,25 @@ bb0(%0 : $C, %1 : $C, %2 : $Int):
|
|||||||
return %2 : $Int
|
return %2 : $Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @non_escaping_local_object_does_not_alias_with_unknown
|
||||||
|
// CHECK: PAIR #7.
|
||||||
|
// CHECK-NEXT: (0): %1 = alloc_ref $X // user: %3
|
||||||
|
// CHECK-NEXT: (0): %3 = apply %2(%1) : $@convention(thin) (X) -> X
|
||||||
|
// CHECK-NEXT: NoAlias
|
||||||
|
sil @non_escaping_local_object_does_not_alias_with_unknown : $@convention(thin) (X) -> () {
|
||||||
|
bb0(%0 : $X):
|
||||||
|
%1 = alloc_ref $X
|
||||||
|
|
||||||
|
%f = function_ref @not_escaping : $@convention(thin) (X) -> X
|
||||||
|
%2 = apply %f(%1) : $@convention(thin) (X) -> X
|
||||||
|
|
||||||
|
%12 = tuple()
|
||||||
|
return %12 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
sil @not_escaping: $@convention(thin) (X) -> X {
|
||||||
|
bb0(%0 : $X):
|
||||||
|
%1 = alloc_ref $X
|
||||||
|
return %1 : $X
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user