Skip to content

Commit ba664d9

Browse files
committed
[AA] Move earliest escape tracking from DSE to AA
This is a followup to D109844 (and alternative to D109907), which integrates the new "earliest escape" tracking into AliasAnalysis. This is done by replacing the pre-existing context-free capture cache in AAQueryInfo with a replaceable (virtual) object with two implementations: The SimpleCaptureInfo implements the previous behavior (check whether object is captured at all), while EarliestEscapeInfo implements the new behavior from DSE. This combines the "earliest escape" analysis with the full power of BasicAA: It subsumes the call handling from D109907, considers a wider range of escape sources, and works with AA recursion. The compile-time cost is slightly higher than with D109907. Differential Revision: https://reviews.llvm.org/D110368
1 parent 327bbbb commit ba664d9

File tree

7 files changed

+129
-103
lines changed

7 files changed

+129
-103
lines changed

llvm/include/llvm/Analysis/AliasAnalysis.h

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class DominatorTree;
6161
class FenceInst;
6262
class Function;
6363
class InvokeInst;
64+
class LoopInfo;
6465
class PreservedAnalyses;
6566
class TargetLibraryInfo;
6667
class Value;
@@ -378,6 +379,50 @@ createModRefInfo(const FunctionModRefBehavior FMRB) {
378379
return ModRefInfo(FMRB & static_cast<int>(ModRefInfo::ModRef));
379380
}
380381

382+
/// Virtual base class for providers of capture information.
383+
struct CaptureInfo {
384+
virtual ~CaptureInfo() = 0;
385+
virtual bool isNotCapturedBeforeOrAt(const Value *Object,
386+
const Instruction *I) = 0;
387+
};
388+
389+
/// Context-free CaptureInfo provider, which computes and caches whether an
390+
/// object is captured in the function at all, but does not distinguish whether
391+
/// it was captured before or after the context instruction.
392+
class SimpleCaptureInfo final : public CaptureInfo {
393+
SmallDenseMap<const Value *, bool, 8> IsCapturedCache;
394+
395+
public:
396+
bool isNotCapturedBeforeOrAt(const Value *Object,
397+
const Instruction *I) override;
398+
};
399+
400+
/// Context-sensitive CaptureInfo provider, which computes and caches the
401+
/// earliest common dominator closure of all captures. It provides a good
402+
/// approximation to a precise "captures before" analysis.
403+
class EarliestEscapeInfo final : public CaptureInfo {
404+
DominatorTree &DT;
405+
const LoopInfo &LI;
406+
407+
/// Map from identified local object to an instruction before which it does
408+
/// not escape, or nullptr if it never escapes. The "earliest" instruction
409+
/// may be a conservative approximation, e.g. the first instruction in the
410+
/// function is always a legal choice.
411+
DenseMap<const Value *, Instruction *> EarliestEscapes;
412+
413+
/// Reverse map from instruction to the objects it is the earliest escape for.
414+
/// This is used for cache invalidation purposes.
415+
DenseMap<Instruction *, TinyPtrVector<const Value *>> Inst2Obj;
416+
417+
public:
418+
EarliestEscapeInfo(DominatorTree &DT, const LoopInfo &LI) : DT(DT), LI(LI) {}
419+
420+
bool isNotCapturedBeforeOrAt(const Value *Object,
421+
const Instruction *I) override;
422+
423+
void removeInstruction(Instruction *I);
424+
};
425+
381426
/// Reduced version of MemoryLocation that only stores a pointer and size.
382427
/// Used for caching AATags independent BasicAA results.
383428
struct AACacheLoc {
@@ -425,8 +470,7 @@ class AAQueryInfo {
425470
using AliasCacheT = SmallDenseMap<LocPair, CacheEntry, 8>;
426471
AliasCacheT AliasCache;
427472

428-
using IsCapturedCacheT = SmallDenseMap<const Value *, bool, 8>;
429-
IsCapturedCacheT IsCapturedCache;
473+
CaptureInfo *CI;
430474

431475
/// Query depth used to distinguish recursive queries.
432476
unsigned Depth = 0;
@@ -439,18 +483,26 @@ class AAQueryInfo {
439483
/// assumption is disproven.
440484
SmallVector<AAQueryInfo::LocPair, 4> AssumptionBasedResults;
441485

442-
AAQueryInfo() : AliasCache(), IsCapturedCache() {}
486+
AAQueryInfo(CaptureInfo *CI) : CI(CI) {}
443487

444488
/// Create a new AAQueryInfo based on this one, but with the cache cleared.
445489
/// This is used for recursive queries across phis, where cache results may
446490
/// not be valid.
447491
AAQueryInfo withEmptyCache() {
448-
AAQueryInfo NewAAQI;
492+
AAQueryInfo NewAAQI(CI);
449493
NewAAQI.Depth = Depth;
450494
return NewAAQI;
451495
}
452496
};
453497

498+
/// AAQueryInfo that uses SimpleCaptureInfo.
499+
class SimpleAAQueryInfo : public AAQueryInfo {
500+
SimpleCaptureInfo CI;
501+
502+
public:
503+
SimpleAAQueryInfo() : AAQueryInfo(&CI) {}
504+
};
505+
454506
class BatchAAResults;
455507

456508
class AAResults {
@@ -770,7 +822,7 @@ class AAResults {
770822
/// helpers above.
771823
ModRefInfo getModRefInfo(const Instruction *I,
772824
const Optional<MemoryLocation> &OptLoc) {
773-
AAQueryInfo AAQIP;
825+
SimpleAAQueryInfo AAQIP;
774826
return getModRefInfo(I, OptLoc, AAQIP);
775827
}
776828

@@ -797,7 +849,7 @@ class AAResults {
797849
ModRefInfo callCapturesBefore(const Instruction *I,
798850
const MemoryLocation &MemLoc,
799851
DominatorTree *DT) {
800-
AAQueryInfo AAQIP;
852+
SimpleAAQueryInfo AAQIP;
801853
return callCapturesBefore(I, MemLoc, DT, AAQIP);
802854
}
803855

@@ -896,9 +948,12 @@ class AAResults {
896948
class BatchAAResults {
897949
AAResults &AA;
898950
AAQueryInfo AAQI;
951+
SimpleCaptureInfo SimpleCI;
899952

900953
public:
901-
BatchAAResults(AAResults &AAR) : AA(AAR), AAQI() {}
954+
BatchAAResults(AAResults &AAR) : AA(AAR), AAQI(&SimpleCI) {}
955+
BatchAAResults(AAResults &AAR, CaptureInfo *CI) : AA(AAR), AAQI(CI) {}
956+
902957
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) {
903958
return AA.alias(LocA, LocB, AAQI);
904959
}

llvm/lib/Analysis/AliasAnalysis.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ bool AAResults::invalidate(Function &F, const PreservedAnalyses &PA,
119119

120120
AliasResult AAResults::alias(const MemoryLocation &LocA,
121121
const MemoryLocation &LocB) {
122-
AAQueryInfo AAQIP;
122+
SimpleAAQueryInfo AAQIP;
123123
return alias(LocA, LocB, AAQIP);
124124
}
125125

@@ -162,7 +162,7 @@ AliasResult AAResults::alias(const MemoryLocation &LocA,
162162

163163
bool AAResults::pointsToConstantMemory(const MemoryLocation &Loc,
164164
bool OrLocal) {
165-
AAQueryInfo AAQIP;
165+
SimpleAAQueryInfo AAQIP;
166166
return pointsToConstantMemory(Loc, AAQIP, OrLocal);
167167
}
168168

@@ -190,7 +190,7 @@ ModRefInfo AAResults::getArgModRefInfo(const CallBase *Call, unsigned ArgIdx) {
190190
}
191191

192192
ModRefInfo AAResults::getModRefInfo(Instruction *I, const CallBase *Call2) {
193-
AAQueryInfo AAQIP;
193+
SimpleAAQueryInfo AAQIP;
194194
return getModRefInfo(I, Call2, AAQIP);
195195
}
196196

@@ -217,7 +217,7 @@ ModRefInfo AAResults::getModRefInfo(Instruction *I, const CallBase *Call2,
217217

218218
ModRefInfo AAResults::getModRefInfo(const CallBase *Call,
219219
const MemoryLocation &Loc) {
220-
AAQueryInfo AAQIP;
220+
SimpleAAQueryInfo AAQIP;
221221
return getModRefInfo(Call, Loc, AAQIP);
222222
}
223223

@@ -284,7 +284,7 @@ ModRefInfo AAResults::getModRefInfo(const CallBase *Call,
284284

285285
ModRefInfo AAResults::getModRefInfo(const CallBase *Call1,
286286
const CallBase *Call2) {
287-
AAQueryInfo AAQIP;
287+
SimpleAAQueryInfo AAQIP;
288288
return getModRefInfo(Call1, Call2, AAQIP);
289289
}
290290

@@ -474,7 +474,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, AliasResult AR) {
474474

475475
ModRefInfo AAResults::getModRefInfo(const LoadInst *L,
476476
const MemoryLocation &Loc) {
477-
AAQueryInfo AAQIP;
477+
SimpleAAQueryInfo AAQIP;
478478
return getModRefInfo(L, Loc, AAQIP);
479479
}
480480
ModRefInfo AAResults::getModRefInfo(const LoadInst *L,
@@ -499,7 +499,7 @@ ModRefInfo AAResults::getModRefInfo(const LoadInst *L,
499499

500500
ModRefInfo AAResults::getModRefInfo(const StoreInst *S,
501501
const MemoryLocation &Loc) {
502-
AAQueryInfo AAQIP;
502+
SimpleAAQueryInfo AAQIP;
503503
return getModRefInfo(S, Loc, AAQIP);
504504
}
505505
ModRefInfo AAResults::getModRefInfo(const StoreInst *S,
@@ -531,7 +531,7 @@ ModRefInfo AAResults::getModRefInfo(const StoreInst *S,
531531
}
532532

533533
ModRefInfo AAResults::getModRefInfo(const FenceInst *S, const MemoryLocation &Loc) {
534-
AAQueryInfo AAQIP;
534+
SimpleAAQueryInfo AAQIP;
535535
return getModRefInfo(S, Loc, AAQIP);
536536
}
537537

@@ -547,7 +547,7 @@ ModRefInfo AAResults::getModRefInfo(const FenceInst *S,
547547

548548
ModRefInfo AAResults::getModRefInfo(const VAArgInst *V,
549549
const MemoryLocation &Loc) {
550-
AAQueryInfo AAQIP;
550+
SimpleAAQueryInfo AAQIP;
551551
return getModRefInfo(V, Loc, AAQIP);
552552
}
553553

@@ -577,7 +577,7 @@ ModRefInfo AAResults::getModRefInfo(const VAArgInst *V,
577577

578578
ModRefInfo AAResults::getModRefInfo(const CatchPadInst *CatchPad,
579579
const MemoryLocation &Loc) {
580-
AAQueryInfo AAQIP;
580+
SimpleAAQueryInfo AAQIP;
581581
return getModRefInfo(CatchPad, Loc, AAQIP);
582582
}
583583

@@ -597,7 +597,7 @@ ModRefInfo AAResults::getModRefInfo(const CatchPadInst *CatchPad,
597597

598598
ModRefInfo AAResults::getModRefInfo(const CatchReturnInst *CatchRet,
599599
const MemoryLocation &Loc) {
600-
AAQueryInfo AAQIP;
600+
SimpleAAQueryInfo AAQIP;
601601
return getModRefInfo(CatchRet, Loc, AAQIP);
602602
}
603603

@@ -617,7 +617,7 @@ ModRefInfo AAResults::getModRefInfo(const CatchReturnInst *CatchRet,
617617

618618
ModRefInfo AAResults::getModRefInfo(const AtomicCmpXchgInst *CX,
619619
const MemoryLocation &Loc) {
620-
AAQueryInfo AAQIP;
620+
SimpleAAQueryInfo AAQIP;
621621
return getModRefInfo(CX, Loc, AAQIP);
622622
}
623623

@@ -645,7 +645,7 @@ ModRefInfo AAResults::getModRefInfo(const AtomicCmpXchgInst *CX,
645645

646646
ModRefInfo AAResults::getModRefInfo(const AtomicRMWInst *RMW,
647647
const MemoryLocation &Loc) {
648-
AAQueryInfo AAQIP;
648+
SimpleAAQueryInfo AAQIP;
649649
return getModRefInfo(RMW, Loc, AAQIP);
650650
}
651651

llvm/lib/Analysis/BasicAliasAnalysis.cpp

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,51 @@ static bool isObjectSize(const Value *V, uint64_t Size, const DataLayout &DL,
223223
return ObjectSize != MemoryLocation::UnknownSize && ObjectSize == Size;
224224
}
225225

226+
//===----------------------------------------------------------------------===//
227+
// CaptureInfo implementations
228+
//===----------------------------------------------------------------------===//
229+
230+
CaptureInfo::~CaptureInfo() = default;
231+
232+
bool SimpleCaptureInfo::isNotCapturedBeforeOrAt(const Value *Object,
233+
const Instruction *I) {
234+
return isNonEscapingLocalObject(Object, &IsCapturedCache);
235+
}
236+
237+
bool EarliestEscapeInfo::isNotCapturedBeforeOrAt(const Value *Object,
238+
const Instruction *I) {
239+
if (!isIdentifiedFunctionLocal(Object))
240+
return false;
241+
242+
auto Iter = EarliestEscapes.insert({Object, nullptr});
243+
if (Iter.second) {
244+
Instruction *EarliestCapture = FindEarliestCapture(
245+
Object, *const_cast<Function *>(I->getFunction()),
246+
/*ReturnCaptures=*/false, /*StoreCaptures=*/true, DT);
247+
if (EarliestCapture) {
248+
auto Ins = Inst2Obj.insert({EarliestCapture, {}});
249+
Ins.first->second.push_back(Object);
250+
}
251+
Iter.first->second = EarliestCapture;
252+
}
253+
254+
// No capturing instruction.
255+
if (!Iter.first->second)
256+
return true;
257+
258+
return I != Iter.first->second &&
259+
!isPotentiallyReachable(Iter.first->second, I, nullptr, &DT, &LI);
260+
}
261+
262+
void EarliestEscapeInfo::removeInstruction(Instruction *I) {
263+
auto Iter = Inst2Obj.find(I);
264+
if (Iter != Inst2Obj.end()) {
265+
for (const Value *Obj : Iter->second)
266+
EarliestEscapes.erase(Obj);
267+
Inst2Obj.erase(I);
268+
}
269+
}
270+
226271
//===----------------------------------------------------------------------===//
227272
// GetElementPtr Instruction Decomposition and Analysis
228273
//===----------------------------------------------------------------------===//
@@ -835,7 +880,7 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
835880
// then the call can not mod/ref the pointer unless the call takes the pointer
836881
// as an argument, and itself doesn't capture it.
837882
if (!isa<Constant>(Object) && Call != Object &&
838-
isNonEscapingLocalObject(Object, &AAQI.IsCapturedCache)) {
883+
AAQI.CI->isNotCapturedBeforeOrAt(Object, Call)) {
839884

840885
// Optimistically assume that call doesn't touch Object and check this
841886
// assumption in the following loop.
@@ -1514,10 +1559,10 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, LocationSize V1Size,
15141559
// location if that memory location doesn't escape. Or it may pass a
15151560
// nocapture value to other functions as long as they don't capture it.
15161561
if (isEscapeSource(O1) &&
1517-
isNonEscapingLocalObject(O2, &AAQI.IsCapturedCache))
1562+
AAQI.CI->isNotCapturedBeforeOrAt(O2, cast<Instruction>(O1)))
15181563
return AliasResult::NoAlias;
15191564
if (isEscapeSource(O2) &&
1520-
isNonEscapingLocalObject(O1, &AAQI.IsCapturedCache))
1565+
AAQI.CI->isNotCapturedBeforeOrAt(O1, cast<Instruction>(O2)))
15211566
return AliasResult::NoAlias;
15221567
}
15231568

0 commit comments

Comments
 (0)