[Polly] Add support for -polly-dump-before/after with NPM.

The new pass manager does not allow adding module passes at the
-polly-position=before-vectorizer extension point. Introduce a
DumpFunctionPass that dumps only current function. In contrast to the
legacy pass manager's -polly-dump-before, each function will be dumped
into its own file. -polly-dump-before-file is still not supported.

The DumpFunctionPass uses llvm::CloneModule to copy the current function
into a new module and then write it into a file.
This commit is contained in:
Michael Kruse 2021-08-22 20:35:14 -05:00
parent a8de667af0
commit 9cfab5e249
6 changed files with 268 additions and 6 deletions

View File

@ -16,6 +16,7 @@
#include "polly/CodeGen/PPCGCodeGeneration.h"
#include "polly/Config/config.h"
#include "polly/Support/DumpFunctionPass.h"
#include "polly/Support/DumpModulePass.h"
#include "llvm/ADT/StringRef.h"
#include <cstdlib>
@ -100,6 +101,7 @@ struct PollyForcePassLinking {
polly::createForwardOpTreeWrapperPass();
polly::createDeLICMWrapperPass();
polly::createDumpModuleWrapperPass("", true);
polly::createDumpFunctionWrapperPass("");
polly::createSimplifyWrapperPass(0);
polly::createPruneUnprofitableWrapperPass();
}

View File

@ -0,0 +1,43 @@
//===------ DumpFunctionPass.cpp --------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Write a function to a file.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_SUPPORT_DUMPFUNCTIONPASS_H
#define POLLY_SUPPORT_DUMPFUNCTIONPASS_H
#include "llvm/IR/PassManager.h"
#include <string>
namespace llvm {
class ModulePass;
} // namespace llvm
namespace polly {
llvm::FunctionPass *createDumpFunctionWrapperPass(std::string Suffix);
/// A pass that isolates a function into a new Module and writes it into a file.
struct DumpFunctionPass : llvm::PassInfoMixin<DumpFunctionPass> {
std::string Suffix;
DumpFunctionPass(std::string Suffix) : Suffix(std::move(Suffix)) {}
llvm::PreservedAnalyses run(llvm::Function &F,
llvm::FunctionAnalysisManager &AM);
};
} // namespace polly
namespace llvm {
class PassRegistry;
void initializeDumpFunctionWrapperPassPass(llvm::PassRegistry &);
} // namespace llvm
#endif /* POLLY_SUPPORT_DUMPFUNCTIONPASS_H */

View File

@ -83,6 +83,7 @@ add_llvm_pass_plugin(Polly
Support/ScopLocation.cpp
Support/ISLTools.cpp
Support/DumpModulePass.cpp
Support/DumpFunctionPass.cpp
Support/VirtualInstruction.cpp
Transform/Canonicalization.cpp
Transform/CodePreparation.cpp

View File

@ -0,0 +1,121 @@
//===------ DumpFunctionPass.cpp --------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Write a function to a file.
//
//===----------------------------------------------------------------------===//
#include "polly/Support/DumpFunctionPass.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "llvm/Transforms/IPO/StripDeadPrototypes.h"
#include "llvm/Transforms/Utils/Cloning.h"
#define DEBUG_TYPE "polly-dump-func"
using namespace llvm;
using namespace polly;
namespace {
static void runDumpFunction(llvm::Function &F, StringRef Suffix) {
StringRef FName = F.getName();
Module *M = F.getParent();
StringRef ModuleName = M->getName();
StringRef Stem = sys::path::stem(ModuleName);
std::string Dumpfile = (Twine(Stem) + "-" + FName + Suffix + ".ll").str();
LLVM_DEBUG(dbgs() << "Dumping function '" << FName << "' to '" << Dumpfile
<< "'...\n");
ValueToValueMapTy VMap;
auto ShouldCloneDefinition = [&F](const GlobalValue *GV) -> bool {
return GV == &F;
};
std::unique_ptr<Module> CM = CloneModule(*M, VMap, ShouldCloneDefinition);
LLVM_DEBUG(dbgs() << "Global DCE...\n");
{
ModuleAnalysisManager MAM;
ModulePassManager MPM;
PassInstrumentationCallbacks PIC;
MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
MPM.addPass(GlobalDCEPass());
MPM.addPass(StripDeadPrototypesPass());
MPM.run(*CM, MAM);
}
LLVM_DEBUG(dbgs() << "Write to file '" << 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;
}
CM->print(Out->os(), nullptr);
Out->keep();
LLVM_DEBUG(dbgs() << "Dump file " << Dumpfile << " written successfully\n");
}
class DumpFunctionWrapperPass : public FunctionPass {
private:
DumpFunctionWrapperPass(const DumpFunctionWrapperPass &) = delete;
const DumpFunctionWrapperPass &
operator=(const DumpFunctionWrapperPass &) = delete;
std::string Suffix;
public:
static char ID;
explicit DumpFunctionWrapperPass() : FunctionPass(ID), Suffix("-dump") {}
explicit DumpFunctionWrapperPass(std::string Suffix)
: FunctionPass(ID), Suffix(std::move(Suffix)) {}
/// @name FunctionPass interface
//@{
virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
virtual bool runOnFunction(llvm::Function &F) override {
runDumpFunction(F, Suffix);
return false;
}
//@}
};
char DumpFunctionWrapperPass::ID;
} // namespace
FunctionPass *polly::createDumpFunctionWrapperPass(std::string Suffix) {
return new DumpFunctionWrapperPass(std::move(Suffix));
}
llvm::PreservedAnalyses DumpFunctionPass::run(Function &F,
FunctionAnalysisManager &AM) {
runDumpFunction(F, Suffix);
return PreservedAnalyses::all();
}
INITIALIZE_PASS_BEGIN(DumpFunctionWrapperPass, "polly-dump-function",
"Polly - Dump Function", false, false)
INITIALIZE_PASS_END(DumpFunctionWrapperPass, "polly-dump-function",
"Polly - Dump Function", false, false)

View File

@ -36,6 +36,7 @@
#include "polly/ScopDetection.h"
#include "polly/ScopInfo.h"
#include "polly/Simplify.h"
#include "polly/Support/DumpFunctionPass.h"
#include "polly/Support/DumpModulePass.h"
#include "llvm/Analysis/CFGPrinter.h"
#include "llvm/IR/LegacyPassManager.h"
@ -610,19 +611,19 @@ static void buildLatePollyPipeline(FunctionPassManager &PM,
return;
if (DumpBefore)
report_fatal_error("Option -polly-dump-before not supported with NPM",
false);
PM.addPass(DumpFunctionPass("-before"));
if (!DumpBeforeFile.empty())
report_fatal_error("Option -polly-dump-before-file not supported with NPM",
report_fatal_error("Option -polly-dump-before-file at -polly-position=late "
"not supported with NPM",
false);
buildCommonPollyPipeline(PM, Level, EnableForOpt);
if (DumpAfter)
report_fatal_error("Option -polly-dump-after not supported with NPM",
false);
PM.addPass(DumpFunctionPass("-after"));
if (!DumpAfterFile.empty())
report_fatal_error("Option -polly-dump-after-file not supported with NPM",
report_fatal_error("Option -polly-dump-after-file at -polly-position=late "
"not supported with NPM",
false);
}

View File

@ -0,0 +1,94 @@
; New pass manager
; RUN: opt %loadPolly -enable-new-pm=1 -O3 -polly -polly-position=before-vectorizer -polly-dump-before --disable-output %s
; RUN: FileCheck --input-file=dumpfunction-callee-before.ll --check-prefix=CHECK --check-prefix=CALLEE %s
; RUN: FileCheck --input-file=dumpfunction-caller-before.ll --check-prefix=CHECK --check-prefix=CALLER %s
;
; RUN: opt %loadPolly -enable-new-pm=1 -O3 -polly -polly-position=before-vectorizer -polly-dump-after --disable-output %s
; RUN: FileCheck --input-file=dumpfunction-callee-before.ll --check-prefix=CHECK --check-prefix=CALLEE %s
; RUN: FileCheck --input-file=dumpfunction-caller-before.ll --check-prefix=CHECK --check-prefix=CALLER %s
; 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);
; }
%unrelated_type = type { i32 }
@callee_alias = dso_local unnamed_addr alias void(i32, double*, i32), void(i32, double*, i32 )* @callee
define 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_alias(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
}
declare void @unrelated_decl()
!llvm.ident = !{!8}
!8 = !{!"xyxxy"}
; CHECK-NOT: unrelated_type
; CALLEE-LABEL: @callee(
; CALLEE-NOT: @caller
; CALLEE-NOT: @unrelated_decl
; CALLER-NOT: @callee(
; CALLER-LABEL: @caller(
; CHECK-NOT: @unrelated_decl
; CHECK: xyxxy