diff --git a/polly/include/polly/LinkAllPasses.h b/polly/include/polly/LinkAllPasses.h index 78843690a3dad7..7960b4a95cd201 100644 --- a/polly/include/polly/LinkAllPasses.h +++ b/polly/include/polly/LinkAllPasses.h @@ -99,7 +99,7 @@ struct PollyForcePassLinking { polly::createFlattenSchedulePass(); polly::createForwardOpTreeWrapperPass(); polly::createDeLICMWrapperPass(); - polly::createDumpModulePass("", true); + polly::createDumpModuleWrapperPass("", true); polly::createSimplifyWrapperPass(0); polly::createPruneUnprofitableWrapperPass(); } diff --git a/polly/include/polly/Support/DumpModulePass.h b/polly/include/polly/Support/DumpModulePass.h index 8299cfde28b9f8..851ba6401d03cb 100644 --- a/polly/include/polly/Support/DumpModulePass.h +++ b/polly/include/polly/Support/DumpModulePass.h @@ -13,8 +13,10 @@ #ifndef POLLY_SUPPORT_DUMPMODULEPASS_H #define POLLY_SUPPORT_DUMPMODULEPASS_H +#include "llvm/IR/PassManager.h" +#include + namespace llvm { -class StringRef; class ModulePass; } // namespace llvm @@ -28,12 +30,25 @@ namespace polly { /// The intent of IsSuffix is to avoid the file being overwritten when /// processing multiple modules and/or with multiple dump passes in the /// pipeline. -llvm::ModulePass *createDumpModulePass(llvm::StringRef Filename, bool IsSuffix); +llvm::ModulePass *createDumpModuleWrapperPass(std::string Filename, + bool IsSuffix); + +/// A pass that prints the module into a file. +struct DumpModulePass : llvm::PassInfoMixin { + std::string Filename; + bool IsSuffix; + + DumpModulePass(std::string Filename, bool IsSuffix) + : Filename(std::move(Filename)), IsSuffix(IsSuffix) {} + + llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); +}; + } // namespace polly namespace llvm { class PassRegistry; -void initializeDumpModulePass(llvm::PassRegistry &); +void initializeDumpModuleWrapperPassPass(llvm::PassRegistry &); } // namespace llvm #endif /* POLLY_SUPPORT_DUMPMODULEPASS_H */ diff --git a/polly/lib/Support/DumpModulePass.cpp b/polly/lib/Support/DumpModulePass.cpp index e190ee672b7dd8..85f4dd39adde86 100644 --- a/polly/lib/Support/DumpModulePass.cpp +++ b/polly/lib/Support/DumpModulePass.cpp @@ -25,10 +25,34 @@ using namespace polly; namespace { -class DumpModule : public ModulePass { +static void runDumpModule(llvm::Module &M, StringRef Filename, bool IsSuffix) { + std::string Dumpfile; + if (IsSuffix) { + StringRef ModuleName = M.getName(); + StringRef Stem = sys::path::stem(ModuleName); + Dumpfile = (Twine(Stem) + Filename + ".ll").str(); + } else { + Dumpfile = Filename.str(); + } + LLVM_DEBUG(dbgs() << "Dumping module to " << Dumpfile << '\n'); + + std::unique_ptr Out; + std::error_code EC; + Out.reset(new ToolOutputFile(Dumpfile, EC, sys::fs::OF_None)); + if (EC) { + errs() << EC.message() << '\n'; + return; + } + + M.print(Out->os(), nullptr); + Out->keep(); +} + +class DumpModuleWrapperPass : public ModulePass { private: - DumpModule(const DumpModule &) = delete; - const DumpModule &operator=(const DumpModule &) = delete; + DumpModuleWrapperPass(const DumpModuleWrapperPass &) = delete; + const DumpModuleWrapperPass & + operator=(const DumpModuleWrapperPass &) = delete; std::string Filename; bool IsSuffix; @@ -39,10 +63,11 @@ class DumpModule : public ModulePass { /// This constructor is used e.g. if using opt -polly-dump-module. /// /// Provide a default suffix to not overwrite the original file. - explicit DumpModule() : ModulePass(ID), Filename("-dump"), IsSuffix(true) {} + explicit DumpModuleWrapperPass() + : ModulePass(ID), Filename("-dump"), IsSuffix(true) {} - explicit DumpModule(llvm::StringRef Filename, bool IsSuffix) - : ModulePass(ID), Filename(Filename), IsSuffix(IsSuffix) {} + explicit DumpModuleWrapperPass(std::string Filename, bool IsSuffix) + : ModulePass(ID), Filename(std::move(Filename)), IsSuffix(IsSuffix) {} /// @name ModulePass interface //@{ @@ -51,41 +76,27 @@ class DumpModule : public ModulePass { } virtual bool runOnModule(llvm::Module &M) override { - std::string Dumpfile; - if (IsSuffix) { - auto ModuleName = M.getName(); - auto Stem = sys::path::stem(ModuleName); - Dumpfile = (Twine(Stem) + Filename + ".ll").str(); - } else { - Dumpfile = Filename; - } - LLVM_DEBUG(dbgs() << "Dumping module to " << Dumpfile << '\n'); - - std::unique_ptr Out; - std::error_code EC; - Out.reset(new ToolOutputFile(Dumpfile, EC, sys::fs::OF_None)); - if (EC) { - errs() << EC.message() << '\n'; - return false; - } - - M.print(Out->os(), nullptr); - Out->keep(); - + runDumpModule(M, Filename, IsSuffix); return false; } //@} }; -char DumpModule::ID; +char DumpModuleWrapperPass::ID; } // namespace -ModulePass *polly::createDumpModulePass(llvm::StringRef Filename, - bool IsSuffix) { - return new DumpModule(Filename, IsSuffix); +ModulePass *polly::createDumpModuleWrapperPass(std::string Filename, + bool IsSuffix) { + return new DumpModuleWrapperPass(std::move(Filename), IsSuffix); +} + +llvm::PreservedAnalyses DumpModulePass::run(llvm::Module &M, + llvm::ModuleAnalysisManager &AM) { + runDumpModule(M, Filename, IsSuffix); + return PreservedAnalyses::all(); } -INITIALIZE_PASS_BEGIN(DumpModule, "polly-dump-module", "Polly - Dump Module", - false, false) -INITIALIZE_PASS_END(DumpModule, "polly-dump-module", "Polly - Dump Module", - false, false) +INITIALIZE_PASS_BEGIN(DumpModuleWrapperPass, "polly-dump-module", + "Polly - Dump Module", false, false) +INITIALIZE_PASS_END(DumpModuleWrapperPass, "polly-dump-module", + "Polly - Dump Module", false, false) diff --git a/polly/lib/Support/RegisterPasses.cpp b/polly/lib/Support/RegisterPasses.cpp index d8fe5efdd9f352..99144b87090fe0 100644 --- a/polly/lib/Support/RegisterPasses.cpp +++ b/polly/lib/Support/RegisterPasses.cpp @@ -269,7 +269,7 @@ void initializePollyPasses(PassRegistry &Registry) { initializeForwardOpTreeWrapperPassPass(Registry); initializeDeLICMWrapperPassPass(Registry); initializeSimplifyWrapperPassPass(Registry); - initializeDumpModulePass(Registry); + initializeDumpModuleWrapperPassPass(Registry); initializePruneUnprofitableWrapperPassPass(Registry); } @@ -302,10 +302,11 @@ void initializePollyPasses(PassRegistry &Registry) { static void registerPollyPasses(llvm::legacy::PassManagerBase &PM, bool EnableForOpt) { if (DumpBefore) - PM.add(polly::createDumpModulePass("-before", true)); + PM.add(polly::createDumpModuleWrapperPass("-before", true)); for (auto &Filename : DumpBeforeFile) - PM.add(polly::createDumpModulePass(Filename, false)); + PM.add(polly::createDumpModuleWrapperPass(Filename, false)); + PM.add(polly::createCodePreparationPass()); PM.add(polly::createScopDetectionWrapperPassPass()); if (PollyDetectOnly) @@ -397,9 +398,9 @@ static void registerPollyPasses(llvm::legacy::PassManagerBase &PM, PM.add(createBarrierNoopPass()); if (DumpAfter) - PM.add(polly::createDumpModulePass("-after", true)); + PM.add(polly::createDumpModuleWrapperPass("-after", true)); for (auto &Filename : DumpAfterFile) - PM.add(polly::createDumpModulePass(Filename, false)); + PM.add(polly::createDumpModuleWrapperPass(Filename, false)); if (CFGPrinter) PM.add(llvm::createCFGPrinterLegacyPassPass()); @@ -429,7 +430,6 @@ registerPollyEarlyAsPossiblePasses(const llvm::PassManagerBuilder &Builder, return; registerCanonicalicationPasses(PM); - PM.add(polly::createCodePreparationPass()); registerPollyPasses(PM, EnableForOpt); } @@ -444,7 +444,6 @@ registerPollyLoopOptimizerEndPasses(const llvm::PassManagerBuilder &Builder, if (!shouldEnablePollyForDiagnostic() && !EnableForOpt) return; - PM.add(polly::createCodePreparationPass()); registerPollyPasses(PM, EnableForOpt); if (EnableForOpt) PM.add(createCodegenCleanupPass()); @@ -461,7 +460,6 @@ registerPollyScalarOptimizerLatePasses(const llvm::PassManagerBuilder &Builder, if (!shouldEnablePollyForDiagnostic() && !EnableForOpt) return; - PM.add(polly::createCodePreparationPass()); polly::registerPollyPasses(PM, EnableForOpt); if (EnableForOpt) PM.add(createCodegenCleanupPass()); @@ -485,12 +483,6 @@ static void buildCommonPollyPipeline(FunctionPassManager &PM, // TODO add utility passes for the various command line options, once they're // ported - if (DumpBefore) - report_fatal_error("Option -polly-dump-before not supported with NPM", - false); - if (!DumpBeforeFile.empty()) - report_fatal_error("Option -polly-dump-before-file not supported with NPM", - false); if (PollyDetectOnly) { // Don't add more passes other than the ScopPassManager's detection passes. @@ -597,12 +589,16 @@ static void buildEarlyPollyPipeline(ModulePassManager &MPM, FunctionPassManager FPM = buildCanonicalicationPassesForNPM(MPM, Level); - if (DumpBefore) - report_fatal_error("Option -polly-dump-before not supported with NPM", - false); - if (!DumpBeforeFile.empty()) - report_fatal_error("Option -polly-dump-before-file not supported with NPM", - false); + if (DumpBefore || !DumpBeforeFile.empty()) { + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + + if (DumpBefore) + MPM.addPass(DumpModulePass("-before", true)); + for (auto &Filename : DumpBeforeFile) + MPM.addPass(DumpModulePass(Filename, false)); + + FPM = FunctionPassManager(); + } buildCommonPollyPipeline(FPM, Level, EnableForOpt); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); diff --git a/polly/test/Support/dumpmodule.ll b/polly/test/Support/dumpmodule.ll new file mode 100644 index 00000000000000..c3a15066c7001d --- /dev/null +++ b/polly/test/Support/dumpmodule.ll @@ -0,0 +1,80 @@ +; Legacy pass manager +; RUN: opt %loadPolly -enable-new-pm=0 -O3 -polly -polly-position=early -polly-dump-before-file=%t-legacy-early.ll --disable-output < %s && FileCheck --input-file=%t-legacy-early.ll --check-prefix=EARLY %s +; RUN: opt %loadPolly -enable-new-pm=0 -O3 -polly -polly-position=before-vectorizer -polly-dump-before-file=%t-legacy-late.ll --disable-output < %s && FileCheck --input-file=%t-legacy-late.ll --check-prefix=LATE %s +; +; New pass manager +; RUN: opt %loadPolly -enable-new-pm=1 -O3 -polly -polly-position=early -polly-dump-before-file=%t-npm-early.ll --disable-output < %s && FileCheck --input-file=%t-npm-early.ll --check-prefix=EARLY %s +; +; Check the module dumping before Polly at specific positions in the +; pass pipeline. +; +; void callee(int n, double A[], int i) { +; for (int j = 0; j < n; j += 1) +; A[i+j] = 42.0; +; } +; +; void caller(int n, double A[]) { +; for (int i = 0; i < n; i += 1) +; callee(n, A, i); +; } + + +define internal void @callee(i32 %n, double* noalias nonnull %A, i32 %i) { +entry: + br label %for + +for: + %j = phi i32 [0, %entry], [%j.inc, %inc] + %j.cmp = icmp slt i32 %j, %n + br i1 %j.cmp, label %body, label %exit + + body: + %idx = add i32 %i, %j + %arrayidx = getelementptr inbounds double, double* %A, i32 %idx + store double 42.0, double* %arrayidx + br label %inc + +inc: + %j.inc = add nuw nsw i32 %j, 1 + br label %for + +exit: + br label %return + +return: + ret void +} + + +define void @caller(i32 %n, double* noalias nonnull %A) { +entry: + br label %for + +for: + %i = phi i32 [0, %entry], [%j.inc, %inc] + %i.cmp = icmp slt i32 %i, %n + br i1 %i.cmp, label %body, label %exit + + body: + call void @callee(i32 %n, double* %A, i32 %i) + br label %inc + +inc: + %j.inc = add nuw nsw i32 %i, 1 + br label %for + +exit: + br label %return + +return: + ret void +} + + +; EARLY-LABEL: @callee( +; EARLY: store double 4.200000e+01, double* %arrayidx +; EARLY-LABEL: @caller( +; EARLY: call void @callee( + +; LATE-LABEL: @caller( +; LATE: store double 4.200000e+01, double* %arrayidx