[llvm] [CaptureTracking] Compute results with and without return capture (PR #195857)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Thu May 7 06:04:29 PDT 2026
https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/195857
>From a37046c0803c4cbec27dceabb96507e7bca7d84c Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 5 May 2026 14:49:47 +0200
Subject: [PATCH 1/2] [CaptureTracking] Compute results with and without return
capture
Currently PointerMayBeCaptured/FindEarliestEscape accept a
ReturnCaptures argument to determine whether returning the pointer
should be considered a capture. If you want to do a capture check
for both cases, you have to invoke the capture tracking API twice.
This PR instead changes the low level APIs to return a pair of
capture components, one where returns are considered non-capturing,
and one where they are considered capturing.
---
llvm/include/llvm/Analysis/CaptureTracking.h | 19 +++--
llvm/lib/Analysis/BasicAliasAnalysis.cpp | 16 ++--
llvm/lib/Analysis/CaptureTracking.cpp | 73 ++++++++++---------
.../Scalar/DeadStoreElimination.cpp | 8 +-
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 4 +-
5 files changed, 65 insertions(+), 55 deletions(-)
diff --git a/llvm/include/llvm/Analysis/CaptureTracking.h b/llvm/include/llvm/Analysis/CaptureTracking.h
index e652bc5a0a5a6..ca9d1c53de3ef 100644
--- a/llvm/include/llvm/Analysis/CaptureTracking.h
+++ b/llvm/include/llvm/Analysis/CaptureTracking.h
@@ -48,6 +48,14 @@ namespace llvm {
LLVM_ABI bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures,
unsigned MaxUsesToExplore = 0);
+ /// Result of a PointerMayBeCaptured query, which includes the captured
+ /// components for both the case where return is considered a capture, and
+ /// where it isn't.
+ struct CaptureResult {
+ CaptureComponents WithoutRet;
+ CaptureComponents WithRet;
+ };
+
/// Return which components of the pointer may be captured. Only consider
/// components that are part of \p Mask. Once \p StopFn on the accumulated
/// components returns true, the traversal is aborted early. By default, this
@@ -55,8 +63,8 @@ namespace llvm {
/// This function only considers captures of the passed value via its def-use
/// chain, without considering captures of values it may be based on, or
/// implicit captures such as for external globals.
- LLVM_ABI CaptureComponents PointerMayBeCaptured(
- const Value *V, bool ReturnCaptures, CaptureComponents Mask,
+ LLVM_ABI CaptureResult PointerMayBeCaptured(
+ const Value *V, CaptureComponents Mask,
function_ref<bool(CaptureComponents)> StopFn = capturesAnything,
unsigned MaxUsesToExplore = 0);
@@ -106,10 +114,9 @@ namespace llvm {
// not in a cycle.
//
// Only consider components that are part of \p Mask.
- LLVM_ABI std::pair<Instruction *, CaptureComponents>
- FindEarliestCapture(const Value *V, Function &F, bool ReturnCaptures,
- const DominatorTree &DT, CaptureComponents Mask,
- unsigned MaxUsesToExplore = 0);
+ LLVM_ABI std::pair<Instruction *, CaptureResult>
+ FindEarliestCapture(const Value *V, Function &F, const DominatorTree &DT,
+ CaptureComponents Mask, unsigned MaxUsesToExplore = 0);
/// Capture information for a specific Use.
struct UseCaptureInfo {
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 8172cf29d890b..65ffa34eeb923 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -208,9 +208,11 @@ CaptureComponents SimpleCaptureAnalysis::getCapturesBefore(const Value *Object,
if (!Inserted)
return CacheIt->second;
- CaptureComponents Ret = PointerMayBeCaptured(
- Object, /*ReturnCaptures=*/false, CaptureComponents::Provenance,
- [](CaptureComponents CC) { return capturesFullProvenance(CC); });
+ CaptureComponents Ret =
+ PointerMayBeCaptured(
+ Object, CaptureComponents::Provenance,
+ [](CaptureComponents CC) { return capturesFullProvenance(CC); })
+ .WithoutRet;
CacheIt->second = Ret;
return Ret;
}
@@ -234,13 +236,13 @@ EarliestEscapeAnalysis::getCapturesBefore(const Value *Object,
auto Iter = EarliestEscapes.try_emplace(Object);
if (Iter.second) {
- std::pair<Instruction *, CaptureComponents> EarliestCapture =
- FindEarliestCapture(Object, *DT.getRoot()->getParent(),
- /*ReturnCaptures=*/false, DT,
+ std::pair<Instruction *, CaptureResult> EarliestCapture =
+ FindEarliestCapture(Object, *DT.getRoot()->getParent(), DT,
CaptureComponents::Provenance);
if (EarliestCapture.first)
Inst2Obj[EarliestCapture.first].push_back(Object);
- Iter.first->second = EarliestCapture;
+ Iter.first->second = {EarliestCapture.first,
+ EarliestCapture.second.WithoutRet};
}
auto IsNotCapturedBefore = [&]() {
diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp
index 22229d9c26b3b..c34fde8d11704 100644
--- a/llvm/lib/Analysis/CaptureTracking.cpp
+++ b/llvm/lib/Analysis/CaptureTracking.cpp
@@ -57,32 +57,32 @@ bool CaptureTracker::shouldExplore(const Use *U) { return true; }
namespace {
struct SimpleCaptureTracker : public CaptureTracker {
- explicit SimpleCaptureTracker(bool ReturnCaptures, CaptureComponents Mask,
+ explicit SimpleCaptureTracker(CaptureComponents Mask,
function_ref<bool(CaptureComponents)> StopFn)
- : ReturnCaptures(ReturnCaptures), Mask(Mask), StopFn(StopFn) {}
+ : Mask(Mask), StopFn(StopFn) {}
void tooManyUses() override {
LLVM_DEBUG(dbgs() << "Captured due to too many uses\n");
CC = Mask;
+ CCWithRet = Mask;
}
Action captured(const Use *U, UseCaptureInfo CI) override {
- if (isa<ReturnInst>(U->getUser()) && !ReturnCaptures)
- return ContinueIgnoringReturn;
-
if (capturesNothing(CI.UseCC & Mask))
return Continue;
LLVM_DEBUG(dbgs() << "Captured by: " << *U->getUser() << "\n");
- CC |= CI.UseCC & Mask;
+ CCWithRet |= CI.UseCC & Mask;
+ if (!isa<ReturnInst>(U->getUser()))
+ CC |= CI.UseCC & Mask;
return StopFn(CC) ? Stop : Continue;
}
- bool ReturnCaptures;
CaptureComponents Mask;
function_ref<bool(CaptureComponents)> StopFn;
CaptureComponents CC = CaptureComponents::None;
+ CaptureComponents CCWithRet = CaptureComponents::None;
};
/// Only find pointer captures which happen before the given instruction. Uses
@@ -155,26 +155,26 @@ struct CapturesBefore : public CaptureTracker {
// escape are not in a cycle.
struct EarliestCaptures : public CaptureTracker {
- EarliestCaptures(bool ReturnCaptures, Function &F, const DominatorTree &DT,
- CaptureComponents Mask)
- : DT(DT), ReturnCaptures(ReturnCaptures), F(F), Mask(Mask) {}
+ EarliestCaptures(Function &F, const DominatorTree &DT, CaptureComponents Mask)
+ : DT(DT), F(F), Mask(Mask) {}
void tooManyUses() override {
CC = Mask;
+ CCWithRet = Mask;
EarliestCapture = &*F.getEntryBlock().begin();
}
Action captured(const Use *U, UseCaptureInfo CI) override {
Instruction *I = cast<Instruction>(U->getUser());
- if (isa<ReturnInst>(I) && !ReturnCaptures)
- return ContinueIgnoringReturn;
-
if (capturesAnything(CI.UseCC & Mask)) {
- if (!EarliestCapture)
- EarliestCapture = I;
- else
- EarliestCapture = DT.findNearestCommonDominator(EarliestCapture, I);
- CC |= CI.UseCC & Mask;
+ CCWithRet |= CI.UseCC & Mask;
+ if (!isa<ReturnInst>(I)) {
+ if (!EarliestCapture)
+ EarliestCapture = I;
+ else
+ EarliestCapture = DT.findNearestCommonDominator(EarliestCapture, I);
+ CC |= CI.UseCC & Mask;
+ }
}
// Continue analysis, as we need to see all potential captures.
@@ -182,24 +182,25 @@ struct EarliestCaptures : public CaptureTracker {
}
const DominatorTree &DT;
- bool ReturnCaptures;
Function &F;
CaptureComponents Mask;
Instruction *EarliestCapture = nullptr;
CaptureComponents CC = CaptureComponents::None;
+ CaptureComponents CCWithRet = CaptureComponents::None;
};
} // namespace
-CaptureComponents llvm::PointerMayBeCaptured(
- const Value *V, bool ReturnCaptures, CaptureComponents Mask,
- function_ref<bool(CaptureComponents)> StopFn, unsigned MaxUsesToExplore) {
+CaptureResult
+llvm::PointerMayBeCaptured(const Value *V, CaptureComponents Mask,
+ function_ref<bool(CaptureComponents)> StopFn,
+ unsigned MaxUsesToExplore) {
assert(!isa<GlobalValue>(V) &&
"It doesn't make sense to ask whether a global is captured.");
LLVM_DEBUG(dbgs() << "Captured?: " << *V << " = ");
- SimpleCaptureTracker SCT(ReturnCaptures, Mask, StopFn);
+ SimpleCaptureTracker SCT(Mask, StopFn);
PointerMayBeCaptured(V, &SCT, MaxUsesToExplore);
if (capturesAnything(SCT.CC))
++NumCaptured;
@@ -207,14 +208,14 @@ CaptureComponents llvm::PointerMayBeCaptured(
++NumNotCaptured;
LLVM_DEBUG(dbgs() << "not captured\n");
}
- return SCT.CC;
+ return {SCT.CC, SCT.CCWithRet};
}
bool llvm::PointerMayBeCaptured(const Value *V, bool ReturnCaptures,
unsigned MaxUsesToExplore) {
- return capturesAnything(
- PointerMayBeCaptured(V, ReturnCaptures, CaptureComponents::All,
- capturesAnything, MaxUsesToExplore));
+ CaptureResult Res = PointerMayBeCaptured(V, CaptureComponents::All,
+ capturesAnything, MaxUsesToExplore);
+ return capturesAnything(ReturnCaptures ? Res.WithRet : Res.WithoutRet);
}
CaptureComponents llvm::PointerMayBeCapturedBefore(
@@ -225,9 +226,10 @@ CaptureComponents llvm::PointerMayBeCapturedBefore(
assert(!isa<GlobalValue>(V) &&
"It doesn't make sense to ask whether a global is captured.");
- if (!DT)
- return PointerMayBeCaptured(V, ReturnCaptures, Mask, StopFn,
- MaxUsesToExplore);
+ if (!DT) {
+ CaptureResult Res = PointerMayBeCaptured(V, Mask, StopFn, MaxUsesToExplore);
+ return ReturnCaptures ? Res.WithRet : Res.WithoutRet;
+ }
CapturesBefore CB(ReturnCaptures, I, DT, IncludeI, LI, Mask, StopFn);
PointerMayBeCaptured(V, &CB, MaxUsesToExplore);
@@ -248,20 +250,19 @@ bool llvm::PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
capturesAnything, LI, MaxUsesToExplore));
}
-std::pair<Instruction *, CaptureComponents>
-llvm::FindEarliestCapture(const Value *V, Function &F, bool ReturnCaptures,
- const DominatorTree &DT, CaptureComponents Mask,
- unsigned MaxUsesToExplore) {
+std::pair<Instruction *, CaptureResult>
+llvm::FindEarliestCapture(const Value *V, Function &F, const DominatorTree &DT,
+ CaptureComponents Mask, unsigned MaxUsesToExplore) {
assert(!isa<GlobalValue>(V) &&
"It doesn't make sense to ask whether a global is captured.");
- EarliestCaptures CB(ReturnCaptures, F, DT, Mask);
+ EarliestCaptures CB(F, DT, Mask);
PointerMayBeCaptured(V, &CB, MaxUsesToExplore);
if (capturesAnything(CB.CC))
++NumCapturedBefore;
else
++NumNotCapturedBefore;
- return {CB.EarliestCapture, CB.CC};
+ return {CB.EarliestCapture, {CB.CC, CB.CCWithRet}};
}
UseCaptureInfo llvm::DetermineUseCaptureKind(const Use &U, const Value *Base) {
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 6704fd0ef86e0..056f844b3805a 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -1396,8 +1396,8 @@ bool DSEState::isInvisibleToCallerAfterRet(const Value *V, const Value *Ptr,
}
auto I = InvisibleToCallerAfterRet.insert({V, false});
if (I.second && isInvisibleToCallerOnUnwind(V) && isNoAliasCall(V))
- I.first->second = capturesNothing(PointerMayBeCaptured(
- V, /*ReturnCaptures=*/true, CaptureComponents::Provenance));
+ I.first->second = capturesNothing(
+ PointerMayBeCaptured(V, CaptureComponents::Provenance).WithRet);
return I.first->second;
}
@@ -1414,8 +1414,8 @@ bool DSEState::isInvisibleToCallerOnUnwind(const Value *V) {
// with the killing MemoryDef. But we refrain from doing so for now to
// limit compile-time and this does not cause any changes to the number
// of stores removed on a large test set in practice.
- I.first->second = capturesAnything(PointerMayBeCaptured(
- V, /*ReturnCaptures=*/false, CaptureComponents::Provenance));
+ I.first->second = capturesAnything(
+ PointerMayBeCaptured(V, CaptureComponents::Provenance).WithoutRet);
return !I.first->second;
}
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 5bfd06affdb1f..3a98e86038904 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -3070,8 +3070,8 @@ static Value *isSafeToSpeculateStore(Instruction *I, BasicBlock *BrBB,
bool ExplicitlyDereferenceableOnly;
if (isWritableObject(Obj, ExplicitlyDereferenceableOnly) &&
capturesNothing(
- PointerMayBeCaptured(Obj, /*ReturnCaptures=*/false,
- CaptureComponents::Provenance)) &&
+ PointerMayBeCaptured(Obj, CaptureComponents::Provenance)
+ .WithoutRet) &&
(!ExplicitlyDereferenceableOnly ||
isDereferenceablePointer(StorePtr, StoreTy,
LI->getDataLayout()))) {
>From cc9c5b7d922005b64830745fc31bb31bd5cdcc49 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Thu, 7 May 2026 14:59:10 +0200
Subject: [PATCH 2/2] Implement ReturnCaptures support in CaptureAnalysis
---
llvm/include/llvm/Analysis/AliasAnalysis.h | 14 +++--
llvm/lib/Analysis/BasicAliasAnalysis.cpp | 55 +++++++++----------
.../Scalar/DeadStoreElimination.cpp | 4 +-
3 files changed, 36 insertions(+), 37 deletions(-)
diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h
index 845ccdbfce776..23fa20f17d92f 100644
--- a/llvm/include/llvm/Analysis/AliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/AliasAnalysis.h
@@ -39,6 +39,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/PassManager.h"
@@ -155,19 +156,20 @@ struct LLVM_ABI CaptureAnalysis {
/// are also considered.
///
/// If I is nullptr, then captures at any point will be considered.
- virtual CaptureComponents
- getCapturesBefore(const Value *Object, const Instruction *I, bool OrAt) = 0;
+ virtual CaptureComponents getCapturesBefore(const Value *Object,
+ const Instruction *I, bool OrAt,
+ bool ReturnCaptures) = 0;
};
/// Context-free CaptureAnalysis provider, which computes and caches whether an
/// object is captured in the function at all, but does not distinguish whether
/// it was captured before or after the context instruction.
class LLVM_ABI SimpleCaptureAnalysis final : public CaptureAnalysis {
- SmallDenseMap<const Value *, CaptureComponents, 8> IsCapturedCache;
+ SmallDenseMap<const Value *, CaptureResult, 8> IsCapturedCache;
public:
CaptureComponents getCapturesBefore(const Value *Object, const Instruction *I,
- bool OrAt) override;
+ bool OrAt, bool ReturnCaptures) override;
};
/// Context-sensitive CaptureAnalysis provider, which computes and caches the
@@ -183,7 +185,7 @@ class LLVM_ABI EarliestEscapeAnalysis final : public CaptureAnalysis {
/// that may be captured (by any instruction, not necessarily the earliest
/// one). The "earliest" instruction may be a conservative approximation,
/// e.g. the first instruction in the function is always a legal choice.
- DenseMap<const Value *, std::pair<Instruction *, CaptureComponents>>
+ DenseMap<const Value *, std::pair<Instruction *, CaptureResult>>
EarliestEscapes;
/// Reverse map from instruction to the objects it is the earliest escape for.
@@ -196,7 +198,7 @@ class LLVM_ABI EarliestEscapeAnalysis final : public CaptureAnalysis {
: DT(DT), LI(LI), CI(CI) {}
CaptureComponents getCapturesBefore(const Value *Object, const Instruction *I,
- bool OrAt) override;
+ bool OrAt, bool ReturnCaptures) override;
void removeInstruction(Instruction *I);
};
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 65ffa34eeb923..41c5df99afa5d 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -197,24 +197,18 @@ static bool areBothVScale(const Value *V1, const Value *V2) {
CaptureAnalysis::~CaptureAnalysis() = default;
-CaptureComponents SimpleCaptureAnalysis::getCapturesBefore(const Value *Object,
- const Instruction *I,
- bool OrAt) {
+CaptureComponents SimpleCaptureAnalysis::getCapturesBefore(
+ const Value *Object, const Instruction *I, bool OrAt, bool ReturnCaptures) {
if (!isIdentifiedFunctionLocal(Object))
return CaptureComponents::Provenance;
- auto [CacheIt, Inserted] =
- IsCapturedCache.insert({Object, CaptureComponents::Provenance});
- if (!Inserted)
- return CacheIt->second;
-
- CaptureComponents Ret =
- PointerMayBeCaptured(
- Object, CaptureComponents::Provenance,
- [](CaptureComponents CC) { return capturesFullProvenance(CC); })
- .WithoutRet;
- CacheIt->second = Ret;
- return Ret;
+ auto [CacheIt, Inserted] = IsCapturedCache.try_emplace(Object);
+ if (Inserted)
+ CacheIt->second = PointerMayBeCaptured(
+ Object, CaptureComponents::Provenance,
+ [](CaptureComponents CC) { return capturesFullProvenance(CC); });
+
+ return ReturnCaptures ? CacheIt->second.WithRet : CacheIt->second.WithoutRet;
}
static bool isNotInCycle(const Instruction *I, const DominatorTree *DT,
@@ -228,9 +222,8 @@ static bool isNotInCycle(const Instruction *I, const DominatorTree *DT,
!isPotentiallyReachableFromMany(Succs, BB, nullptr, DT, LI);
}
-CaptureComponents
-EarliestEscapeAnalysis::getCapturesBefore(const Value *Object,
- const Instruction *I, bool OrAt) {
+CaptureComponents EarliestEscapeAnalysis::getCapturesBefore(
+ const Value *Object, const Instruction *I, bool OrAt, bool ReturnCaptures) {
if (!isIdentifiedFunctionLocal(Object))
return CaptureComponents::Provenance;
@@ -241,8 +234,12 @@ EarliestEscapeAnalysis::getCapturesBefore(const Value *Object,
CaptureComponents::Provenance);
if (EarliestCapture.first)
Inst2Obj[EarliestCapture.first].push_back(Object);
- Iter.first->second = {EarliestCapture.first,
- EarliestCapture.second.WithoutRet};
+ Iter.first->second = {EarliestCapture.first, EarliestCapture.second};
+ }
+
+ if (ReturnCaptures) {
+ assert(!I && "Context instruction not supported if ReturnCaptures");
+ return Iter.first->second.second.WithRet;
}
auto IsNotCapturedBefore = [&]() {
@@ -265,7 +262,7 @@ EarliestEscapeAnalysis::getCapturesBefore(const Value *Object,
};
if (IsNotCapturedBefore())
return CaptureComponents::None;
- return Iter.first->second.second;
+ return Iter.first->second.second.WithoutRet;
}
void EarliestEscapeAnalysis::removeInstruction(Instruction *I) {
@@ -973,8 +970,8 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
// non-volatile stores for them.
if (isModOrRefSet(OtherMR) && !isa<Constant>(Object) && Call != Object &&
(isa<AllocaInst>(Object) || !Call->hasFnAttr(Attribute::ReturnsTwice))) {
- CaptureComponents CC =
- AAQI.CA->getCapturesBefore(Object, Call, /*OrAt=*/false);
+ CaptureComponents CC = AAQI.CA->getCapturesBefore(
+ Object, Call, /*OrAt=*/false, /*ReturnCaptures=*/false);
if (capturesNothing(CC))
OtherMR = ModRefInfo::NoModRef;
else if (capturesReadProvenanceOnly(CC))
@@ -1668,13 +1665,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) &&
- capturesNothing(AAQI.CA->getCapturesBefore(
- O2, dyn_cast<Instruction>(O1), /*OrAt*/ true)))
+ if (isEscapeSource(O1) && capturesNothing(AAQI.CA->getCapturesBefore(
+ O2, dyn_cast<Instruction>(O1), /*OrAt=*/true,
+ /*ReturnCaptures=*/false)))
return AliasResult::NoAlias;
- if (isEscapeSource(O2) &&
- capturesNothing(AAQI.CA->getCapturesBefore(
- O1, dyn_cast<Instruction>(O2), /*OrAt*/ true)))
+ if (isEscapeSource(O2) && capturesNothing(AAQI.CA->getCapturesBefore(
+ O1, dyn_cast<Instruction>(O2), /*OrAt=*/true,
+ /*ReturnCaptures=*/false)))
return AliasResult::NoAlias;
}
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 056f844b3805a..319701e7c25f0 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -1165,8 +1165,8 @@ static bool isFuncLocalAndNotCaptured(Value *Arg, const CallBase *CB,
EarliestEscapeAnalysis &EA) {
const Value *UnderlyingObj = getUnderlyingObject(Arg);
return isIdentifiedFunctionLocal(UnderlyingObj) &&
- capturesNothing(
- EA.getCapturesBefore(UnderlyingObj, CB, /*OrAt*/ true));
+ capturesNothing(EA.getCapturesBefore(UnderlyingObj, CB, /*OrAt=*/true,
+ /*ReturnCaptures=*/false));
}
DSEState::DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
More information about the llvm-commits
mailing list