[llvm] a344b38 - [GVN] Preserve MemorySSA if it is available.
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 3 04:29:16 PDT 2020
Author: Florian Hahn
Date: 2020-09-03T12:28:13+01:00
New Revision: a344b382a0f64922c22a4ad048aca925a784942a
URL: https://github.com/llvm/llvm-project/commit/a344b382a0f64922c22a4ad048aca925a784942a
DIFF: https://github.com/llvm/llvm-project/commit/a344b382a0f64922c22a4ad048aca925a784942a.diff
LOG: [GVN] Preserve MemorySSA if it is available.
Preserve MemorySSA if it is available before running GVN.
DSE with MemorySSA will run closely after GVN. If GVN and 2 other
passes preserve MemorySSA, DSE can re-use MemorySSA used by LICM
when doing LTO.
Reviewed By: asbirlea
Differential Revision: https://reviews.llvm.org/D86534
Added:
llvm/test/Transforms/GVN/preserve-memoryssa.ll
Modified:
llvm/include/llvm/Transforms/Scalar/GVN.h
llvm/lib/Transforms/Scalar/GVN.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/Scalar/GVN.h b/llvm/include/llvm/Transforms/Scalar/GVN.h
index f2818c6b792e..be3804f95c3e 100644
--- a/llvm/include/llvm/Transforms/Scalar/GVN.h
+++ b/llvm/include/llvm/Transforms/Scalar/GVN.h
@@ -46,11 +46,12 @@ class FunctionPass;
class IntrinsicInst;
class LoadInst;
class LoopInfo;
+class MemorySSA;
+class MemorySSAUpdater;
class OptimizationRemarkEmitter;
class PHINode;
class TargetLibraryInfo;
class Value;
-
/// A private "module" namespace for types and utilities used by GVN. These
/// are implementation details and should not be used by clients.
namespace gvn LLVM_LIBRARY_VISIBILITY {
@@ -211,6 +212,7 @@ class GVN : public PassInfoMixin<GVN> {
OptimizationRemarkEmitter *ORE = nullptr;
ImplicitControlFlowTracking *ICF = nullptr;
LoopInfo *LI = nullptr;
+ MemorySSAUpdater *MSSAU = nullptr;
ValueTable VN;
@@ -246,7 +248,7 @@ class GVN : public PassInfoMixin<GVN> {
bool runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
const TargetLibraryInfo &RunTLI, AAResults &RunAA,
MemoryDependenceResults *RunMD, LoopInfo *LI,
- OptimizationRemarkEmitter *ORE);
+ OptimizationRemarkEmitter *ORE, MemorySSA *MSSA = nullptr);
/// Push a new Value to the LeaderTable onto the list for its value number.
void addToLeaderTable(uint32_t N, Value *V, const BasicBlock *BB) {
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index ff7596b19cb2..f8962c085224 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -26,8 +26,8 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/AssumeBundleQueries.h"
#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/AssumeBundleQueries.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/DomTreeUpdater.h"
@@ -36,6 +36,8 @@
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
+#include "llvm/Analysis/MemorySSA.h"
+#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/PHITransAddr.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
@@ -653,14 +655,18 @@ PreservedAnalyses GVN::run(Function &F, FunctionAnalysisManager &AM) {
auto *MemDep =
isMemDepEnabled() ? &AM.getResult<MemoryDependenceAnalysis>(F) : nullptr;
auto *LI = AM.getCachedResult<LoopAnalysis>(F);
+ auto *MSSA = AM.getCachedResult<MemorySSAAnalysis>(F);
auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
- bool Changed = runImpl(F, AC, DT, TLI, AA, MemDep, LI, &ORE);
+ bool Changed = runImpl(F, AC, DT, TLI, AA, MemDep, LI, &ORE,
+ MSSA ? &MSSA->getMSSA() : nullptr);
if (!Changed)
return PreservedAnalyses::all();
PreservedAnalyses PA;
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<GlobalsAA>();
PA.preserve<TargetLibraryAnalysis>();
+ if (MSSA)
+ PA.preserve<MemorySSAAnalysis>();
if (LI)
PA.preserve<LoopAnalysis>();
return PA;
@@ -1335,6 +1341,22 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
LI->getAlign(), LI->getOrdering(), LI->getSyncScopeID(),
UnavailablePred->getTerminator());
NewLoad->setDebugLoc(LI->getDebugLoc());
+ if (MSSAU) {
+ auto *MSSA = MSSAU->getMemorySSA();
+ // Get the defining access of the original load or use the load if it is a
+ // MemoryDef (e.g. because it is volatile). The inserted loads are
+ // guaranteed to load from the same definition.
+ auto *LIAcc = MSSA->getMemoryAccess(LI);
+ auto *DefiningAcc =
+ isa<MemoryDef>(LIAcc) ? LIAcc : LIAcc->getDefiningAccess();
+ auto *NewAccess = MSSAU->createMemoryAccessInBB(
+ NewLoad, DefiningAcc, NewLoad->getParent(),
+ MemorySSA::BeforeTerminator);
+ if (auto *NewDef = dyn_cast<MemoryDef>(NewAccess))
+ MSSAU->insertDef(NewDef, /*RenameUses=*/true);
+ else
+ MSSAU->insertUse(cast<MemoryUse>(NewAccess), /*RenameUses=*/true);
+ }
// Transfer the old load's AA tags to the new load.
AAMDNodes Tags;
@@ -1551,9 +1573,17 @@ bool GVN::processAssumeIntrinsic(IntrinsicInst *IntrinsicI) {
// Insert a new store to null instruction before the load to indicate that
// this code is not reachable. FIXME: We could insert unreachable
// instruction directly because we can modify the CFG.
- new StoreInst(UndefValue::get(Int8Ty),
- Constant::getNullValue(Int8Ty->getPointerTo()),
- IntrinsicI);
+ auto *NewS = new StoreInst(UndefValue::get(Int8Ty),
+ Constant::getNullValue(Int8Ty->getPointerTo()),
+ IntrinsicI);
+ if (MSSAU) {
+ // This added store is to null, so it will never executed and we can
+ // just use the LiveOnEntry def as defining access.
+ auto *NewDef = MSSAU->createMemoryAccessInBB(
+ NewS, MSSAU->getMemorySSA()->getLiveOnEntryDef(), NewS->getParent(),
+ MemorySSA::BeforeTerminator);
+ MSSAU->insertDef(cast<MemoryDef>(NewDef), /*RenameUses=*/true);
+ }
}
if (isAssumeWithEmptyBundle(*IntrinsicI))
markInstructionForDeletion(IntrinsicI);
@@ -1687,6 +1717,8 @@ bool GVN::processLoad(LoadInst *L) {
// Replace the load!
patchAndReplaceAllUsesWith(L, AvailableValue);
markInstructionForDeletion(L);
+ if (MSSAU)
+ MSSAU->removeMemoryAccess(L);
++NumGVNLoad;
reportLoadElim(L, AvailableValue, ORE);
// Tell MDA to rexamine the reused pointer since we might have more
@@ -2204,7 +2236,7 @@ bool GVN::processInstruction(Instruction *I) {
bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
const TargetLibraryInfo &RunTLI, AAResults &RunAA,
MemoryDependenceResults *RunMD, LoopInfo *LI,
- OptimizationRemarkEmitter *RunORE) {
+ OptimizationRemarkEmitter *RunORE, MemorySSA *MSSA) {
AC = &RunAC;
DT = &RunDT;
VN.setDomTree(DT);
@@ -2217,6 +2249,8 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
VN.setMemDep(MD);
ORE = RunORE;
InvalidBlockRPONumbers = true;
+ MemorySSAUpdater Updater(MSSA);
+ MSSAU = MSSA ? &Updater : nullptr;
bool Changed = false;
bool ShouldContinue = true;
@@ -2227,7 +2261,7 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ) {
BasicBlock *BB = &*FI++;
- bool removedBlock = MergeBlockIntoPredecessor(BB, &DTU, LI, nullptr, MD);
+ bool removedBlock = MergeBlockIntoPredecessor(BB, &DTU, LI, MSSAU, MD);
if (removedBlock)
++NumGVNBlocks;
@@ -2263,6 +2297,9 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
// iteration.
DeadBlocks.clear();
+ if (MSSA && VerifyMemorySSA)
+ MSSA->verifyMemorySSA();
+
return Changed;
}
@@ -2303,6 +2340,8 @@ bool GVN::processBlock(BasicBlock *BB) {
salvageKnowledge(I, AC);
salvageDebugInfo(*I);
if (MD) MD->removeInstruction(I);
+ if (MSSAU)
+ MSSAU->removeMemoryAccess(I);
LLVM_DEBUG(verifyRemoved(I));
ICF->removeInstruction(I);
I->eraseFromParent();
@@ -2533,6 +2572,8 @@ bool GVN::performScalarPRE(Instruction *CurInst) {
LLVM_DEBUG(dbgs() << "GVN PRE removed: " << *CurInst << '\n');
if (MD)
MD->removeInstruction(CurInst);
+ if (MSSAU)
+ MSSAU->removeMemoryAccess(CurInst);
LLVM_DEBUG(verifyRemoved(CurInst));
// FIXME: Intended to be markInstructionForDeletion(CurInst), but it causes
// some assertion failures.
@@ -2577,7 +2618,7 @@ BasicBlock *GVN::splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ) {
// possible.
BasicBlock *BB = SplitCriticalEdge(
Pred, Succ,
- CriticalEdgeSplittingOptions(DT, LI).unsetPreserveLoopSimplify());
+ CriticalEdgeSplittingOptions(DT, LI, MSSAU).unsetPreserveLoopSimplify());
if (MD)
MD->invalidateCachedPredecessors();
InvalidBlockRPONumbers = true;
@@ -2592,7 +2633,7 @@ bool GVN::splitCriticalEdges() {
do {
std::pair<Instruction *, unsigned> Edge = toSplit.pop_back_val();
SplitCriticalEdge(Edge.first, Edge.second,
- CriticalEdgeSplittingOptions(DT, LI));
+ CriticalEdgeSplittingOptions(DT, LI, MSSAU));
} while (!toSplit.empty());
if (MD) MD->invalidateCachedPredecessors();
InvalidBlockRPONumbers = true;
@@ -2791,6 +2832,7 @@ class llvm::gvn::GVNLegacyPass : public FunctionPass {
auto *LIWP = getAnalysisIfAvailable<LoopInfoWrapperPass>();
+ auto *MSSAWP = getAnalysisIfAvailable<MemorySSAWrapperPass>();
return Impl.runImpl(
F, getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F),
getAnalysis<DominatorTreeWrapperPass>().getDomTree(),
@@ -2800,7 +2842,8 @@ class llvm::gvn::GVNLegacyPass : public FunctionPass {
? &getAnalysis<MemoryDependenceWrapperPass>().getMemDep()
: nullptr,
LIWP ? &LIWP->getLoopInfo() : nullptr,
- &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE());
+ &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE(),
+ MSSAWP ? &MSSAWP->getMSSA() : nullptr);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -2817,6 +2860,7 @@ class llvm::gvn::GVNLegacyPass : public FunctionPass {
AU.addPreserved<TargetLibraryInfoWrapperPass>();
AU.addPreserved<LoopInfoWrapperPass>();
AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+ AU.addPreserved<MemorySSAWrapperPass>();
}
private:
diff --git a/llvm/test/Transforms/GVN/preserve-memoryssa.ll b/llvm/test/Transforms/GVN/preserve-memoryssa.ll
new file mode 100644
index 000000000000..a815baaa3d00
--- /dev/null
+++ b/llvm/test/Transforms/GVN/preserve-memoryssa.ll
@@ -0,0 +1,95 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -aa-pipeline=basic-aa -passes='require<memoryssa>,gvn' -S -verify-memoryssa %s | FileCheck %s
+
+; REQUIRES: asserts
+
+declare void @use(i32) readnone
+
+define i32 @test(i32* %ptr.0, i32** %ptr.1, i1 %c) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[LV_0:%.*]] = load i32, i32* [[PTR_0:%.*]], align 8
+; CHECK-NEXT: call void @use(i32 [[LV_0]])
+; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN749:%.*]], label [[FOR_INC774:%.*]]
+; CHECK: if.then749:
+; CHECK-NEXT: [[LV_1:%.*]] = load i32*, i32** [[PTR_1:%.*]], align 8
+; CHECK-NEXT: store i32 10, i32* [[LV_1]], align 4
+; CHECK-NEXT: [[LV_2_PRE:%.*]] = load i32, i32* [[PTR_0]], align 8
+; CHECK-NEXT: br label [[FOR_INC774]]
+; CHECK: for.inc774:
+; CHECK-NEXT: [[LV_2:%.*]] = phi i32 [ [[LV_2_PRE]], [[IF_THEN749]] ], [ [[LV_0]], [[ENTRY:%.*]] ]
+; CHECK-NEXT: call void @use(i32 [[LV_2]])
+; CHECK-NEXT: ret i32 1
+;
+entry:
+ br label %for.end435
+
+for.end435:
+ %lv.0 = load i32, i32* %ptr.0, align 8
+ call void @use(i32 %lv.0)
+ br label %if.end724
+
+if.end724:
+ br i1 %c, label %if.then749, label %for.inc774
+
+if.then749:
+ %lv.1 = load i32*, i32** %ptr.1, align 8
+ %arrayidx772 = getelementptr inbounds i32, i32* %lv.1, i64 0
+ store i32 10, i32* %arrayidx772, align 4
+ br label %for.inc774
+
+for.inc774:
+ br label %for.body830
+
+for.body830:
+ %lv.2 = load i32, i32* %ptr.0, align 8
+ call void @use(i32 %lv.2)
+ br label %for.body.i22
+
+for.body.i22:
+ ret i32 1
+}
+
+define i32 @test_volatile(i32* %ptr.0, i32** %ptr.1, i1 %c) {
+; CHECK-LABEL: @test_volatile(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[LV_0:%.*]] = load volatile i32, i32* [[PTR_0:%.*]], align 8
+; CHECK-NEXT: call void @use(i32 [[LV_0]])
+; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN749:%.*]], label [[FOR_INC774:%.*]]
+; CHECK: if.then749:
+; CHECK-NEXT: [[LV_1:%.*]] = load volatile i32*, i32** [[PTR_1:%.*]], align 8
+; CHECK-NEXT: store i32 10, i32* [[LV_1]], align 4
+; CHECK-NEXT: br label [[FOR_INC774]]
+; CHECK: for.inc774:
+; CHECK-NEXT: [[LV_2:%.*]] = load volatile i32, i32* [[PTR_0]], align 8
+; CHECK-NEXT: call void @use(i32 [[LV_2]])
+; CHECK-NEXT: ret i32 1
+;
+entry:
+ br label %for.end435
+
+for.end435:
+ %lv.0 = load volatile i32, i32* %ptr.0, align 8
+ call void @use(i32 %lv.0)
+ br label %if.end724
+
+if.end724:
+ br i1 %c, label %if.then749, label %for.inc774
+
+if.then749:
+ %lv.1 = load volatile i32*, i32** %ptr.1, align 8
+ %arrayidx772 = getelementptr inbounds i32, i32* %lv.1, i64 0
+ store i32 10, i32* %arrayidx772, align 4
+ br label %for.inc774
+
+for.inc774:
+ br label %for.body830
+
+for.body830:
+ %lv.2 = load volatile i32, i32* %ptr.0, align 8
+ call void @use(i32 %lv.2)
+ br label %for.body.i22
+
+for.body.i22:
+ ret i32 1
+}
More information about the llvm-commits
mailing list