Skip to content

Commit cdacda9

Browse files
committed
Merge pull request #11 from nadavrot/alias_analysis_cleanups
Alias Analysis cleanups
2 parents 5ed14f1 + 971aa23 commit cdacda9

File tree

4 files changed

+105
-139
lines changed

4 files changed

+105
-139
lines changed

Diff for: include/swift/SILAnalysis/AliasAnalysis.h

+56-52
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,24 @@ class SideEffectAnalysis;
2828
/// needed since we do not have an "analysis" infrastructure.
2929
class AliasAnalysis : public SILAnalysis {
3030
public:
31-
/// The result of an alias query. This is based off of LLVM's alias
32-
/// analysis so see LLVM's documentation for more information.
31+
32+
/// This enum describes the different kinds of aliasing relations between
33+
/// pointers.
34+
///
35+
/// NoAlias: There is never dependence between memory referenced by the two
36+
/// pointers. Example: Two pointers pointing to non-overlapping
37+
/// memory ranges.
38+
///
39+
/// MayAlias: Two pointers might refer to the same memory location.
40+
///
41+
///
42+
/// PartialAlias: The two memory locations are known to be overlapping
43+
/// but do not start at the same address.
44+
///
45+
///
46+
/// MustAlias: The two memory locations always start at exactly the same
47+
/// location. The pointers are equal.
3348
///
34-
/// FIXME: PartialAlias?
3549
enum class AliasResult : unsigned {
3650
NoAlias=0, ///< The two values have no dependencies on each
3751
/// other.
@@ -42,15 +56,11 @@ class AliasAnalysis : public SILAnalysis {
4256
};
4357

4458
private:
45-
using AliasCacheKey = std::pair<SILValue, SILValue>;
46-
llvm::DenseMap<AliasCacheKey, AliasResult> AliasCache;
4759
SILModule *Mod;
4860
SideEffectAnalysis *SEA;
4961

5062
using MemoryBehavior = SILInstruction::MemoryBehavior;
5163

52-
AliasResult cacheValue(AliasCacheKey Key, AliasResult Result);
53-
5464
AliasResult aliasAddressProjection(SILValue V1, SILValue V2,
5565
SILValue O1, SILValue O2);
5666

@@ -70,84 +80,77 @@ class AliasAnalysis : public SILAnalysis {
7080

7181
SideEffectAnalysis *getSideEffectAnalysis() const { return SEA; }
7282

73-
/// Perform an alias query to see if V1, V2 refer to the same values.
74-
AliasResult alias(SILValue V1, SILValue V2, SILType TBAAType1 = SILType(),
83+
/// Compute the alias properties of the pointers \p V1 and \p V2.
84+
/// The optional arguments \pTBAAType1 and \p TBAAType2 specify the exact
85+
/// types that the pointers access.
86+
AliasResult alias(SILValue V1, SILValue V2,
87+
SILType TBAAType1 = SILType(),
7588
SILType TBAAType2 = SILType());
7689

77-
/// Convenience method that returns true if V1 and V2 must alias.
78-
bool isMustAlias(SILValue V1, SILValue V2, SILType TBAAType1 = SILType(),
79-
SILType TBAAType2 = SILType()) {
80-
return alias(V1, V2, TBAAType1, TBAAType2) == AliasResult::MustAlias;
81-
}
82-
83-
/// Convenience method that returns true if V1 and V2 partially alias.
84-
bool isPartialAlias(SILValue V1, SILValue V2, SILType TBAAType1 = SILType(),
85-
SILType TBAAType2 = SILType()) {
86-
return alias(V1, V2, TBAAType1, TBAAType2) == AliasResult::PartialAlias;
90+
#define ALIAS_PROPERTY_CONVENIENCE_METHOD(KIND) \
91+
bool is##KIND(SILValue V1, SILValue V2, \
92+
SILType TBAAType1 = SILType(), \
93+
SILType TBAAType2 = SILType()) { \
94+
return alias(V1, V2, TBAAType1, TBAAType2) == AliasResult::KIND; \
8795
}
8896

89-
/// Convenience method that returns true if V1, V2 can not alias.
90-
bool isNoAlias(SILValue V1, SILValue V2, SILType TBAAType1 = SILType(),
91-
SILType TBAAType2 = SILType()) {
92-
return alias(V1, V2, TBAAType1, TBAAType2) == AliasResult::NoAlias;
93-
}
97+
ALIAS_PROPERTY_CONVENIENCE_METHOD(MustAlias)
98+
ALIAS_PROPERTY_CONVENIENCE_METHOD(PartialAlias)
99+
ALIAS_PROPERTY_CONVENIENCE_METHOD(NoAlias)
100+
ALIAS_PROPERTY_CONVENIENCE_METHOD(MayAlias)
94101

95-
/// Convenience method that returns true if V1, V2 may alias.
96-
bool isMayAlias(SILValue V1, SILValue V2, SILType TBAAType1 = SILType(),
97-
SILType TBAAType2 = SILType()) {
98-
return alias(V1, V2, TBAAType1, TBAAType2) == AliasResult::MayAlias;
99-
}
102+
#undef ALIAS_PROPERTY_CONVENIENCE_METHOD
100103

101104
/// Use the alias analysis to determine the memory behavior of Inst with
102105
/// respect to V.
103106
///
104107
/// TODO: When ref count behavior is separated from generic memory behavior,
105108
/// the IgnoreRefCountIncrements flag will be unnecessary.
106-
MemoryBehavior getMemoryBehavior(SILInstruction *Inst, SILValue V,
107-
RetainObserveKind =
108-
RetainObserveKind::ObserveRetains);
109+
MemoryBehavior computeMemoryBehavior(SILInstruction *Inst, SILValue V,
110+
RetainObserveKind);
109111

110-
/// Returns true if Inst may read from memory in a manner that affects V.
112+
/// Returns true if \p Inst may read from memory in a manner that
113+
/// affects V.
111114
bool mayReadFromMemory(SILInstruction *Inst, SILValue V) {
112-
MemoryBehavior B = getMemoryBehavior(Inst, V,
113-
RetainObserveKind::IgnoreRetains);
115+
auto B = computeMemoryBehavior(Inst, V, RetainObserveKind::IgnoreRetains);
114116
return B == MemoryBehavior::MayRead ||
115-
B == MemoryBehavior::MayReadWrite ||
116-
B == MemoryBehavior::MayHaveSideEffects;
117+
B == MemoryBehavior::MayReadWrite ||
118+
B == MemoryBehavior::MayHaveSideEffects;
117119
}
118120

119-
/// Returns true if Inst may write to memory in a manner that affects V.
121+
/// Returns true if \p Inst may write to memory in a manner that
122+
/// affects V.
120123
bool mayWriteToMemory(SILInstruction *Inst, SILValue V) {
121-
MemoryBehavior B = getMemoryBehavior(Inst, V,
122-
RetainObserveKind::IgnoreRetains);
124+
auto B = computeMemoryBehavior(Inst, V, RetainObserveKind::IgnoreRetains);
123125
return B == MemoryBehavior::MayWrite ||
124-
B == MemoryBehavior::MayReadWrite ||
125-
B == MemoryBehavior::MayHaveSideEffects;
126+
B == MemoryBehavior::MayReadWrite ||
127+
B == MemoryBehavior::MayHaveSideEffects;
126128
}
127129

128-
/// Returns true if Inst may read or write to memory in a manner that affects
129-
/// V.
130+
/// Returns true if \p Inst may read or write to memory in a manner that
131+
/// affects V.
130132
bool mayReadOrWriteMemory(SILInstruction *Inst, SILValue V) {
131-
auto B = getMemoryBehavior(Inst, V, RetainObserveKind::IgnoreRetains);
132-
return B != MemoryBehavior::None;
133+
auto B = computeMemoryBehavior(Inst, V, RetainObserveKind::IgnoreRetains);
134+
return MemoryBehavior::None != B;
133135
}
134136

135137
/// Returns true if Inst may have side effects in a manner that affects V.
136138
bool mayHaveSideEffects(SILInstruction *Inst, SILValue V) {
137-
MemoryBehavior B = getMemoryBehavior(Inst, V);
139+
auto B = computeMemoryBehavior(Inst, V, RetainObserveKind::ObserveRetains);
138140
return B == MemoryBehavior::MayWrite ||
139-
B == MemoryBehavior::MayReadWrite ||
140-
B == MemoryBehavior::MayHaveSideEffects;
141+
B == MemoryBehavior::MayReadWrite ||
142+
B == MemoryBehavior::MayHaveSideEffects;
141143
}
142144

143145
/// Returns true if Inst may have side effects in a manner that affects
144146
/// V. This is independent of whether or not Inst may write to V and is meant
145147
/// to encode notions such as ref count modifications.
146148
bool mayHavePureSideEffects(SILInstruction *Inst, SILValue V) {
147-
return getMemoryBehavior(Inst, V) == MemoryBehavior::MayHaveSideEffects;
149+
auto B = computeMemoryBehavior(Inst, V, RetainObserveKind::ObserveRetains);
150+
return MemoryBehavior::MayHaveSideEffects == B;
148151
}
149152

150-
virtual void invalidate(SILAnalysis::InvalidationKind K) { AliasCache.clear(); }
153+
virtual void invalidate(SILAnalysis::InvalidationKind K) { }
151154

152155
virtual void invalidate(SILFunction *, SILAnalysis::InvalidationKind K) {
153156
invalidate(K);
@@ -161,7 +164,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
161164
/// Otherwise, return an empty type.
162165
SILType computeTBAAType(SILValue V);
163166

164-
/// Check if V points to a let-variable.
167+
/// Check if \p V points to a let-member.
168+
/// Nobody can write into let members.
165169
bool isLetPointer(SILValue V);
166170

167171
} // end namespace swift

Diff for: lib/SILAnalysis/AliasAnalysis.cpp

+31-71
Original file line numberDiff line numberDiff line change
@@ -76,26 +76,18 @@ static inline bool shouldRunBasicAA() {
7676

7777
#endif
7878

79-
static llvm::cl::opt<bool>
80-
CacheAAResults("cache-aa-results",
81-
llvm::cl::desc("Should AA results be cached"),
82-
llvm::cl::init(true));
83-
8479
//===----------------------------------------------------------------------===//
8580
// Utilities
8681
//===----------------------------------------------------------------------===//
8782

88-
llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS,
89-
AliasAnalysis::AliasResult R) {
83+
using AliasResult = AliasAnalysis::AliasResult;
84+
85+
llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, AliasResult R) {
9086
switch (R) {
91-
case AliasAnalysis::AliasResult::NoAlias:
92-
return OS << "NoAlias";
93-
case AliasAnalysis::AliasResult::MayAlias:
94-
return OS << "MayAlias";
95-
case AliasAnalysis::AliasResult::PartialAlias:
96-
return OS << "PartialAlias";
97-
case AliasAnalysis::AliasResult::MustAlias:
98-
return OS << "MustAlias";
87+
case AliasResult::NoAlias: return OS << "NoAlias";
88+
case AliasResult::MayAlias: return OS << "MayAlias";
89+
case AliasResult::PartialAlias: return OS << "PartialAlias";
90+
case AliasResult::MustAlias: return OS << "MustAlias";
9991
}
10092
}
10193

@@ -265,9 +257,8 @@ static bool aliasUnequalObjects(SILValue O1, SILValue O2) {
265257
/// Uses a bunch of ad-hoc rules to disambiguate a GEP instruction against
266258
/// another pointer. We know that V1 is a GEP, but we don't know anything about
267259
/// V2. O1, O2 are getUnderlyingObject of V1, V2 respectively.
268-
AliasAnalysis::AliasResult
269-
AliasAnalysis::aliasAddressProjection(SILValue V1, SILValue V2,
270-
SILValue O1, SILValue O2) {
260+
AliasResult AliasAnalysis::aliasAddressProjection(SILValue V1, SILValue V2,
261+
SILValue O1, SILValue O2) {
271262

272263
// If V2 is also a gep instruction with a must-alias or not-aliasing base
273264
// pointer, figure out if the indices of the GEPs tell us anything about the
@@ -278,9 +269,9 @@ AliasAnalysis::aliasAddressProjection(SILValue V1, SILValue V2,
278269
// must alias relation on O1. This ensures that given an alloc_stack and a
279270
// gep from that alloc_stack, we say that they partially alias.
280271
if (isSameValueOrGlobal(O1, V2.stripCasts()))
281-
return AliasAnalysis::AliasResult::PartialAlias;
272+
return AliasResult::PartialAlias;
282273

283-
return AliasAnalysis::AliasResult::MayAlias;
274+
return AliasResult::MayAlias;
284275
}
285276

286277
assert(!Projection::isAddrProjection(O1) &&
@@ -289,12 +280,12 @@ AliasAnalysis::aliasAddressProjection(SILValue V1, SILValue V2,
289280
"underlying object may not be a projection");
290281

291282
// Do the base pointers alias?
292-
AliasAnalysis::AliasResult BaseAlias = aliasInner(O1, O2);
283+
AliasResult BaseAlias = aliasInner(O1, O2);
293284

294285
// If the underlying objects are not aliased, the projected values are also
295286
// not aliased.
296-
if (BaseAlias == AliasAnalysis::AliasResult::NoAlias)
297-
return AliasAnalysis::AliasResult::NoAlias;
287+
if (BaseAlias == AliasResult::NoAlias)
288+
return AliasResult::NoAlias;
298289

299290
// Let's do alias checking based on projections.
300291
auto V1Path = ProjectionPath::getAddrProjectionPath(O1, V1, true);
@@ -311,32 +302,32 @@ AliasAnalysis::aliasAddressProjection(SILValue V1, SILValue V2,
311302
// horizon) or enable Projection to represent a cast as a special sort of
312303
// projection.
313304
if (!V1Path || !V2Path)
314-
return AliasAnalysis::AliasResult::MayAlias;
305+
return AliasResult::MayAlias;
315306

316307
auto R = V1Path->computeSubSeqRelation(*V2Path);
317308

318309
// If all of the projections are equal (and they have the same base pointer),
319310
// the two GEPs must be the same.
320-
if (BaseAlias == AliasAnalysis::AliasResult::MustAlias &&
311+
if (BaseAlias == AliasResult::MustAlias &&
321312
R == SubSeqRelation_t::Equal)
322-
return AliasAnalysis::AliasResult::MustAlias;
313+
return AliasResult::MustAlias;
323314

324315
// The two GEPs do not alias if they are accessing different fields, even if
325316
// we don't know the base pointers. Different fields should not overlap.
326317
//
327318
// TODO: Replace this with a check on the computed subseq relation. See the
328319
// TODO in computeSubSeqRelation.
329320
if (V1Path->hasNonEmptySymmetricDifference(V2Path.getValue()))
330-
return AliasAnalysis::AliasResult::NoAlias;
321+
return AliasResult::NoAlias;
331322

332323
// If one of the GEPs is a super path of the other then they partially
333324
// alias. W
334-
if (BaseAlias == AliasAnalysis::AliasResult::MustAlias &&
325+
if (BaseAlias == AliasResult::MustAlias &&
335326
isStrictSubSeqRelation(R))
336-
return AliasAnalysis::AliasResult::PartialAlias;
327+
return AliasResult::PartialAlias;
337328

338329
// We failed to prove anything. Be conservative and return MayAlias.
339-
return AliasAnalysis::AliasResult::MayAlias;
330+
return AliasResult::MayAlias;
340331
}
341332

342333

@@ -606,19 +597,17 @@ static bool typesMayAlias(SILType T1, SILType T2, SILType TBAA1Ty,
606597

607598
/// The main AA entry point. Performs various analyses on V1, V2 in an attempt
608599
/// to disambiguate the two values.
609-
AliasAnalysis::AliasResult AliasAnalysis::alias(SILValue V1, SILValue V2,
610-
SILType TBAAType1,
611-
SILType TBAAType2) {
612-
auto Result = aliasInner(V1, V2, TBAAType1, TBAAType2);
613-
AliasCache.clear();
614-
return Result;
600+
AliasResult AliasAnalysis::alias(SILValue V1, SILValue V2,
601+
SILType TBAAType1,
602+
SILType TBAAType2) {
603+
return aliasInner(V1, V2, TBAAType1, TBAAType2);
615604
}
616605

617606
/// The main AA entry point. Performs various analyses on V1, V2 in an attempt
618607
/// to disambiguate the two values.
619-
AliasAnalysis::AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
620-
SILType TBAAType1,
621-
SILType TBAAType2) {
608+
AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
609+
SILType TBAAType1,
610+
SILType TBAAType2) {
622611
#ifndef NDEBUG
623612
// If alias analysis is disabled, always return may alias.
624613
if (!shouldRunAA())
@@ -648,24 +637,6 @@ AliasAnalysis::AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
648637
DEBUG(llvm::dbgs() << " After Cast Stripping V1:" << *V1.getDef());
649638
DEBUG(llvm::dbgs() << " After Cast Stripping V2:" << *V2.getDef());
650639

651-
// Create a key to lookup if we have already computed an alias result for V1,
652-
// V2. Canonicalize our cache keys so that the pointer with the lower address
653-
// is always the first element of the pair. This ensures we do not pollute our
654-
// cache with two entries with the same key, albeit with the key's fields
655-
// swapped.
656-
auto Key = V1 < V2? std::make_pair(V1, V2) : std::make_pair(V2, V1);
657-
658-
// If we find our key in the cache, just return the alias result.
659-
if (CacheAAResults) {
660-
auto Pair = AliasCache.find(Key);
661-
if (Pair != AliasCache.end()) {
662-
DEBUG(llvm::dbgs() << " Found value in the cache: " << Pair->second
663-
<< "\n");
664-
665-
return Pair->second;
666-
}
667-
}
668-
669640
// Ok, we need to actually compute an Alias Analysis result for V1, V2. Begin
670641
// by finding the "base" of V1, V2 by stripping off all casts and GEPs.
671642
SILValue O1 = getUnderlyingObject(V1);
@@ -676,7 +647,7 @@ AliasAnalysis::AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
676647
// If O1 and O2 do not equal, see if we can prove that they can not be the
677648
// same object. If we can, return No Alias.
678649
if (O1 != O2 && aliasUnequalObjects(O1, O2))
679-
return cacheValue(Key, AliasResult::NoAlias);
650+
return AliasResult::NoAlias;
680651

681652
// Ok, either O1, O2 are the same or we could not prove anything based off of
682653
// their inequality. Now we climb up use-def chains and attempt to do tricks
@@ -694,19 +665,16 @@ AliasAnalysis::AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2,
694665
if (Projection::isAddrProjection(V1)) {
695666
AliasResult Result = aliasAddressProjection(V1, V2, O1, O2);
696667
if (Result != AliasResult::MayAlias)
697-
return cacheValue(Key, Result);
668+
return Result;
698669
}
699670

700-
701671
// We could not prove anything. Be conservative and return that V1, V2 may
702672
// alias.
703673
return AliasResult::MayAlias;
704674
}
705675

706-
/// Check if this is the address of a "let" member.
707-
/// Nobody can write into let members.
708676
bool swift::isLetPointer(SILValue V) {
709-
// Traverse the "access" path for V and check that starts with "let"
677+
// Traverse the "access" path for V and check that it starts with "let"
710678
// and everything along this path is a value-type (i.e. struct or tuple).
711679

712680
// Is this an address of a "let" class member?
@@ -733,14 +701,6 @@ bool swift::isLetPointer(SILValue V) {
733701
return false;
734702
}
735703

736-
AliasAnalysis::AliasResult AliasAnalysis::cacheValue(AliasCacheKey Key,
737-
AliasResult Result) {
738-
if (!CacheAAResults)
739-
return Result;
740-
DEBUG(llvm::dbgs() << "Caching Alias Result: " << Result << "\n" << Key.first
741-
<< Key.second << "\n");
742-
return AliasCache[Key] = Result;
743-
}
744704

745705
void AliasAnalysis::initialize(SILPassManager *PM) {
746706
SEA = PM->getAnalysis<SideEffectAnalysis>();

0 commit comments

Comments
 (0)