Skip to content

Commit 92b56cb

Browse files
committed
[AliasAnalysis] Reintroduce the cache to AliasAnalysis.
This commit reintroduces the cache to AliasAnalysis. This cache solves the problem of dead pointers that stay in the cache maps after instructions are being deleted. It's inefficient to scan the whole cache every time we want to invalidate a single pointer (pointers can be a part of a key). We solve this problem by mapping pointers to internal indices. With this map in place it's very easy to invalidate real pointers (by removing them from the ptr-to-index map), and there is no harm in keeping stale indices in the map. We limit the size of the map to keep the memory usage down. The hit rate of the cache on stdlib is about ~85%.
1 parent 19ebd05 commit 92b56cb

File tree

2 files changed

+109
-6
lines changed

2 files changed

+109
-6
lines changed

include/swift/SILAnalysis/AliasAnalysis.h

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,28 @@
1313
#ifndef SWIFT_SILANALYSIS_ALIASANALYSIS_H
1414
#define SWIFT_SILANALYSIS_ALIASANALYSIS_H
1515

16+
#include "swift/Basic/ValueEnumerator.h"
1617
#include "swift/SIL/SILInstruction.h"
1718
#include "swift/SILAnalysis/Analysis.h"
1819
#include "swift/SILAnalysis/SideEffectAnalysis.h"
1920
#include "llvm/ADT/DenseMap.h"
2021

22+
namespace {
23+
/// A cache for AliasAnalysis.
24+
/// This struct represents the argument list to the method 'alias'.
25+
/// The two SILValue pointers are mapped to size_t indices because we need
26+
/// an efficient way to invalidate them (the mechanism is described below).
27+
/// The Type arguments are translated to void* because their
28+
/// underlying storage is opaque pointers that never goes away.
29+
struct AliasKeyTy {
30+
// The SILValue pair:
31+
size_t V1, V2;
32+
unsigned ResultNo1, ResultNo2;
33+
// The TBAAType pair:
34+
void *T1, *T2;
35+
};
36+
}
37+
2138
namespace swift {
2239

2340
class SILValue;
@@ -69,6 +86,16 @@ class AliasAnalysis : public SILAnalysis {
6986
/// never change.
7087
llvm::DenseMap<TBAACacheKey, bool> TypesMayAliasCache;
7188

89+
/// AliasAnalysis value cache.
90+
/// The alias() method uses this map to cache queries.
91+
llvm::DenseMap<AliasKeyTy, AliasResult> AliasCache;
92+
93+
/// The AliasAnalysis cache can't directly map a pair of ValueBase pointers
94+
/// to alias results because we'd like to be able to remove deleted pointers
95+
/// without having to scan the whole map. So, instead of storing pointers
96+
/// we map pointers to indices and store the indices.
97+
ValueEnumerator<ValueBase*> ValueBaseToIndex;
98+
7299
using MemoryBehavior = SILInstruction::MemoryBehavior;
73100

74101
AliasResult aliasAddressProjection(SILValue V1, SILValue V2,
@@ -83,7 +110,12 @@ class AliasAnalysis : public SILAnalysis {
83110
bool typesMayAlias(SILType T1, SILType T2);
84111

85112

86-
virtual void handleDeleteNotification(ValueBase *I) override { }
113+
virtual void handleDeleteNotification(ValueBase *I) override {
114+
// The pointer I is going away. We can't scan the whole cache and remove
115+
// all of the occurrences of the pointer. Instead we remove the pointer
116+
// from the cache the translates pointers to indices.
117+
ValueBaseToIndex.invalidateValue(I);
118+
}
87119

88120
public:
89121
AliasAnalysis(SILModule *M) :
@@ -172,14 +204,22 @@ class AliasAnalysis : public SILAnalysis {
172204
return MemoryBehavior::MayHaveSideEffects == B;
173205
}
174206

175-
virtual void invalidate(SILAnalysis::InvalidationKind K) override { }
207+
/// Encodes the alias query as a AliasKeyTy.
208+
/// The parameters to this function are identical to the parameters of alias()
209+
/// and this method serializes them into a key for the alias analysis cache.
210+
AliasKeyTy toAliasKey(SILValue V1, SILValue V2, SILType Type1, SILType Type2);
211+
212+
virtual void invalidate(SILAnalysis::InvalidationKind K) override {
213+
AliasCache.clear();
214+
}
176215

177216
virtual void invalidate(SILFunction *,
178217
SILAnalysis::InvalidationKind K) override {
179218
invalidate(K);
180219
}
181220
};
182221

222+
183223
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
184224
AliasAnalysis::AliasResult R);
185225

@@ -193,4 +233,34 @@ bool isLetPointer(SILValue V);
193233

194234
} // end namespace swift
195235

236+
namespace llvm {
237+
template <> struct llvm::DenseMapInfo<AliasKeyTy> {
238+
static inline AliasKeyTy getEmptyKey() {
239+
return {0, 0, 0, 0, nullptr, nullptr};
240+
}
241+
static inline AliasKeyTy getTombstoneKey() {
242+
auto Allone = std::numeric_limits<size_t>::max();
243+
return {Allone, Allone, 0xff, 0xff, nullptr, nullptr};
244+
}
245+
static unsigned getHashValue(const AliasKeyTy Val) {
246+
unsigned H = 0;
247+
H ^= DenseMapInfo<size_t>::getHashValue(Val.V1);
248+
H ^= DenseMapInfo<size_t>::getHashValue(Val.V2);
249+
H ^= DenseMapInfo<unsigned>::getHashValue(Val.ResultNo1);
250+
H ^= DenseMapInfo<unsigned>::getHashValue(Val.ResultNo2);
251+
H ^= DenseMapInfo<void *>::getHashValue(Val.T1);
252+
H ^= DenseMapInfo<void *>::getHashValue(Val.T2);
253+
return H;
254+
}
255+
static bool isEqual(const AliasKeyTy LHS, const AliasKeyTy RHS) {
256+
return LHS.V1 == RHS.V1 &&
257+
LHS.V2 == RHS.V2 &&
258+
LHS.ResultNo1 == RHS.ResultNo1 &&
259+
LHS.ResultNo2 == RHS.ResultNo2 &&
260+
LHS.T1 == RHS.T1 &&
261+
LHS.T2 == RHS.T2;
262+
}
263+
};
264+
}
265+
196266
#endif

lib/SILAnalysis/AliasAnalysis.cpp

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@
2828

2929
using namespace swift;
3030

31+
32+
// The AliasAnalysis Cache must not grow beyond this size.
33+
// We limit the size of the AA cache to 2**14 because we want to limit the
34+
// memory usage of this cache.
35+
static const int AliasAnalysisMaxCacheSize = 16384;
36+
37+
3138
//===----------------------------------------------------------------------===//
3239
// AA Debugging
3340
//===----------------------------------------------------------------------===//
@@ -570,9 +577,25 @@ bool AliasAnalysis::typesMayAlias(SILType T1, SILType T2) {
570577
/// The main AA entry point. Performs various analyses on V1, V2 in an attempt
571578
/// to disambiguate the two values.
572579
AliasResult AliasAnalysis::alias(SILValue V1, SILValue V2,
573-
SILType TBAAType1,
574-
SILType TBAAType2) {
575-
return aliasInner(V1, V2, TBAAType1, TBAAType2);
580+
SILType TBAAType1, SILType TBAAType2) {
581+
AliasKeyTy Key = toAliasKey(V1, V2, TBAAType1, TBAAType2);
582+
583+
// Check if we've already computed this result.
584+
auto It = AliasCache.find(Key);
585+
if (It != AliasCache.end()) {
586+
return It->second;
587+
}
588+
589+
// Flush the cache if the size of the cache is too large.
590+
if (AliasCache.size() > AliasAnalysisMaxCacheSize) {
591+
AliasCache.clear();
592+
ValueBaseToIndex.clear();
593+
}
594+
595+
// Calculate the aliasing result and store it in the cache.
596+
auto Result = aliasInner(V1, V2, TBAAType1, TBAAType2);
597+
AliasCache[Key] = Result;
598+
return Result;
576599
}
577600

578601
/// The main AA entry point. Performs various analyses on V1, V2 in an attempt
@@ -673,11 +696,21 @@ bool swift::isLetPointer(SILValue V) {
673696
return false;
674697
}
675698

676-
677699
void AliasAnalysis::initialize(SILPassManager *PM) {
678700
SEA = PM->getAnalysis<SideEffectAnalysis>();
679701
}
680702

681703
SILAnalysis *swift::createAliasAnalysis(SILModule *M) {
682704
return new AliasAnalysis(M);
683705
}
706+
707+
AliasKeyTy AliasAnalysis::toAliasKey(SILValue V1, SILValue V2,
708+
SILType Type1, SILType Type2) {
709+
size_t idx1 = ValueBaseToIndex.getIndex(V1.getDef());
710+
size_t idx2 = ValueBaseToIndex.getIndex(V2.getDef());
711+
unsigned R1 = V1.getResultNumber();
712+
unsigned R2 = V2.getResultNumber();
713+
void *t1 = Type1.getOpaqueValue();
714+
void *t2 = Type2.getOpaqueValue();
715+
return {idx1, idx2, R1, R2, t1, t2};
716+
}

0 commit comments

Comments
 (0)