[Polly] Add support for -polly-dump-before(-file) with the NPM.

Only supported with -polly-position=early. Unfortunately, the
extension point callpack for VectorizerStart only passes a
FunctionPassManager, making it impossible to add a module pass.
This commit is contained in:
Michael Kruse 2021-05-17 19:31:09 -05:00
parent 9f7d552cff
commit 29bef8e4e3
5 changed files with 161 additions and 59 deletions

View File

@ -99,7 +99,7 @@ struct PollyForcePassLinking {
polly::createFlattenSchedulePass();
polly::createForwardOpTreeWrapperPass();
polly::createDeLICMWrapperPass();
polly::createDumpModulePass("", true);
polly::createDumpModuleWrapperPass("", true);
polly::createSimplifyWrapperPass(0);
polly::createPruneUnprofitableWrapperPass();
}

View File

@ -13,8 +13,10 @@
#ifndef POLLY_SUPPORT_DUMPMODULEPASS_H
#define POLLY_SUPPORT_DUMPMODULEPASS_H
#include "llvm/IR/PassManager.h"
#include <string>
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<DumpModulePass> {
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 */

View File

@ -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<ToolOutputFile> 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 @@ public:
/// 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 @@ public:
}
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<ToolOutputFile> 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);
}
INITIALIZE_PASS_BEGIN(DumpModule, "polly-dump-module", "Polly - Dump Module",
false, false)
INITIALIZE_PASS_END(DumpModule, "polly-dump-module", "Polly - Dump Module",
false, false)
llvm::PreservedAnalyses DumpModulePass::run(llvm::Module &M,
llvm::ModuleAnalysisManager &AM) {
runDumpModule(M, Filename, IsSuffix);
return PreservedAnalyses::all();
}
INITIALIZE_PASS_BEGIN(DumpModuleWrapperPass, "polly-dump-module",
"Polly - Dump Module", false, false)
INITIALIZE_PASS_END(DumpModuleWrapperPass, "polly-dump-module",
"Polly - Dump Module", false, false)

View File

@ -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)));

View File

@ -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