diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-11-22 18:23:53 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2021-01-06 22:15:30 +0100 |
commit | f6f6f6375d1a4bced8a6e79a78726ab32b8dd879 (patch) | |
tree | c6bfae3da01c535024c19ce9051bfac66aed839e /llvm/lib/Analysis/BasicAliasAnalysis.cpp | |
parent | 0e874fc014be818a9c6782729f2c8e8273a7a906 (diff) | |
download | llvm-f6f6f6375d1a4bced8a6e79a78726ab32b8dd879.zip llvm-f6f6f6375d1a4bced8a6e79a78726ab32b8dd879.tar.gz llvm-f6f6f6375d1a4bced8a6e79a78726ab32b8dd879.tar.bz2 |
[BasicAA] Fix BatchAA results for phi-phi assumptions
Change the way NoAlias assumptions in BasicAA are handled. Instead of
handling this inside the phi-phi code, always initially insert a
NoAlias result into the map and keep track whether it is used.
If it is used, then we require that we also get back NoAlias from
the recursive queries. Otherwise, the entry is changed to MayAlias.
Additionally, keep track of all location pairs we inserted that may
still be based on assumptions higher up. If it turns out one of those
assumptions is incorrect, we flush them from the cache.
The compile-time impact for the new implementation is significantly
higher than the previous iteration of this patch:
https://llvm-compile-time-tracker.com/compare.php?from=c0bb9859de6991cc233e2dedb978dd118da8c382&to=c07112373279143e37568b5bcd293daf81a35973&stat=instructions
However, it should avoid the exponential runtime cases we run into
if we don't cache assumption-based results entirely.
This also produces better results in some cases, because NoAlias
assumptions can now start at any root, rather than just phi-phi pairs.
This is not just relevant for analysis quality, but also for BatchAA
consistency: Otherwise, results would once again depend on query order,
though at least they wouldn't be wrong.
This ended up both more complicated and more expensive than I hoped,
but I wasn't able to come up with another solution that satisfies all
the constraints.
Differential Revision: https://reviews.llvm.org/D91936
Diffstat (limited to 'llvm/lib/Analysis/BasicAliasAnalysis.cpp')
-rw-r--r-- | llvm/lib/Analysis/BasicAliasAnalysis.cpp | 122 |
1 files changed, 73 insertions, 49 deletions
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp index f9275da..1440906 100644 --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -806,8 +806,12 @@ AliasResult BasicAAResult::alias(const MemoryLocation &LocA, if (Locs.first.Ptr > Locs.second.Ptr) std::swap(Locs.first, Locs.second); auto CacheIt = AAQI.AliasCache.find(Locs); - if (CacheIt != AAQI.AliasCache.end()) - return CacheIt->second; + if (CacheIt != AAQI.AliasCache.end()) { + // This code exists to skip a second BasicAA call while recursing into + // BestAA. Don't make use of assumptions here. + const auto &Entry = CacheIt->second; + return Entry.isDefinitive() ? Entry.Result : MayAlias; + } AliasResult Alias = aliasCheck(LocA.Ptr, LocA.Size, LocA.AATags, LocB.Ptr, LocB.Size, LocB.AATags, AAQI); @@ -1376,42 +1380,20 @@ AliasResult BasicAAResult::aliasPHI(const PHINode *PN, LocationSize PNSize, // on corresponding edges. if (const PHINode *PN2 = dyn_cast<PHINode>(V2)) if (PN2->getParent() == PN->getParent()) { - AAQueryInfo::LocPair Locs(MemoryLocation(PN, PNSize, PNAAInfo), - MemoryLocation(V2, V2Size, V2AAInfo)); - if (PN > V2) - std::swap(Locs.first, Locs.second); - // Analyse the PHIs' inputs under the assumption that the PHIs are - // NoAlias. - // If the PHIs are May/MustAlias there must be (recursively) an input - // operand from outside the PHIs' cycle that is MayAlias/MustAlias or - // there must be an operation on the PHIs within the PHIs' value cycle - // that causes a MayAlias. - // Pretend the phis do not alias. - AliasResult Alias = NoAlias; - AliasResult OrigAliasResult; - { - // Limited lifetime iterator invalidated by the aliasCheck call below. - auto CacheIt = AAQI.AliasCache.find(Locs); - assert((CacheIt != AAQI.AliasCache.end()) && - "There must exist an entry for the phi node"); - OrigAliasResult = CacheIt->second; - CacheIt->second = NoAlias; - } - + Optional<AliasResult> Alias; for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { AliasResult ThisAlias = aliasCheck(PN->getIncomingValue(i), PNSize, PNAAInfo, PN2->getIncomingValueForBlock(PN->getIncomingBlock(i)), V2Size, V2AAInfo, AAQI); - Alias = MergeAliasResults(ThisAlias, Alias); - if (Alias == MayAlias) + if (Alias) + *Alias = MergeAliasResults(*Alias, ThisAlias); + else + Alias = ThisAlias; + if (*Alias == MayAlias) break; } - - // Reset if speculation failed. - if (Alias != NoAlias) - AAQI.updateResult(Locs, OrigAliasResult); - return Alias; + return *Alias; } SmallVector<Value *, 4> V1Srcs; @@ -1630,64 +1612,106 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, LocationSize V1Size, MemoryLocation(V2, V2Size, V2AAInfo)); if (V1 > V2) std::swap(Locs.first, Locs.second); - std::pair<AAQueryInfo::AliasCacheT::iterator, bool> Pair = - AAQI.AliasCache.try_emplace(Locs, MayAlias); - if (!Pair.second) - return Pair.first->second; + const auto &Pair = AAQI.AliasCache.try_emplace( + Locs, AAQueryInfo::CacheEntry{NoAlias, 0}); + if (!Pair.second) { + auto &Entry = Pair.first->second; + if (!Entry.isDefinitive()) { + // Remember that we used an assumption. + ++Entry.NumAssumptionUses; + ++NumAssumptionUses; + } + return Entry.Result; + } + int OrigNumAssumptionUses = NumAssumptionUses; + unsigned OrigNumAssumptionBasedResults = AssumptionBasedResults.size(); + AliasResult Result = aliasCheckRecursive(V1, V1Size, V1AAInfo, V2, V2Size, + V2AAInfo, AAQI, O1, O2); + + auto It = AAQI.AliasCache.find(Locs); + assert(It != AAQI.AliasCache.end() && "Must be in cache"); + auto &Entry = It->second; + + // Check whether a NoAlias assumption has been used, but disproven. + bool AssumptionDisproven = Entry.NumAssumptionUses > 0 && Result != NoAlias; + if (AssumptionDisproven) + Result = MayAlias; + + // This is a definitive result now, when considered as a root query. + NumAssumptionUses -= Entry.NumAssumptionUses; + Entry.Result = Result; + Entry.NumAssumptionUses = -1; + + // If the assumption has been disproven, remove any results that may have + // been based on this assumption. Do this after the Entry updates above to + // avoid iterator invalidation. + if (AssumptionDisproven) + while (AssumptionBasedResults.size() > OrigNumAssumptionBasedResults) + AAQI.AliasCache.erase(AssumptionBasedResults.pop_back_val()); + + // The result may still be based on assumptions higher up in the chain. + // Remember it, so it can be purged from the cache later. + if (OrigNumAssumptionUses != NumAssumptionUses && Result != MayAlias) + AssumptionBasedResults.push_back(Locs); + return Result; +} + +AliasResult BasicAAResult::aliasCheckRecursive( + const Value *V1, LocationSize V1Size, const AAMDNodes &V1AAInfo, + const Value *V2, LocationSize V2Size, const AAMDNodes &V2AAInfo, + AAQueryInfo &AAQI, const Value *O1, const Value *O2) { if (const GEPOperator *GV1 = dyn_cast<GEPOperator>(V1)) { AliasResult Result = aliasGEP(GV1, V1Size, V1AAInfo, V2, V2Size, V2AAInfo, O1, O2, AAQI); if (Result != MayAlias) - return AAQI.updateResult(Locs, Result); + return Result; } else if (const GEPOperator *GV2 = dyn_cast<GEPOperator>(V2)) { AliasResult Result = aliasGEP(GV2, V2Size, V2AAInfo, V1, V1Size, V1AAInfo, O2, O1, AAQI); if (Result != MayAlias) - return AAQI.updateResult(Locs, Result); + return Result; } if (const PHINode *PN = dyn_cast<PHINode>(V1)) { AliasResult Result = aliasPHI(PN, V1Size, V1AAInfo, V2, V2Size, V2AAInfo, O2, AAQI); if (Result != MayAlias) - return AAQI.updateResult(Locs, Result); + return Result; } else if (const PHINode *PN = dyn_cast<PHINode>(V2)) { AliasResult Result = aliasPHI(PN, V2Size, V2AAInfo, V1, V1Size, V1AAInfo, O1, AAQI); if (Result != MayAlias) - return AAQI.updateResult(Locs, Result); + return Result; } if (const SelectInst *S1 = dyn_cast<SelectInst>(V1)) { AliasResult Result = aliasSelect(S1, V1Size, V1AAInfo, V2, V2Size, V2AAInfo, O2, AAQI); if (Result != MayAlias) - return AAQI.updateResult(Locs, Result); + return Result; } else if (const SelectInst *S2 = dyn_cast<SelectInst>(V2)) { AliasResult Result = aliasSelect(S2, V2Size, V2AAInfo, V1, V1Size, V1AAInfo, O1, AAQI); if (Result != MayAlias) - return AAQI.updateResult(Locs, Result); + return Result; } // If both pointers are pointing into the same object and one of them // accesses the entire object, then the accesses must overlap in some way. - if (O1 == O2) + if (O1 == O2) { + bool NullIsValidLocation = NullPointerIsDefined(&F); if (V1Size.isPrecise() && V2Size.isPrecise() && (isObjectSize(O1, V1Size.getValue(), DL, TLI, NullIsValidLocation) || isObjectSize(O2, V2Size.getValue(), DL, TLI, NullIsValidLocation))) - return AAQI.updateResult(Locs, PartialAlias); + return PartialAlias; + } // Recurse back into the best AA results we have, potentially with refined // memory locations. We have already ensured that BasicAA has a MayAlias // cache result for these, so any recursion back into BasicAA won't loop. - AliasResult Result = getBestAAResults().alias(Locs.first, Locs.second, AAQI); - if (Result != MayAlias) - return AAQI.updateResult(Locs, Result); - - // MayAlias is already in the cache. - return MayAlias; + return getBestAAResults().alias(MemoryLocation(V1, V1Size, V1AAInfo), + MemoryLocation(V2, V2Size, V2AAInfo), AAQI); } /// Check whether two Values can be considered equivalent. |