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:
Erik Eckstein
2015-12-17 17:07:51 -08:00
parent ae6fa34645
commit 09c61c61bf
3 changed files with 36 additions and 65 deletions

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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
}