Skip to content

Commit d2fc6eb

Browse files
committed
AliasAnalysis: make AliasAnalysis a function analysis and simplify the cache keys
Instead of caching alias results globally for the module, make AliasAnalysis a FunctionAnalysisBase which caches the alias results per function. Why? * So far the result caches could only grow. They were reset when they reached a certain size. This was not ideal. Now, they are invalidated whenever the function changes. * It was not possible to actually invalidate an alias analysis result. This is required, for example in TempRValueOpt and TempLValueOpt (so far it was done manually with invalidateInstruction). * Type based alias analysis results were also cached for the whole module, while it is actually dependent on the function, because it depends on the function's resilience expansion. This was a potential bug. I also added a new PassManager API to directly get a function-base analysis: getAnalysis(SILFunction *f) The second change of this commit is the removal of the instruction-index indirection for the cache keys. Now the cache keys directly work on instruction pointers instead of instruction indices. This reduces the number of hash table lookups for a cache lookup from 3 to 1. This indirection was needed to avoid dangling instruction pointers in the cache keys. But this is not needed anymore, because of the new delayed instruction deletion mechanism.
1 parent 24799e1 commit d2fc6eb

21 files changed

+194
-339
lines changed

include/swift/SILOptimizer/Analysis/AliasAnalysis.h

+58-151
Original file line numberDiff line numberDiff line change
@@ -13,53 +13,19 @@
1313
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_ALIASANALYSIS_H
1414
#define SWIFT_SILOPTIMIZER_ANALYSIS_ALIASANALYSIS_H
1515

16-
#include "swift/Basic/ValueEnumerator.h"
1716
#include "swift/SIL/ApplySite.h"
1817
#include "swift/SIL/SILInstruction.h"
1918
#include "swift/SILOptimizer/Analysis/Analysis.h"
20-
#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h"
2119
#include "llvm/ADT/DenseMap.h"
2220

23-
using swift::RetainObserveKind;
24-
25-
namespace {
26-
27-
/// A key used for the AliasAnalysis cache.
28-
///
29-
/// This struct represents the argument list to the method 'alias'. The two
30-
/// SILValue pointers are mapped to integer indices because we need an
31-
/// efficient way to invalidate them (the mechanism is described below). The
32-
/// Type arguments are translated to void* because their underlying storage is
33-
/// opaque pointers that never goes away.
34-
struct AliasKeyTy {
35-
// The SILValue pair:
36-
swift::ValueIndexTy V1, V2;
37-
// The TBAAType pair:
38-
void *T1, *T2;
39-
};
40-
41-
/// A key used for the MemoryBehavior Analysis cache.
42-
///
43-
/// The two SILValue pointers are mapped to integer indices because we need an
44-
/// efficient way to invalidate them (the mechanism is described below). The
45-
/// RetainObserveKind represents the inspection mode for the memory behavior
46-
/// analysis.
47-
struct MemBehaviorKeyTy {
48-
// The SILValue pair:
49-
swift::ValueIndexTy V1, V2;
50-
};
51-
}
52-
5321
namespace swift {
5422

55-
class SILInstruction;
56-
class ValueBase;
5723
class SideEffectAnalysis;
5824
class EscapeAnalysis;
5925

6026
/// This class is a simple wrapper around an alias analysis cache. This is
6127
/// needed since we do not have an "analysis" infrastructure.
62-
class AliasAnalysis : public SILAnalysis {
28+
class AliasAnalysis {
6329
public:
6430

6531
/// This enum describes the different kinds of aliasing relations between
@@ -89,12 +55,28 @@ class AliasAnalysis : public SILAnalysis {
8955
};
9056

9157
private:
92-
SILModule *Mod;
93-
SideEffectAnalysis *SEA;
94-
EscapeAnalysis *EA;
58+
/// A key used for the AliasAnalysis cache.
59+
///
60+
/// This struct represents the argument list to the method 'alias'.
61+
struct AliasCacheKey {
62+
// The SILValue pair:
63+
SILValue V1, V2;
64+
// The TBAAType pair:
65+
void *T1, *T2;
66+
};
67+
68+
friend struct ::llvm::DenseMapInfo<swift::AliasAnalysis::AliasCacheKey>;
69+
70+
/// A key used for the MemoryBehavior Analysis cache.
71+
using MemBehaviorCacheKey = std::pair<SILValue, SILInstruction *>;
72+
73+
using ScopeCacheKey = std::pair<SILInstruction *, SILInstruction *>;
9574

9675
using TBAACacheKey = std::pair<SILType, SILType>;
9776

77+
SideEffectAnalysis *SEA;
78+
EscapeAnalysis *EA;
79+
9880
/// A cache for the computation of TBAA. True means that the types may
9981
/// alias. False means that the types must not alias.
10082
///
@@ -105,33 +87,27 @@ class AliasAnalysis : public SILAnalysis {
10587
/// AliasAnalysis value cache.
10688
///
10789
/// The alias() method uses this map to cache queries.
108-
llvm::DenseMap<AliasKeyTy, AliasResult> AliasCache;
90+
llvm::DenseMap<AliasCacheKey, AliasResult> AliasCache;
10991

11092
using MemoryBehavior = SILInstruction::MemoryBehavior;
93+
11194
/// MemoryBehavior value cache.
11295
///
11396
/// The computeMemoryBehavior() method uses this map to cache queries.
114-
llvm::DenseMap<MemBehaviorKeyTy, MemoryBehavior> MemoryBehaviorCache;
97+
llvm::DenseMap<MemBehaviorCacheKey, MemoryBehavior> MemoryBehaviorCache;
11598

11699
/// Set of instructions inside immutable-scopes.
117100
///
118-
/// Contains pairs of intruction indices: the first instruction is the begin-
119-
/// scope instruction (e.g. begin_access), the second instruction is an
101+
/// Contains pairs of intructions: the first instruction is the begin-scope
102+
/// instruction (e.g. begin_access), the second instruction is an
120103
/// instruction inside the scope (only may-write instructions are considered).
121-
llvm::DenseSet<MemBehaviorKeyTy> instsInImmutableScopes;
104+
llvm::DenseSet<ScopeCacheKey> instsInImmutableScopes;
122105

123106
/// Computed immutable scopes.
124107
///
125-
/// Contains the begin-scope instruction's indices (e.g. begin_access) of
126-
/// all computed scopes.
127-
llvm::DenseSet<ValueIndexTy> immutableScopeComputed;
128-
129-
/// The caches can't directly map a pair of value/instruction pointers
130-
/// to results because we'd like to be able to remove deleted instruction
131-
/// pointers without having to scan the whole map. So, instead of storing
132-
/// pointers we map pointers to indices and store the indices.
133-
ValueEnumerator<ValueBase *> ValueToIndex;
134-
ValueEnumerator<SILInstruction *> InstructionToIndex;
108+
/// Contains the begin-scope instructions (e.g. begin_access) of all computed
109+
/// scopes.
110+
llvm::SmallPtrSet<SILInstruction *, 16> immutableScopeComputed;
135111

136112
AliasResult aliasAddressProjection(SILValue V1, SILValue V2,
137113
SILValue O1, SILValue O2);
@@ -144,34 +120,15 @@ class AliasAnalysis : public SILAnalysis {
144120
/// Returns True if memory of type \p T1 and \p T2 may alias.
145121
bool typesMayAlias(SILType T1, SILType T2, const SILFunction &F);
146122

147-
virtual void handleDeleteNotification(SILNode *node) override;
148-
149-
virtual bool needsNotifications() override { return true; }
150-
151-
void computeImmutableScope(SingleValueInstruction *beginScopeInst,
152-
ValueIndexTy beginIdx);
123+
void computeImmutableScope(SingleValueInstruction *beginScopeInst);
153124

154125
bool isInImmutableScope(SILInstruction *inst, SILValue V);
155126

156127
public:
157-
AliasAnalysis(SILModule *M)
158-
: SILAnalysis(SILAnalysisKind::Alias), Mod(M), SEA(nullptr), EA(nullptr) {
159-
}
160-
161-
static bool classof(const SILAnalysis *S) {
162-
return S->getKind() == SILAnalysisKind::Alias;
163-
}
164-
165-
virtual void initialize(SILPassManager *PM) override;
128+
AliasAnalysis(SideEffectAnalysis *SEA, EscapeAnalysis *EA)
129+
: SEA(SEA), EA(EA) {}
166130

167-
/// Explicitly invalidate an instruction.
168-
///
169-
/// This can be useful to update the alias analysis within a pass.
170-
/// It's needed if e.g. \p inst is an address projection and its operand gets
171-
/// replaced with a different underlying object.
172-
void invalidateInstruction(SILInstruction *inst) {
173-
handleDeleteNotification(inst->asSILNode());
174-
}
131+
static SILAnalysisKind getAnalysisKind() { return SILAnalysisKind::Alias; }
175132

176133
/// Perform an alias query to see if V1, V2 refer to the same values.
177134
AliasResult alias(SILValue V1, SILValue V2, SILType TBAAType1 = SILType(),
@@ -249,37 +206,6 @@ class AliasAnalysis : public SILAnalysis {
249206

250207
/// Returns true if \p Ptr may be released by the builtin \p BI.
251208
bool canBuiltinDecrementRefCount(BuiltinInst *BI, SILValue Ptr);
252-
253-
/// Encodes the alias query as a AliasKeyTy.
254-
/// The parameters to this function are identical to the parameters of alias()
255-
/// and this method serializes them into a key for the alias analysis cache.
256-
AliasKeyTy toAliasKey(SILValue V1, SILValue V2, SILType Type1, SILType Type2);
257-
258-
/// Encodes the memory behavior query as a MemBehaviorKeyTy.
259-
MemBehaviorKeyTy toMemoryBehaviorKey(SILInstruction *V1, SILValue V2);
260-
261-
virtual void invalidate() override {
262-
AliasCache.clear();
263-
MemoryBehaviorCache.clear();
264-
InstructionToIndex.clear();
265-
ValueToIndex.clear();
266-
instsInImmutableScopes.clear();
267-
immutableScopeComputed.clear();
268-
}
269-
270-
virtual void invalidate(SILFunction *,
271-
SILAnalysis::InvalidationKind K) override {
272-
invalidate();
273-
}
274-
275-
/// Notify the analysis about a newly created function.
276-
virtual void notifyAddedOrModifiedFunction(SILFunction *F) override {}
277-
278-
/// Notify the analysis about a function which will be deleted from the
279-
/// module.
280-
virtual void notifyWillDeleteFunction(SILFunction *F) override {}
281-
282-
virtual void invalidateFunctionTables() override { }
283209
};
284210

285211

@@ -293,51 +219,32 @@ SILType computeTBAAType(SILValue V);
293219
} // end namespace swift
294220

295221
namespace llvm {
296-
template <> struct DenseMapInfo<AliasKeyTy> {
297-
static inline AliasKeyTy getEmptyKey() {
298-
auto Allone = std::numeric_limits<swift::ValueIndexTy>::max();
299-
return {0, Allone, nullptr, nullptr};
300-
}
301-
static inline AliasKeyTy getTombstoneKey() {
302-
auto Allone = std::numeric_limits<swift::ValueIndexTy>::max();
303-
return {Allone, 0, nullptr, nullptr};
304-
}
305-
static unsigned getHashValue(const AliasKeyTy Val) {
306-
unsigned H = 0;
307-
H ^= DenseMapInfo<swift::ValueIndexTy>::getHashValue(Val.V1);
308-
H ^= DenseMapInfo<swift::ValueIndexTy>::getHashValue(Val.V2);
309-
H ^= DenseMapInfo<void *>::getHashValue(Val.T1);
310-
H ^= DenseMapInfo<void *>::getHashValue(Val.T2);
311-
return H;
312-
}
313-
static bool isEqual(const AliasKeyTy LHS, const AliasKeyTy RHS) {
314-
return LHS.V1 == RHS.V1 &&
315-
LHS.V2 == RHS.V2 &&
316-
LHS.T1 == RHS.T1 &&
317-
LHS.T2 == RHS.T2;
318-
}
319-
};
222+
template <> struct DenseMapInfo<swift::AliasAnalysis::AliasCacheKey> {
223+
using AliasCacheKey = swift::AliasAnalysis::AliasCacheKey;
320224

321-
template <> struct DenseMapInfo<MemBehaviorKeyTy> {
322-
static inline MemBehaviorKeyTy getEmptyKey() {
323-
auto Allone = std::numeric_limits<swift::ValueIndexTy>::max();
324-
return {0, Allone};
325-
}
326-
static inline MemBehaviorKeyTy getTombstoneKey() {
327-
auto Allone = std::numeric_limits<swift::ValueIndexTy>::max();
328-
return {Allone, 0};
329-
}
330-
static unsigned getHashValue(const MemBehaviorKeyTy V) {
331-
unsigned H = 0;
332-
H ^= DenseMapInfo<swift::ValueIndexTy>::getHashValue(V.V1);
333-
H ^= DenseMapInfo<swift::ValueIndexTy>::getHashValue(V.V2);
334-
return H;
335-
}
336-
static bool isEqual(const MemBehaviorKeyTy LHS,
337-
const MemBehaviorKeyTy RHS) {
338-
return LHS.V1 == RHS.V1 && LHS.V2 == RHS.V2;
339-
}
340-
};
225+
static inline AliasCacheKey getEmptyKey() {
226+
return {DenseMapInfo<swift::SILValue>::getEmptyKey(), swift::SILValue(),
227+
nullptr, nullptr};
228+
}
229+
static inline AliasCacheKey getTombstoneKey() {
230+
return {DenseMapInfo<swift::SILValue>::getTombstoneKey(), swift::SILValue(),
231+
nullptr, nullptr};
232+
}
233+
static unsigned getHashValue(const AliasCacheKey Val) {
234+
unsigned H = 0;
235+
H ^= DenseMapInfo<swift::SILValue>::getHashValue(Val.V1);
236+
H ^= DenseMapInfo<swift::SILValue>::getHashValue(Val.V2);
237+
H ^= DenseMapInfo<void *>::getHashValue(Val.T1);
238+
H ^= DenseMapInfo<void *>::getHashValue(Val.T2);
239+
return H;
240+
}
241+
static bool isEqual(const AliasCacheKey LHS, const AliasCacheKey RHS) {
242+
return LHS.V1 == RHS.V1 &&
243+
LHS.V2 == RHS.V2 &&
244+
LHS.T1 == RHS.T1 &&
245+
LHS.T2 == RHS.T2;
246+
}
247+
};
341248
}
342249

343250
#endif

include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h

+7-10
Original file line numberDiff line numberDiff line change
@@ -273,18 +273,17 @@ class EpilogueARCFunctionInfo {
273273
};
274274

275275
class EpilogueARCAnalysis : public FunctionAnalysisBase<EpilogueARCFunctionInfo> {
276+
/// Backlink to the pass manager.
277+
SILPassManager *passManager = nullptr;
276278
/// Current post order analysis we are using.
277-
PostOrderAnalysis *PO;
278-
/// Current alias analysis we are using.
279-
AliasAnalysis *AA;
279+
PostOrderAnalysis *PO = nullptr;
280280
/// Current RC Identity analysis we are using.
281-
RCIdentityAnalysis *RC;
282-
281+
RCIdentityAnalysis *RC = nullptr;
282+
283283
public:
284284
EpilogueARCAnalysis(SILModule *)
285285
: FunctionAnalysisBase<EpilogueARCFunctionInfo>(
286-
SILAnalysisKind::EpilogueARC),
287-
PO(nullptr), AA(nullptr), RC(nullptr) {}
286+
SILAnalysisKind::EpilogueARC) {}
288287

289288
EpilogueARCAnalysis(const EpilogueARCAnalysis &) = delete;
290289
EpilogueARCAnalysis &operator=(const EpilogueARCAnalysis &) = delete;
@@ -312,9 +311,7 @@ class EpilogueARCAnalysis : public FunctionAnalysisBase<EpilogueARCFunctionInfo>
312311
virtual void initialize(SILPassManager *PM) override;
313312

314313
virtual std::unique_ptr<EpilogueARCFunctionInfo>
315-
newFunctionAnalysis(SILFunction *F) override {
316-
return std::make_unique<EpilogueARCFunctionInfo>(F, PO, AA, RC);
317-
}
314+
newFunctionAnalysis(SILFunction *F) override;
318315

319316
virtual bool shouldInvalidate(SILAnalysis::InvalidationKind K) override {
320317
return true;

include/swift/SILOptimizer/PassManager/PassManager.h

+9
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,15 @@ class SILPassManager {
132132
llvm_unreachable("Unable to find analysis for requested type.");
133133
}
134134

135+
template<typename T>
136+
T *getAnalysis(SILFunction *f) {
137+
for (SILAnalysis *A : Analyses) {
138+
if (A->getKind() == T::getAnalysisKind())
139+
return static_cast<FunctionAnalysisBase<T> *>(A)->get(f);
140+
}
141+
llvm_unreachable("Unable to find analysis for requested type.");
142+
}
143+
135144
/// \returns the module that the pass manager owns.
136145
SILModule *getModule() { return Mod; }
137146

include/swift/SILOptimizer/PassManager/Transforms.h

+3
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ namespace swift {
8686
template<typename T>
8787
T* getAnalysis() { return PM->getAnalysis<T>(); }
8888

89+
template<typename T>
90+
T* getAnalysis(SILFunction *f) { return PM->getAnalysis<T>(f); }
91+
8992
const SILOptions &getOptions() { return PM->getOptions(); }
9093
};
9194

lib/SILOptimizer/ARC/ARCLoopOpts.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class ARCLoopOpts : public SILFunctionTransform {
6666
}
6767

6868
// Get all of the analyses that we need.
69-
auto *AA = getAnalysis<AliasAnalysis>();
69+
auto *AA = getAnalysis<AliasAnalysis>(F);
7070
auto *RCFI = getAnalysis<RCIdentityAnalysis>()->get(F);
7171
auto *EAFI = getAnalysis<EpilogueARCAnalysis>()->get(F);
7272
auto *LRFI = getAnalysis<LoopRegionAnalysis>()->get(F);

lib/SILOptimizer/ARC/ARCSequenceOpts.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ class ARCSequenceOpts : public SILFunctionTransform {
260260
return;
261261

262262
if (!EnableLoopARC) {
263-
auto *AA = getAnalysis<AliasAnalysis>();
263+
auto *AA = getAnalysis<AliasAnalysis>(F);
264264
auto *POTA = getAnalysis<PostOrderAnalysis>();
265265
auto *RCFI = getAnalysis<RCIdentityAnalysis>()->get(F);
266266
auto *EAFI = getAnalysis<EpilogueARCAnalysis>()->get(F);
@@ -288,7 +288,7 @@ class ARCSequenceOpts : public SILFunctionTransform {
288288
LA->unlockInvalidation();
289289
}
290290

291-
auto *AA = getAnalysis<AliasAnalysis>();
291+
auto *AA = getAnalysis<AliasAnalysis>(F);
292292
auto *POTA = getAnalysis<PostOrderAnalysis>();
293293
auto *RCFI = getAnalysis<RCIdentityAnalysis>()->get(F);
294294
auto *EAFI = getAnalysis<EpilogueARCAnalysis>()->get(F);

0 commit comments

Comments
 (0)