diff options
author | Nikita Popov <npopov@redhat.com> | 2025-06-12 14:13:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-06-12 14:13:15 +0200 |
commit | bc7fafbeea08bf8cd9a18fa10d3d3bc63f0c45a3 (patch) | |
tree | 82a91f05642bfb051c09b98024e4d05f8296946b /llvm/lib/Analysis/BasicAliasAnalysis.cpp | |
parent | 2ecbfc0beb42abbbd2c3d28bfd576b38c44a5b46 (diff) | |
download | llvm-bc7fafbeea08bf8cd9a18fa10d3d3bc63f0c45a3.zip llvm-bc7fafbeea08bf8cd9a18fa10d3d3bc63f0c45a3.tar.gz llvm-bc7fafbeea08bf8cd9a18fa10d3d3bc63f0c45a3.tar.bz2 |
[AA] Take read-only provenance captures into account (#143097)
Update the AA CaptureAnalysis providers to return CaptureComponents, so
we can distinguish between full provenance and read-only provenance
captures.
Use this to restrict "other" memory effects on call from ModRef to Ref.
Ideally we would also apply the same reasoning for escape sources, but
the current API cannot actually convey the necessary information (we can
only say NoAlias or MayAlias, not MayAlias but only via Ref).
Diffstat (limited to 'llvm/lib/Analysis/BasicAliasAnalysis.cpp')
-rw-r--r-- | llvm/lib/Analysis/BasicAliasAnalysis.cpp | 86 |
1 files changed, 51 insertions, 35 deletions
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp index f862d69..31611df 100644 --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -192,18 +192,20 @@ static bool areBothVScale(const Value *V1, const Value *V2) { CaptureAnalysis::~CaptureAnalysis() = default; -bool SimpleCaptureAnalysis::isNotCapturedBefore(const Value *Object, - const Instruction *I, - bool OrAt) { +CaptureComponents SimpleCaptureAnalysis::getCapturesBefore(const Value *Object, + const Instruction *I, + bool OrAt) { if (!isIdentifiedFunctionLocal(Object)) - return false; + return CaptureComponents::Provenance; - auto [CacheIt, Inserted] = IsCapturedCache.insert({Object, false}); + auto [CacheIt, Inserted] = + IsCapturedCache.insert({Object, CaptureComponents::Provenance}); if (!Inserted) return CacheIt->second; - bool Ret = !capturesAnything(PointerMayBeCaptured( - Object, /*ReturnCaptures=*/false, CaptureComponents::Provenance)); + CaptureComponents Ret = PointerMayBeCaptured( + Object, /*ReturnCaptures=*/false, CaptureComponents::Provenance, + [](CaptureComponents CC) { return capturesFullProvenance(CC); }); CacheIt->second = Ret; return Ret; } @@ -216,37 +218,44 @@ static bool isNotInCycle(const Instruction *I, const DominatorTree *DT, !isPotentiallyReachableFromMany(Succs, BB, nullptr, DT, LI); } -bool EarliestEscapeAnalysis::isNotCapturedBefore(const Value *Object, - const Instruction *I, - bool OrAt) { +CaptureComponents +EarliestEscapeAnalysis::getCapturesBefore(const Value *Object, + const Instruction *I, bool OrAt) { if (!isIdentifiedFunctionLocal(Object)) - return false; + return CaptureComponents::Provenance; auto Iter = EarliestEscapes.try_emplace(Object); if (Iter.second) { - Instruction *EarliestCapture = FindEarliestCapture( - Object, *const_cast<Function *>(DT.getRoot()->getParent()), - /*ReturnCaptures=*/false, DT, CaptureComponents::Provenance); - if (EarliestCapture) - Inst2Obj[EarliestCapture].push_back(Object); + std::pair<Instruction *, CaptureComponents> EarliestCapture = + FindEarliestCapture( + Object, *const_cast<Function *>(DT.getRoot()->getParent()), + /*ReturnCaptures=*/false, DT, CaptureComponents::Provenance); + if (EarliestCapture.first) + Inst2Obj[EarliestCapture.first].push_back(Object); Iter.first->second = EarliestCapture; } - // No capturing instruction. - if (!Iter.first->second) - return true; - - // No context instruction means any use is capturing. - if (!I) - return false; + auto IsNotCapturedBefore = [&]() { + // No capturing instruction. + Instruction *CaptureInst = Iter.first->second.first; + if (!CaptureInst) + return true; - if (I == Iter.first->second) { - if (OrAt) + // No context instruction means any use is capturing. + if (!I) return false; - return isNotInCycle(I, &DT, LI); - } - return !isPotentiallyReachable(Iter.first->second, I, nullptr, &DT, LI); + if (I == CaptureInst) { + if (OrAt) + return false; + return isNotInCycle(I, &DT, LI); + } + + return !isPotentiallyReachable(CaptureInst, I, nullptr, &DT, LI); + }; + if (IsNotCapturedBefore()) + return CaptureComponents::None; + return Iter.first->second.second; } void EarliestEscapeAnalysis::removeInstruction(Instruction *I) { @@ -946,9 +955,14 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call, // As an exception, ignore allocas, as setjmp is not required to preserve // non-volatile stores for them. if (isModOrRefSet(OtherMR) && !isa<Constant>(Object) && Call != Object && - AAQI.CA->isNotCapturedBefore(Object, Call, /*OrAt=*/false) && - (isa<AllocaInst>(Object) || !Call->hasFnAttr(Attribute::ReturnsTwice))) - OtherMR = ModRefInfo::NoModRef; + (isa<AllocaInst>(Object) || !Call->hasFnAttr(Attribute::ReturnsTwice))) { + CaptureComponents CC = + AAQI.CA->getCapturesBefore(Object, Call, /*OrAt=*/false); + if (capturesNothing(CC)) + OtherMR = ModRefInfo::NoModRef; + else if (capturesReadProvenanceOnly(CC)) + OtherMR = ModRefInfo::Ref; + } // Refine the modref info for argument memory. We only bother to do this // if ArgMR is not a subset of OtherMR, otherwise this won't have an impact @@ -1614,11 +1628,13 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, LocationSize V1Size, // temporary store the nocapture argument's value in a temporary memory // location if that memory location doesn't escape. Or it may pass a // nocapture value to other functions as long as they don't capture it. - if (isEscapeSource(O1) && AAQI.CA->isNotCapturedBefore( - O2, dyn_cast<Instruction>(O1), /*OrAt*/ true)) + if (isEscapeSource(O1) && + capturesNothing(AAQI.CA->getCapturesBefore( + O2, dyn_cast<Instruction>(O1), /*OrAt*/ true))) return AliasResult::NoAlias; - if (isEscapeSource(O2) && AAQI.CA->isNotCapturedBefore( - O1, dyn_cast<Instruction>(O2), /*OrAt*/ true)) + if (isEscapeSource(O2) && + capturesNothing(AAQI.CA->getCapturesBefore( + O1, dyn_cast<Instruction>(O2), /*OrAt*/ true))) return AliasResult::NoAlias; } |