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 ValueBase;
|
||||
class SideEffectAnalysis;
|
||||
class EscapeAnalysis;
|
||||
|
||||
/// This class is a simple wrapper around an alias analysis cache. This is
|
||||
/// needed since we do not have an "analysis" infrastructure.
|
||||
@@ -91,6 +92,7 @@ public:
|
||||
private:
|
||||
SILModule *Mod;
|
||||
SideEffectAnalysis *SEA;
|
||||
EscapeAnalysis *EA;
|
||||
|
||||
using TBAACacheKey = std::pair<SILType, SILType>;
|
||||
|
||||
@@ -140,7 +142,7 @@ private:
|
||||
|
||||
public:
|
||||
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) {
|
||||
return S->getKind() == AnalysisKind::Alias;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
|
||||
#include "swift/SILOptimizer/Analysis/ValueTracking.h"
|
||||
#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h"
|
||||
#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h"
|
||||
#include "swift/SILOptimizer/Utils/Local.h"
|
||||
#include "swift/SILOptimizer/PassManager/PassManager.h"
|
||||
#include "swift/SIL/Projection.h"
|
||||
@@ -175,47 +176,6 @@ static bool isIdentifiedFunctionLocal(SILValue 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
|
||||
/// can not alias.
|
||||
static bool aliasUnequalObjects(SILValue O1, SILValue O2) {
|
||||
@@ -243,16 +203,6 @@ static bool aliasUnequalObjects(SILValue O1, SILValue O2) {
|
||||
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.
|
||||
return false;
|
||||
}
|
||||
@@ -644,6 +594,14 @@ AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
|
||||
if (O1 != O2 && aliasUnequalObjects(O1, O2))
|
||||
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
|
||||
// their inequality. Now we climb up use-def chains and attempt to do tricks
|
||||
// based off of GEPs.
|
||||
@@ -698,6 +656,7 @@ bool swift::isLetPointer(SILValue V) {
|
||||
|
||||
void AliasAnalysis::initialize(SILPassManager *PM) {
|
||||
SEA = PM->getAnalysis<SideEffectAnalysis>();
|
||||
EA = PM->getAnalysis<EscapeAnalysis>();
|
||||
}
|
||||
|
||||
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): %8 = load %3#1 : $*Builtin.NativeObject
|
||||
// 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)
|
||||
|
||||
@@ -318,10 +314,6 @@ sil @use_native_object : $@convention(thin) (Builtin.NativeObject) -> ()
|
||||
// CHECK-NEXT: (0): %3 = alloc_stack $Builtin.NativeObject
|
||||
// CHECK-NEXT: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
||||
// 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-NEXT: (1): %3 = alloc_stack $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: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
||||
// 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).
|
||||
|
||||
@@ -373,7 +361,7 @@ sil @use_native_object : $@convention(thin) (Builtin.NativeObject) -> ()
|
||||
// CHECK-NEXT: (0): %8 = load %3#1 : $*Builtin.NativeObject
|
||||
// CHECK-NEXT: (0): %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
|
||||
// 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):
|
||||
%2 = alloc_stack $Builtin.NativeObject
|
||||
%3 = alloc_stack $Builtin.NativeObject
|
||||
@@ -515,3 +503,25 @@ bb0(%0 : $C, %1 : $C, %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