diff --git a/llvm/include/llvm/Transforms/Scalar/GVN.h b/llvm/include/llvm/Transforms/Scalar/GVN.h index be6c0ec5edab0..c8be390799836 100644 --- a/llvm/include/llvm/Transforms/Scalar/GVN.h +++ b/llvm/include/llvm/Transforms/Scalar/GVN.h @@ -77,6 +77,7 @@ struct GVNOptions { std::optional AllowLoadInLoopPRE; std::optional AllowLoadPRESplitBackedge; std::optional AllowMemDep; + std::optional AllowMemorySSA; GVNOptions() = default; @@ -108,6 +109,12 @@ struct GVNOptions { AllowMemDep = MemDep; return *this; } + + /// Enables or disables use of MemorySSA. + GVNOptions &setMemorySSA(bool MemSSA) { + AllowMemorySSA = MemSSA; + return *this; + } }; /// The core GVN pass object. @@ -144,6 +151,7 @@ class GVNPass : public PassInfoMixin { bool isLoadInLoopPREEnabled() const; bool isLoadPRESplitBackedgeEnabled() const; bool isMemDepEnabled() const; + bool isMemorySSAEnabled() const; /// This class holds the mapping between values and value numbers. It is used /// as an efficient mechanism to determine the expression-wise equivalence of @@ -383,9 +391,8 @@ class GVNPass : public PassInfoMixin { void assignBlockRPONumber(Function &F); }; -/// Create a legacy GVN pass. This also allows parameterizing whether or not -/// MemDep is enabled. -FunctionPass *createGVNPass(bool NoMemDepAnalysis = false); +/// Create a legacy GVN pass. +FunctionPass *createGVNPass(); /// A simple and fast domtree-based GVN pass to hoist common expressions /// from sibling branches. diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index aac4407740055..90d11956d62a7 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -1042,6 +1042,8 @@ Expected parseGVNOptions(StringRef Params) { Result.setLoadPRESplitBackedge(Enable); } else if (ParamName == "memdep") { Result.setMemDep(Enable); + } else if (ParamName == "memoryssa") { + Result.setMemorySSA(Enable); } else { return make_error( formatv("invalid GVN pass parameter '{0}' ", ParamName).str(), diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 1021d7fcd9247..a93a995655a14 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -526,7 +526,7 @@ FUNCTION_PASS_WITH_PARAMS( "gvn", "GVNPass", [](GVNOptions Opts) { return GVNPass(Opts); }, parseGVNOptions, "no-pre;pre;no-load-pre;load-pre;no-split-backedge-load-pre;" - "split-backedge-load-pre;no-memdep;memdep") + "split-backedge-load-pre;no-memdep;memdep;no-memoryssa;memoryssa") FUNCTION_PASS_WITH_PARAMS( "hardware-loops", "HardwareLoopsPass", [](HardwareLoopOptions Opts) { return HardwareLoopsPass(Opts); }, diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp index 229fffe92b99c..8d27a22570e9c 100644 --- a/llvm/lib/Transforms/Scalar/GVN.cpp +++ b/llvm/lib/Transforms/Scalar/GVN.cpp @@ -113,6 +113,8 @@ static cl::opt GVNEnableSplitBackedgeInLoadPRE("enable-split-backedge-in-load-pre", cl::init(false)); static cl::opt GVNEnableMemDep("enable-gvn-memdep", cl::init(true)); +static cl::opt GVNEnableMemorySSA("enable-gvn-memoryssa", + cl::init(false)); static cl::opt MaxNumDeps( "gvn-max-num-deps", cl::Hidden, cl::init(100), @@ -820,6 +822,10 @@ bool GVNPass::isMemDepEnabled() const { return Options.AllowMemDep.value_or(GVNEnableMemDep); } +bool GVNPass::isMemorySSAEnabled() const { + return Options.AllowMemorySSA.value_or(GVNEnableMemorySSA); +} + PreservedAnalyses GVNPass::run(Function &F, FunctionAnalysisManager &AM) { // FIXME: The order of evaluation of these 'getResult' calls is very // significant! Re-ordering these variables will cause GVN when run alone to @@ -832,7 +838,10 @@ PreservedAnalyses GVNPass::run(Function &F, FunctionAnalysisManager &AM) { auto *MemDep = isMemDepEnabled() ? &AM.getResult(F) : nullptr; auto &LI = AM.getResult(F); - auto *MSSA = AM.getCachedResult(F); + auto *MSSA = + isMemorySSAEnabled() ? &AM.getResult(F) : nullptr; + assert(!(MemDep && MSSA) && + "Should not use both MemDep and MemorySSA simultaneously!"); auto &ORE = AM.getResult(F); bool Changed = runImpl(F, AC, DT, TLI, AA, MemDep, LI, &ORE, MSSA ? &MSSA->getMSSA() : nullptr); @@ -861,7 +870,9 @@ void GVNPass::printPipeline( OS << (*Options.AllowLoadPRESplitBackedge ? "" : "no-") << "split-backedge-load-pre;"; if (Options.AllowMemDep != std::nullopt) - OS << (*Options.AllowMemDep ? "" : "no-") << "memdep"; + OS << (*Options.AllowMemDep ? "" : "no-") << "memdep;"; + if (Options.AllowMemorySSA != std::nullopt) + OS << (*Options.AllowMemorySSA ? "" : "no-") << "memoryssa"; OS << '>'; } @@ -3293,8 +3304,11 @@ class llvm::gvn::GVNLegacyPass : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid - explicit GVNLegacyPass(bool NoMemDepAnalysis = !GVNEnableMemDep) - : FunctionPass(ID), Impl(GVNOptions().setMemDep(!NoMemDepAnalysis)) { + explicit GVNLegacyPass(bool MemDepAnalysis = GVNEnableMemDep, + bool MemSSAAnalysis = GVNEnableMemorySSA) + : FunctionPass(ID), Impl(GVNOptions() + .setMemDep(MemDepAnalysis) + .setMemorySSA(MemSSAAnalysis)) { initializeGVNLegacyPassPass(*PassRegistry::getPassRegistry()); } @@ -3302,7 +3316,6 @@ class llvm::gvn::GVNLegacyPass : public FunctionPass { if (skipFunction(F)) return false; - auto *MSSAWP = getAnalysisIfAvailable(); return Impl.runImpl( F, getAnalysis().getAssumptionCache(F), getAnalysis().getDomTree(), @@ -3313,7 +3326,9 @@ class llvm::gvn::GVNLegacyPass : public FunctionPass { : nullptr, getAnalysis().getLoopInfo(), &getAnalysis().getORE(), - MSSAWP ? &MSSAWP->getMSSA() : nullptr); + Impl.isMemorySSAEnabled() + ? &getAnalysis().getMSSA() + : nullptr); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -3329,7 +3344,8 @@ class llvm::gvn::GVNLegacyPass : public FunctionPass { AU.addPreserved(); AU.addPreserved(); AU.addRequired(); - AU.addPreserved(); + if (Impl.isMemorySSAEnabled()) + AU.addRequired(); } private: @@ -3341,6 +3357,7 @@ char GVNLegacyPass::ID = 0; INITIALIZE_PASS_BEGIN(GVNLegacyPass, "gvn", "Global Value Numbering", false, false) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) INITIALIZE_PASS_DEPENDENCY(MemoryDependenceWrapperPass) +INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) @@ -3349,6 +3366,4 @@ INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) INITIALIZE_PASS_END(GVNLegacyPass, "gvn", "Global Value Numbering", false, false) // The public interface to this file... -FunctionPass *llvm::createGVNPass(bool NoMemDepAnalysis) { - return new GVNLegacyPass(NoMemDepAnalysis); -} +FunctionPass *llvm::createGVNPass() { return new GVNLegacyPass(); } diff --git a/llvm/test/Other/new-pm-print-pipeline.ll b/llvm/test/Other/new-pm-print-pipeline.ll index 9016473b36ba4..eb3ffe3a098dd 100644 --- a/llvm/test/Other/new-pm-print-pipeline.ll +++ b/llvm/test/Other/new-pm-print-pipeline.ll @@ -31,8 +31,8 @@ ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='function(loop-unroll<>,loop-unroll,loop-unroll)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-10 ; CHECK-10: function(loop-unroll,loop-unroll,loop-unroll) -; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='function(gvn<>,gvn,gvn)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-11 -; CHECK-11: function(gvn<>,gvn,gvn) +; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='function(gvn<>,gvn,gvn)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-11 +; CHECK-11: function(gvn<>,gvn,gvn) ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='function(early-cse<>,early-cse)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-12 ; CHECK-12: function(early-cse<>,early-cse)