-
Notifications
You must be signed in to change notification settings - Fork 16k
[AA][MemCpyOpt] Introduce CapturesBeforeAnalysis and ChainedCaptureAnalysis (NFCI) #174739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[AA][MemCpyOpt] Introduce CapturesBeforeAnalysis and ChainedCaptureAnalysis (NFCI) #174739
Conversation
…alysis (NFCI) Following up on llvm#110484, it should be possible to drop `callCaptureBefore`, whose last user is MemCpyOpt, while retaining its additional precision by encapsulating it into a dedicated CapturesBeforeAnalysis. This uses `PointerMayBeCapturedBefore` and is more precise than EarliestEscapeAnalysis, though more expensive. Also allow users to query them in chain when needed.
|
@llvm/pr-subscribers-llvm-analysis Author: Antonio Frighetto (antoniofrighetto) ChangesFollowing up on #110484, it should be possible to drop Full diff: https://github.com/llvm/llvm-project/pull/174739.diff 4 Files Affected:
diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h
index 878b7e7a1fb3b..0bdfa797e670c 100644
--- a/llvm/include/llvm/Analysis/AliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/AliasAnalysis.h
@@ -198,6 +198,37 @@ class LLVM_ABI EarliestEscapeAnalysis final : public CaptureAnalysis {
void removeInstruction(Instruction *I);
};
+/// Context-sensitive CaptureAnalysis provider, which precisely determines
+/// whether an object is captured before a specific instruction using
+/// PointerMayBeCapturedBefore.
+class LLVM_ABI CapturesBeforeAnalysis final : public CaptureAnalysis {
+ const DominatorTree &DT;
+ const LoopInfo *LI;
+
+public:
+ CapturesBeforeAnalysis(const DominatorTree &DT, const LoopInfo *LI = nullptr)
+ : DT(DT), LI(LI) {}
+
+ CaptureComponents getCapturesBefore(const Value *Object, const Instruction *I,
+ bool OrAt) override;
+};
+
+/// A CaptureAnalysis provider that chains EarliestEscapeAnalysis and
+/// CapturesBeforeAnalysis. It favours the former, cached but approximate;
+/// falling back to the latter, precise but expensive, when needed.
+class LLVM_ABI ChainedCaptureAnalysis final : public CaptureAnalysis {
+ EarliestEscapeAnalysis &EEA;
+ CapturesBeforeAnalysis &CBA;
+
+public:
+ ChainedCaptureAnalysis(EarliestEscapeAnalysis &EEA,
+ CapturesBeforeAnalysis &CBA)
+ : EEA(EEA), CBA(CBA) {}
+
+ CaptureComponents getCapturesBefore(const Value *Object, const Instruction *I,
+ bool OrAt) override;
+};
+
/// Cache key for BasicAA results. It only includes the pointer and size from
/// MemoryLocation, as BasicAA is AATags independent. Additionally, it includes
/// the value of MayBeCrossIteration, which may affect BasicAA results.
@@ -531,22 +562,6 @@ class AAResults {
LLVM_ABI ModRefInfo getModRefInfo(const Instruction *I1,
const Instruction *I2);
- /// Return information about whether a particular call site modifies
- /// or reads the specified memory location \p MemLoc before instruction \p I
- /// in a BasicBlock.
- ModRefInfo callCapturesBefore(const Instruction *I,
- const MemoryLocation &MemLoc,
- DominatorTree *DT) {
- SimpleAAQueryInfo AAQIP(*this);
- return callCapturesBefore(I, MemLoc, DT, AAQIP);
- }
-
- /// A convenience wrapper to synthesize a memory location.
- ModRefInfo callCapturesBefore(const Instruction *I, const Value *P,
- LocationSize Size, DominatorTree *DT) {
- return callCapturesBefore(I, MemoryLocation(P, Size), DT);
- }
-
/// @}
//===--------------------------------------------------------------------===//
/// \name Higher level methods for querying mod/ref information.
diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index fd2f7c1ea9c8d..fd34204eff003 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -616,71 +616,6 @@ ModRefInfo AAResults::getModRefInfo(const Instruction *I,
}
}
-/// Return information about whether a particular call site modifies
-/// or reads the specified memory location \p MemLoc before instruction \p I
-/// in a BasicBlock.
-/// FIXME: this is really just shoring-up a deficiency in alias analysis.
-/// BasicAA isn't willing to spend linear time determining whether an alloca
-/// was captured before or after this particular call, while we are. However,
-/// with a smarter AA in place, this test is just wasting compile time.
-ModRefInfo AAResults::callCapturesBefore(const Instruction *I,
- const MemoryLocation &MemLoc,
- DominatorTree *DT,
- AAQueryInfo &AAQI) {
- if (!DT)
- return ModRefInfo::ModRef;
-
- const Value *Object = getUnderlyingObject(MemLoc.Ptr);
- if (!isIdentifiedFunctionLocal(Object))
- return ModRefInfo::ModRef;
-
- const auto *Call = dyn_cast<CallBase>(I);
- if (!Call || Call == Object)
- return ModRefInfo::ModRef;
-
- if (capturesAnything(PointerMayBeCapturedBefore(
- Object, /* ReturnCaptures */ true, I, DT,
- /* include Object */ true, CaptureComponents::Provenance)))
- return ModRefInfo::ModRef;
-
- unsigned ArgNo = 0;
- ModRefInfo R = ModRefInfo::NoModRef;
- // Set flag only if no May found and all operands processed.
- for (auto CI = Call->data_operands_begin(), CE = Call->data_operands_end();
- CI != CE; ++CI, ++ArgNo) {
- // Only look at the no-capture or byval pointer arguments. If this
- // pointer were passed to arguments that were neither of these, then it
- // couldn't be no-capture.
- if (!(*CI)->getType()->isPointerTy())
- continue;
-
- // Make sure we still check captures(ret: address, provenance) and
- // captures(address) arguments, as these wouldn't be treated as a capture
- // at the call-site.
- CaptureInfo Captures = Call->getCaptureInfo(ArgNo);
- if (capturesAnyProvenance(Captures.getOtherComponents()))
- continue;
-
- AliasResult AR =
- alias(MemoryLocation::getBeforeOrAfter(*CI),
- MemoryLocation::getBeforeOrAfter(Object), AAQI, Call);
- // If this is a no-capture pointer argument, see if we can tell that it
- // is impossible to alias the pointer we're checking. If not, we have to
- // assume that the call could touch the pointer, even though it doesn't
- // escape.
- if (AR == AliasResult::NoAlias)
- continue;
- if (Call->doesNotAccessMemory(ArgNo))
- continue;
- if (Call->onlyReadsMemory(ArgNo)) {
- R = ModRefInfo::Ref;
- continue;
- }
- return ModRefInfo::ModRef;
- }
- return R;
-}
-
/// canBasicBlockModify - Return true if it is possible for execution of the
/// specified basic block to modify the location Loc.
///
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 1d5f9ac465808..f085d720ba597 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -270,6 +270,32 @@ void EarliestEscapeAnalysis::removeInstruction(Instruction *I) {
}
}
+CaptureComponents
+CapturesBeforeAnalysis::getCapturesBefore(const Value *Object,
+ const Instruction *I, bool OrAt) {
+ assert(I && "CapturesBeforeAnalysis requires a context instruction.");
+ if (!isIdentifiedFunctionLocal(Object))
+ return CaptureComponents::Provenance;
+
+ return PointerMayBeCapturedBefore(
+ Object, /* ReturnCaptures */ true, I, &DT, /* IncludeI */ true,
+ CaptureComponents::Provenance, capturesAnything, LI);
+}
+
+CaptureComponents
+ChainedCaptureAnalysis::getCapturesBefore(const Value *Object,
+ const Instruction *I, bool OrAt) {
+ CaptureComponents CC = EEA.getCapturesBefore(Object, I, OrAt);
+ if (!capturesAnyProvenance(CC))
+ return CC;
+
+ // If we still happen not to have the context instruction, we cannot provide
+ // more precision than EarliestEscapeAnalysis.
+ if (!I)
+ return CC;
+ return CBA.getCapturesBefore(Object, I, OrAt);
+}
+
//===----------------------------------------------------------------------===//
// GetElementPtr Instruction Decomposition and Analysis
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index f054b21f2e9dd..5f0e90eed747f 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -1048,14 +1048,15 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad,
// In addition to knowing that the call does not access src in some
// unexpected manner, for example via a global, which we deduce from
// the use analysis, we also need to know that it does not sneakily
- // access dest. We rely on AA to figure this out for us.
- MemoryLocation DestWithSrcSize(cpyDest, LocationSize::precise(srcSize));
- ModRefInfo MR = BAA.getModRefInfo(C, DestWithSrcSize);
- // If necessary, perform additional analysis.
- if (isModOrRefSet(MR))
- MR = BAA.callCapturesBefore(C, DestWithSrcSize, DT);
- if (isModOrRefSet(MR))
- return false;
+ // access dest. We rely on AA with CapturesBeforeAnalysis to figure this out.
+ {
+ MemoryLocation DestWithSrcSize(cpyDest, LocationSize::precise(srcSize));
+ CapturesBeforeAnalysis CBA(*DT);
+ ChainedCaptureAnalysis CCA(*EEA, CBA);
+ BatchAAResults BAAWithCCA(*AA, &CCA);
+ if (isModOrRefSet(BAAWithCCA.getModRefInfo(C, DestWithSrcSize)))
+ return false;
+ }
// We can't create address space casts here because we don't know if they're
// safe for the target.
|
|
@llvm/pr-subscribers-llvm-transforms Author: Antonio Frighetto (antoniofrighetto) ChangesFollowing up on #110484, it should be possible to drop Full diff: https://github.com/llvm/llvm-project/pull/174739.diff 4 Files Affected:
diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h
index 878b7e7a1fb3b..0bdfa797e670c 100644
--- a/llvm/include/llvm/Analysis/AliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/AliasAnalysis.h
@@ -198,6 +198,37 @@ class LLVM_ABI EarliestEscapeAnalysis final : public CaptureAnalysis {
void removeInstruction(Instruction *I);
};
+/// Context-sensitive CaptureAnalysis provider, which precisely determines
+/// whether an object is captured before a specific instruction using
+/// PointerMayBeCapturedBefore.
+class LLVM_ABI CapturesBeforeAnalysis final : public CaptureAnalysis {
+ const DominatorTree &DT;
+ const LoopInfo *LI;
+
+public:
+ CapturesBeforeAnalysis(const DominatorTree &DT, const LoopInfo *LI = nullptr)
+ : DT(DT), LI(LI) {}
+
+ CaptureComponents getCapturesBefore(const Value *Object, const Instruction *I,
+ bool OrAt) override;
+};
+
+/// A CaptureAnalysis provider that chains EarliestEscapeAnalysis and
+/// CapturesBeforeAnalysis. It favours the former, cached but approximate;
+/// falling back to the latter, precise but expensive, when needed.
+class LLVM_ABI ChainedCaptureAnalysis final : public CaptureAnalysis {
+ EarliestEscapeAnalysis &EEA;
+ CapturesBeforeAnalysis &CBA;
+
+public:
+ ChainedCaptureAnalysis(EarliestEscapeAnalysis &EEA,
+ CapturesBeforeAnalysis &CBA)
+ : EEA(EEA), CBA(CBA) {}
+
+ CaptureComponents getCapturesBefore(const Value *Object, const Instruction *I,
+ bool OrAt) override;
+};
+
/// Cache key for BasicAA results. It only includes the pointer and size from
/// MemoryLocation, as BasicAA is AATags independent. Additionally, it includes
/// the value of MayBeCrossIteration, which may affect BasicAA results.
@@ -531,22 +562,6 @@ class AAResults {
LLVM_ABI ModRefInfo getModRefInfo(const Instruction *I1,
const Instruction *I2);
- /// Return information about whether a particular call site modifies
- /// or reads the specified memory location \p MemLoc before instruction \p I
- /// in a BasicBlock.
- ModRefInfo callCapturesBefore(const Instruction *I,
- const MemoryLocation &MemLoc,
- DominatorTree *DT) {
- SimpleAAQueryInfo AAQIP(*this);
- return callCapturesBefore(I, MemLoc, DT, AAQIP);
- }
-
- /// A convenience wrapper to synthesize a memory location.
- ModRefInfo callCapturesBefore(const Instruction *I, const Value *P,
- LocationSize Size, DominatorTree *DT) {
- return callCapturesBefore(I, MemoryLocation(P, Size), DT);
- }
-
/// @}
//===--------------------------------------------------------------------===//
/// \name Higher level methods for querying mod/ref information.
diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index fd2f7c1ea9c8d..fd34204eff003 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -616,71 +616,6 @@ ModRefInfo AAResults::getModRefInfo(const Instruction *I,
}
}
-/// Return information about whether a particular call site modifies
-/// or reads the specified memory location \p MemLoc before instruction \p I
-/// in a BasicBlock.
-/// FIXME: this is really just shoring-up a deficiency in alias analysis.
-/// BasicAA isn't willing to spend linear time determining whether an alloca
-/// was captured before or after this particular call, while we are. However,
-/// with a smarter AA in place, this test is just wasting compile time.
-ModRefInfo AAResults::callCapturesBefore(const Instruction *I,
- const MemoryLocation &MemLoc,
- DominatorTree *DT,
- AAQueryInfo &AAQI) {
- if (!DT)
- return ModRefInfo::ModRef;
-
- const Value *Object = getUnderlyingObject(MemLoc.Ptr);
- if (!isIdentifiedFunctionLocal(Object))
- return ModRefInfo::ModRef;
-
- const auto *Call = dyn_cast<CallBase>(I);
- if (!Call || Call == Object)
- return ModRefInfo::ModRef;
-
- if (capturesAnything(PointerMayBeCapturedBefore(
- Object, /* ReturnCaptures */ true, I, DT,
- /* include Object */ true, CaptureComponents::Provenance)))
- return ModRefInfo::ModRef;
-
- unsigned ArgNo = 0;
- ModRefInfo R = ModRefInfo::NoModRef;
- // Set flag only if no May found and all operands processed.
- for (auto CI = Call->data_operands_begin(), CE = Call->data_operands_end();
- CI != CE; ++CI, ++ArgNo) {
- // Only look at the no-capture or byval pointer arguments. If this
- // pointer were passed to arguments that were neither of these, then it
- // couldn't be no-capture.
- if (!(*CI)->getType()->isPointerTy())
- continue;
-
- // Make sure we still check captures(ret: address, provenance) and
- // captures(address) arguments, as these wouldn't be treated as a capture
- // at the call-site.
- CaptureInfo Captures = Call->getCaptureInfo(ArgNo);
- if (capturesAnyProvenance(Captures.getOtherComponents()))
- continue;
-
- AliasResult AR =
- alias(MemoryLocation::getBeforeOrAfter(*CI),
- MemoryLocation::getBeforeOrAfter(Object), AAQI, Call);
- // If this is a no-capture pointer argument, see if we can tell that it
- // is impossible to alias the pointer we're checking. If not, we have to
- // assume that the call could touch the pointer, even though it doesn't
- // escape.
- if (AR == AliasResult::NoAlias)
- continue;
- if (Call->doesNotAccessMemory(ArgNo))
- continue;
- if (Call->onlyReadsMemory(ArgNo)) {
- R = ModRefInfo::Ref;
- continue;
- }
- return ModRefInfo::ModRef;
- }
- return R;
-}
-
/// canBasicBlockModify - Return true if it is possible for execution of the
/// specified basic block to modify the location Loc.
///
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 1d5f9ac465808..f085d720ba597 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -270,6 +270,32 @@ void EarliestEscapeAnalysis::removeInstruction(Instruction *I) {
}
}
+CaptureComponents
+CapturesBeforeAnalysis::getCapturesBefore(const Value *Object,
+ const Instruction *I, bool OrAt) {
+ assert(I && "CapturesBeforeAnalysis requires a context instruction.");
+ if (!isIdentifiedFunctionLocal(Object))
+ return CaptureComponents::Provenance;
+
+ return PointerMayBeCapturedBefore(
+ Object, /* ReturnCaptures */ true, I, &DT, /* IncludeI */ true,
+ CaptureComponents::Provenance, capturesAnything, LI);
+}
+
+CaptureComponents
+ChainedCaptureAnalysis::getCapturesBefore(const Value *Object,
+ const Instruction *I, bool OrAt) {
+ CaptureComponents CC = EEA.getCapturesBefore(Object, I, OrAt);
+ if (!capturesAnyProvenance(CC))
+ return CC;
+
+ // If we still happen not to have the context instruction, we cannot provide
+ // more precision than EarliestEscapeAnalysis.
+ if (!I)
+ return CC;
+ return CBA.getCapturesBefore(Object, I, OrAt);
+}
+
//===----------------------------------------------------------------------===//
// GetElementPtr Instruction Decomposition and Analysis
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index f054b21f2e9dd..5f0e90eed747f 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -1048,14 +1048,15 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad,
// In addition to knowing that the call does not access src in some
// unexpected manner, for example via a global, which we deduce from
// the use analysis, we also need to know that it does not sneakily
- // access dest. We rely on AA to figure this out for us.
- MemoryLocation DestWithSrcSize(cpyDest, LocationSize::precise(srcSize));
- ModRefInfo MR = BAA.getModRefInfo(C, DestWithSrcSize);
- // If necessary, perform additional analysis.
- if (isModOrRefSet(MR))
- MR = BAA.callCapturesBefore(C, DestWithSrcSize, DT);
- if (isModOrRefSet(MR))
- return false;
+ // access dest. We rely on AA with CapturesBeforeAnalysis to figure this out.
+ {
+ MemoryLocation DestWithSrcSize(cpyDest, LocationSize::precise(srcSize));
+ CapturesBeforeAnalysis CBA(*DT);
+ ChainedCaptureAnalysis CCA(*EEA, CBA);
+ BatchAAResults BAAWithCCA(*AA, &CCA);
+ if (isModOrRefSet(BAAWithCCA.getModRefInfo(C, DestWithSrcSize)))
+ return false;
+ }
// We can't create address space casts here because we don't know if they're
// safe for the target.
|
|
Kind ping on direction. |
Following up on #110484, it should be possible to drop
callCaptureBefore, whose last user is MemCpyOpt, while retaining its additional precision by encapsulating it into a dedicated CapturesBeforeAnalysis. This usesPointerMayBeCapturedBeforeand is more precise than EarliestEscapeAnalysis, though more expensive. Also allow users to query them in chain when needed.