[llvm] 5e7e216 - [DSE,MemorySSA] Use BatchAA for AA queries.
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 22 00:45:00 PDT 2020
Author: Florian Hahn
Date: 2020-08-22T08:36:35+01:00
New Revision: 5e7e2162d4468063698c280a41f54ea1178c99df
URL: https://github.com/llvm/llvm-project/commit/5e7e2162d4468063698c280a41f54ea1178c99df
DIFF: https://github.com/llvm/llvm-project/commit/5e7e2162d4468063698c280a41f54ea1178c99df.diff
LOG: [DSE,MemorySSA] Use BatchAA for AA queries.
We can use BatchAA to avoid some repeated AA queries. We only remove
stores, so I think we will get away with using a single BatchAA instance
for the complete run.
The changes in AliasAnalysis.h mirror the changes in D85583.
The change improves compile-time by roughly 1%.
http://llvm-compile-time-tracker.com/compare.php?from=67ad786353dfcc7633c65de11601d7823746378e&to=10529e5b43809808e8c198f88fffd8f756554e45&stat=instructions
This is part of the patches to bring down compile-time to the level
referenced in
http://lists.llvm.org/pipermail/llvm-dev/2020-August/144417.html
Reviewed By: asbirlea
Differential Revision: https://reviews.llvm.org/D86275
Added:
Modified:
llvm/include/llvm/Analysis/AliasAnalysis.h
llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h
index c35ee2f499de..1e60dd691549 100644
--- a/llvm/include/llvm/Analysis/AliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/AliasAnalysis.h
@@ -847,6 +847,13 @@ class BatchAAResults {
FunctionModRefBehavior getModRefBehavior(const CallBase *Call) {
return AA.getModRefBehavior(Call);
}
+ bool isMustAlias(const MemoryLocation &LocA, const MemoryLocation &LocB) {
+ return alias(LocA, LocB) == MustAlias;
+ }
+ bool isMustAlias(const Value *V1, const Value *V2) {
+ return alias(MemoryLocation(V1, LocationSize::precise(1)),
+ MemoryLocation(V2, LocationSize::precise(1))) == MustAlias;
+ }
};
/// Temporary typedef for legacy code that uses a generic \c AliasAnalysis
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 168d529dd32a..fa0c2f372e53 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -383,12 +383,12 @@ enum OverwriteResult {
/// write to the same underlying object. In that case, use isPartialOverwrite to
/// check if \p Later partially overwrites \p Earlier. Returns 'OW_Unknown' if
/// nothing can be determined.
-static OverwriteResult isOverwrite(const MemoryLocation &Later,
- const MemoryLocation &Earlier,
- const DataLayout &DL,
- const TargetLibraryInfo &TLI,
- int64_t &EarlierOff, int64_t &LaterOff,
- AliasAnalysis &AA, const Function *F) {
+template <typename AATy>
+static OverwriteResult
+isOverwrite(const MemoryLocation &Later, const MemoryLocation &Earlier,
+ const DataLayout &DL, const TargetLibraryInfo &TLI,
+ int64_t &EarlierOff, int64_t &LaterOff, AATy &AA,
+ const Function *F) {
// FIXME: Vet that this works for size upper-bounds. Seems unlikely that we'll
// get imprecise values here, though (except for unknown sizes).
if (!Later.Size.isPrecise() || !Earlier.Size.isPrecise())
@@ -643,11 +643,10 @@ static bool isPossibleSelfRead(Instruction *Inst,
/// modified between the first and the second instruction.
/// Precondition: Second instruction must be dominated by the first
/// instruction.
-static bool memoryIsNotModifiedBetween(Instruction *FirstI,
- Instruction *SecondI,
- AliasAnalysis *AA,
- const DataLayout &DL,
- DominatorTree *DT) {
+template <typename AATy>
+static bool
+memoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI, AATy &AA,
+ const DataLayout &DL, DominatorTree *DT) {
// Do a backwards scan through the CFG from SecondI to FirstI. Look for
// instructions which can modify the memory location accessed by SecondI.
//
@@ -696,7 +695,7 @@ static bool memoryIsNotModifiedBetween(Instruction *FirstI,
for (; BI != EI; ++BI) {
Instruction *I = &*BI;
if (I->mayWriteToMemory() && I != SecondI)
- if (isModSet(AA->getModRefInfo(I, MemLoc.getWithNewPtr(Ptr))))
+ if (isModSet(AA.getModRefInfo(I, MemLoc.getWithNewPtr(Ptr))))
return false;
}
if (B != FirstBB) {
@@ -1132,7 +1131,7 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI,
if (LoadInst *DepLoad = dyn_cast<LoadInst>(SI->getValueOperand())) {
if (SI->getPointerOperand() == DepLoad->getPointerOperand() &&
isRemovable(SI) &&
- memoryIsNotModifiedBetween(DepLoad, SI, AA, DL, DT)) {
+ memoryIsNotModifiedBetween(DepLoad, SI, *AA, DL, DT)) {
LLVM_DEBUG(
dbgs() << "DSE: Remove Store Of Load from same pointer:\n LOAD: "
@@ -1151,7 +1150,7 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI,
dyn_cast<Instruction>(getUnderlyingObject(SI->getPointerOperand()));
if (UnderlyingPointer && isCallocLikeFn(UnderlyingPointer, TLI) &&
- memoryIsNotModifiedBetween(UnderlyingPointer, SI, AA, DL, DT)) {
+ memoryIsNotModifiedBetween(UnderlyingPointer, SI, *AA, DL, DT)) {
LLVM_DEBUG(
dbgs() << "DSE: Remove null store to the calloc'ed object:\n DEAD: "
<< *Inst << "\n OBJECT: " << *UnderlyingPointer << '\n');
@@ -1164,11 +1163,10 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI,
return false;
}
-static Constant *
-tryToMergePartialOverlappingStores(StoreInst *Earlier, StoreInst *Later,
- int64_t InstWriteOffset,
- int64_t DepWriteOffset, const DataLayout &DL,
- AliasAnalysis *AA, DominatorTree *DT) {
+template <typename AATy>
+static Constant *tryToMergePartialOverlappingStores(
+ StoreInst *Earlier, StoreInst *Later, int64_t InstWriteOffset,
+ int64_t DepWriteOffset, const DataLayout &DL, AATy &AA, DominatorTree *DT) {
if (Earlier && isa<ConstantInt>(Earlier->getValueOperand()) &&
DL.typeSizeEqualsStoreSize(Earlier->getValueOperand()->getType()) &&
@@ -1361,7 +1359,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA,
auto *Earlier = dyn_cast<StoreInst>(DepWrite);
auto *Later = dyn_cast<StoreInst>(Inst);
if (Constant *C = tryToMergePartialOverlappingStores(
- Earlier, Later, InstWriteOffset, DepWriteOffset, DL, AA,
+ Earlier, Later, InstWriteOffset, DepWriteOffset, DL, *AA,
DT)) {
auto *SI = new StoreInst(
C, Earlier->getPointerOperand(), false, Earlier->getAlign(),
@@ -1507,6 +1505,16 @@ bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller) {
struct DSEState {
Function &F;
AliasAnalysis &AA;
+
+ /// The single BatchAA instance that is used to cache AA queries. It will
+ /// not be invalidated over the whole run. This is safe, because:
+ /// 1. Only memory writes are removed, so the alias cache for memory
+ /// locations remains valid.
+ /// 2. No new instructions are added (only instructions removed), so cached
+ /// information for a deleted value cannot be accessed by a re-used new
+ /// value pointer.
+ BatchAAResults BatchAA;
+
MemorySSA &MSSA;
DominatorTree &DT;
PostDominatorTree &PDT;
@@ -1534,7 +1542,7 @@ struct DSEState {
DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT,
PostDominatorTree &PDT, const TargetLibraryInfo &TLI)
- : F(F), AA(AA), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI) {}
+ : F(F), AA(AA), BatchAA(AA), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI) {}
static DSEState get(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
DominatorTree &DT, PostDominatorTree &PDT,
@@ -1623,7 +1631,7 @@ struct DSEState {
}
/// Returns true if \p Use completely overwrites \p DefLoc.
- bool isCompleteOverwrite(MemoryLocation DefLoc, Instruction *UseInst) const {
+ bool isCompleteOverwrite(MemoryLocation DefLoc, Instruction *UseInst) {
// UseInst has a MemoryDef associated in MemorySSA. It's possible for a
// MemoryDef to not write to memory, e.g. a volatile load is modeled as a
// MemoryDef.
@@ -1638,7 +1646,7 @@ struct DSEState {
auto CC = getLocForWriteEx(UseInst);
const DataLayout &DL = F.getParent()->getDataLayout();
return CC && isOverwrite(*CC, DefLoc, DL, TLI, DepWriteOffset,
- InstWriteOffset, AA, &F) == OW_Complete;
+ InstWriteOffset, BatchAA, &F) == OW_Complete;
}
/// Returns true if \p Def is not read before returning from the function.
@@ -1717,7 +1725,7 @@ struct DSEState {
/// Returns true if \p MaybeTerm is a memory terminator for the same
/// underlying object as \p DefLoc.
- bool isMemTerminator(MemoryLocation DefLoc, Instruction *MaybeTerm) const {
+ bool isMemTerminator(MemoryLocation DefLoc, Instruction *MaybeTerm) {
Optional<std::pair<MemoryLocation, bool>> MaybeTermLoc =
getLocForTerminator(MaybeTerm);
@@ -1730,11 +1738,11 @@ struct DSEState {
DataLayout DL = MaybeTerm->getParent()->getModule()->getDataLayout();
DefLoc = MemoryLocation(getUnderlyingObject(DefLoc.Ptr));
}
- return AA.isMustAlias(MaybeTermLoc->first, DefLoc);
+ return BatchAA.isMustAlias(MaybeTermLoc->first, DefLoc);
}
// Returns true if \p Use may read from \p DefLoc.
- bool isReadClobber(MemoryLocation DefLoc, Instruction *UseInst) const {
+ bool isReadClobber(MemoryLocation DefLoc, Instruction *UseInst) {
if (!UseInst->mayReadFromMemory())
return false;
@@ -1742,7 +1750,7 @@ struct DSEState {
if (CB->onlyAccessesInaccessibleMemory())
return false;
- ModRefInfo MR = AA.getModRefInfo(UseInst, DefLoc);
+ ModRefInfo MR = BatchAA.getModRefInfo(UseInst, DefLoc);
// If necessary, perform additional analysis.
if (isRefSet(MR))
MR = AA.callCapturesBefore(UseInst, DefLoc, &DT);
@@ -1758,7 +1766,7 @@ struct DSEState {
Optional<MemoryAccess *>
getDomMemoryDef(MemoryDef *KillingDef, MemoryAccess *Current,
MemoryLocation DefLoc, bool DefVisibleToCallerBeforeRet,
- bool DefVisibleToCallerAfterRet, unsigned &ScanLimit) const {
+ bool DefVisibleToCallerAfterRet, unsigned &ScanLimit) {
if (ScanLimit == 0) {
LLVM_DEBUG(dbgs() << "\n ... hit scan limit\n");
return None;
@@ -2285,7 +2293,7 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA,
// Check if NI overwrites SI.
int64_t InstWriteOffset, DepWriteOffset;
OverwriteResult OR = isOverwrite(SILoc, NILoc, DL, TLI, DepWriteOffset,
- InstWriteOffset, State.AA, &F);
+ InstWriteOffset, State.BatchAA, &F);
if (OR == OW_MaybePartial) {
auto Iter = State.IOLs.insert(
std::make_pair<BasicBlock *, InstOverlapIntervalsTy>(
@@ -2303,8 +2311,8 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA,
// TODO: implement tryToMergeParialOverlappingStores using MemorySSA.
if (Earlier && Later && DT.dominates(Earlier, Later)) {
if (Constant *Merged = tryToMergePartialOverlappingStores(
- Earlier, Later, InstWriteOffset, DepWriteOffset, DL, &AA,
- &DT)) {
+ Earlier, Later, InstWriteOffset, DepWriteOffset, DL,
+ State.BatchAA, &DT)) {
// Update stored value of earlier store to merged constant.
Earlier->setOperand(0, Merged);
More information about the llvm-commits
mailing list