Add NoOpLoopNestPass and LOOPNEST_PASS macro

Having a NoOpLoopNestPass can ensure that only outermost loop is invoked
for a LoopNestPass with a lit test.

There are some existing passes that are implemented as LoopNestPass, but
they are still using LOOP_PASS macro.
It would be easier to identify LoopNestPasses with a LOOPNEST_PASS
macro.

Differential Revision: https://reviews.llvm.org/D113185
This commit is contained in:
Whitney Tsang 2021-11-05 15:19:56 +00:00
parent 085accea3c
commit 93421108d2
4 changed files with 109 additions and 4 deletions

View File

@ -319,6 +319,15 @@ public:
static StringRef name() { return "NoOpFunctionAnalysis"; } static StringRef name() { return "NoOpFunctionAnalysis"; }
}; };
/// No-op loop nest pass which does nothing.
struct NoOpLoopNestPass : PassInfoMixin<NoOpLoopNestPass> {
PreservedAnalyses run(LoopNest &L, LoopAnalysisManager &,
LoopStandardAnalysisResults &, LPMUpdater &) {
return PreservedAnalyses::all();
}
static StringRef name() { return "NoOpLoopNestPass"; }
};
/// No-op loop pass which does nothing. /// No-op loop pass which does nothing.
struct NoOpLoopPass : PassInfoMixin<NoOpLoopPass> { struct NoOpLoopPass : PassInfoMixin<NoOpLoopPass> {
PreservedAnalyses run(Loop &L, LoopAnalysisManager &, PreservedAnalyses run(Loop &L, LoopAnalysisManager &,
@ -378,6 +387,8 @@ PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO,
PIC->addClassToPassName(CLASS, NAME); PIC->addClassToPassName(CLASS, NAME);
#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME); PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
#define LOOPNEST_PASS(NAME, CREATE_PASS) \
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
#define LOOP_PASS(NAME, CREATE_PASS) \ #define LOOP_PASS(NAME, CREATE_PASS) \
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME); PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
#define LOOP_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \ #define LOOP_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
@ -907,6 +918,28 @@ static bool isFunctionPassName(StringRef Name, CallbacksT &Callbacks) {
return callbacksAcceptPassName<FunctionPassManager>(Name, Callbacks); return callbacksAcceptPassName<FunctionPassManager>(Name, Callbacks);
} }
template <typename CallbacksT>
static bool isLoopNestPassName(StringRef Name, CallbacksT &Callbacks,
bool &UseMemorySSA) {
UseMemorySSA = false;
// Explicitly handle custom-parsed pass names.
if (parseRepeatPassName(Name))
return true;
if (Name == "lnicm") {
UseMemorySSA = true;
return true;
}
#define LOOPNEST_PASS(NAME, CREATE_PASS) \
if (Name == NAME) \
return true;
#include "PassRegistry.def"
return callbacksAcceptPassName<LoopPassManager>(Name, Callbacks);
}
template <typename CallbacksT> template <typename CallbacksT>
static bool isLoopPassName(StringRef Name, CallbacksT &Callbacks, static bool isLoopPassName(StringRef Name, CallbacksT &Callbacks,
bool &UseMemorySSA) { bool &UseMemorySSA) {
@ -1140,6 +1173,12 @@ Error PassBuilder::parseModulePass(ModulePassManager &MPM,
MPM.addPass(createModuleToFunctionPassAdaptor(CREATE_PASS(Params.get()))); \ MPM.addPass(createModuleToFunctionPassAdaptor(CREATE_PASS(Params.get()))); \
return Error::success(); \ return Error::success(); \
} }
#define LOOPNEST_PASS(NAME, CREATE_PASS) \
if (Name == NAME) { \
MPM.addPass(createModuleToFunctionPassAdaptor( \
createFunctionToLoopPassAdaptor(CREATE_PASS, false, false))); \
return Error::success(); \
}
#define LOOP_PASS(NAME, CREATE_PASS) \ #define LOOP_PASS(NAME, CREATE_PASS) \
if (Name == NAME) { \ if (Name == NAME) { \
MPM.addPass(createModuleToFunctionPassAdaptor( \ MPM.addPass(createModuleToFunctionPassAdaptor( \
@ -1256,6 +1295,12 @@ Error PassBuilder::parseCGSCCPass(CGSCCPassManager &CGPM,
CGPM.addPass(createCGSCCToFunctionPassAdaptor(CREATE_PASS(Params.get()))); \ CGPM.addPass(createCGSCCToFunctionPassAdaptor(CREATE_PASS(Params.get()))); \
return Error::success(); \ return Error::success(); \
} }
#define LOOPNEST_PASS(NAME, CREATE_PASS) \
if (Name == NAME) { \
CGPM.addPass(createCGSCCToFunctionPassAdaptor( \
createFunctionToLoopPassAdaptor(CREATE_PASS, false, false))); \
return Error::success(); \
}
#define LOOP_PASS(NAME, CREATE_PASS) \ #define LOOP_PASS(NAME, CREATE_PASS) \
if (Name == NAME) { \ if (Name == NAME) { \
CGPM.addPass(createCGSCCToFunctionPassAdaptor( \ CGPM.addPass(createCGSCCToFunctionPassAdaptor( \
@ -1360,6 +1405,11 @@ Error PassBuilder::parseFunctionPass(FunctionPassManager &FPM,
// bool UseMemorySSA = !("canon-freeze" || "loop-predication" || // bool UseMemorySSA = !("canon-freeze" || "loop-predication" ||
// "guard-widening"); // "guard-widening");
// The risk is that it may become obsolete if we're not careful. // The risk is that it may become obsolete if we're not careful.
#define LOOPNEST_PASS(NAME, CREATE_PASS) \
if (Name == NAME) { \
FPM.addPass(createFunctionToLoopPassAdaptor(CREATE_PASS, false, false)); \
return Error::success(); \
}
#define LOOP_PASS(NAME, CREATE_PASS) \ #define LOOP_PASS(NAME, CREATE_PASS) \
if (Name == NAME) { \ if (Name == NAME) { \
FPM.addPass(createFunctionToLoopPassAdaptor(CREATE_PASS, false, false)); \ FPM.addPass(createFunctionToLoopPassAdaptor(CREATE_PASS, false, false)); \
@ -1418,6 +1468,11 @@ Error PassBuilder::parseLoopPass(LoopPassManager &LPM,
} }
// Now expand the basic registered passes from the .inc file. // Now expand the basic registered passes from the .inc file.
#define LOOPNEST_PASS(NAME, CREATE_PASS) \
if (Name == NAME) { \
LPM.addPass(CREATE_PASS); \
return Error::success(); \
}
#define LOOP_PASS(NAME, CREATE_PASS) \ #define LOOP_PASS(NAME, CREATE_PASS) \
if (Name == NAME) { \ if (Name == NAME) { \
LPM.addPass(CREATE_PASS); \ LPM.addPass(CREATE_PASS); \
@ -1545,6 +1600,10 @@ Error PassBuilder::parsePassPipeline(ModulePassManager &MPM,
} else if (isFunctionPassName(FirstName, } else if (isFunctionPassName(FirstName,
FunctionPipelineParsingCallbacks)) { FunctionPipelineParsingCallbacks)) {
Pipeline = {{"function", std::move(*Pipeline)}}; Pipeline = {{"function", std::move(*Pipeline)}};
} else if (isLoopNestPassName(FirstName, LoopPipelineParsingCallbacks,
UseMemorySSA)) {
Pipeline = {{"function", {{UseMemorySSA ? "loop-mssa" : "loop",
std::move(*Pipeline)}}}};
} else if (isLoopPassName(FirstName, LoopPipelineParsingCallbacks, } else if (isLoopPassName(FirstName, LoopPipelineParsingCallbacks,
UseMemorySSA)) { UseMemorySSA)) {
Pipeline = {{"function", {{UseMemorySSA ? "loop-mssa" : "loop", Pipeline = {{"function", {{UseMemorySSA ? "loop-mssa" : "loop",
@ -1739,6 +1798,10 @@ void PassBuilder::printPassNames(raw_ostream &OS) {
OS << "Function alias analyses:\n"; OS << "Function alias analyses:\n";
#define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS); #define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS);
#include "PassRegistry.def"
OS << "LoopNest passes:\n";
#define LOOPNEST_PASS(NAME, CREATE_PASS) printPassName(NAME, OS);
#include "PassRegistry.def" #include "PassRegistry.def"
OS << "Loop passes:\n"; OS << "Loop passes:\n";

View File

@ -452,6 +452,16 @@ FUNCTION_PASS_WITH_PARAMS("print<stack-lifetime>",
"may;must") "may;must")
#undef FUNCTION_PASS_WITH_PARAMS #undef FUNCTION_PASS_WITH_PARAMS
#ifndef LOOPNEST_PASS
#define LOOPNEST_PASS(NAME, CREATE_PASS)
#endif
LOOPNEST_PASS("lnicm", LNICMPass())
LOOPNEST_PASS("loop-flatten", LoopFlattenPass())
LOOPNEST_PASS("loop-interchange", LoopInterchangePass())
LOOPNEST_PASS("loop-unroll-and-jam", LoopUnrollAndJamPass())
LOOPNEST_PASS("no-op-loopnest", NoOpLoopNestPass())
#undef LOOPNEST_PASS
#ifndef LOOP_ANALYSIS #ifndef LOOP_ANALYSIS
#define LOOP_ANALYSIS(NAME, CREATE_PASS) #define LOOP_ANALYSIS(NAME, CREATE_PASS)
#endif #endif
@ -469,11 +479,8 @@ LOOP_PASS("canon-freeze", CanonicalizeFreezeInLoopsPass())
LOOP_PASS("dot-ddg", DDGDotPrinterPass()) LOOP_PASS("dot-ddg", DDGDotPrinterPass())
LOOP_PASS("invalidate<all>", InvalidateAllAnalysesPass()) LOOP_PASS("invalidate<all>", InvalidateAllAnalysesPass())
LOOP_PASS("licm", LICMPass()) LOOP_PASS("licm", LICMPass())
LOOP_PASS("lnicm", LNICMPass())
LOOP_PASS("loop-flatten", LoopFlattenPass())
LOOP_PASS("loop-idiom", LoopIdiomRecognizePass()) LOOP_PASS("loop-idiom", LoopIdiomRecognizePass())
LOOP_PASS("loop-instsimplify", LoopInstSimplifyPass()) LOOP_PASS("loop-instsimplify", LoopInstSimplifyPass())
LOOP_PASS("loop-interchange", LoopInterchangePass())
LOOP_PASS("loop-rotate", LoopRotatePass()) LOOP_PASS("loop-rotate", LoopRotatePass())
LOOP_PASS("no-op-loop", NoOpLoopPass()) LOOP_PASS("no-op-loop", NoOpLoopPass())
LOOP_PASS("print", PrintLoopPass(dbgs())) LOOP_PASS("print", PrintLoopPass(dbgs()))
@ -481,7 +488,6 @@ LOOP_PASS("loop-deletion", LoopDeletionPass())
LOOP_PASS("loop-simplifycfg", LoopSimplifyCFGPass()) LOOP_PASS("loop-simplifycfg", LoopSimplifyCFGPass())
LOOP_PASS("loop-reduce", LoopStrengthReducePass()) LOOP_PASS("loop-reduce", LoopStrengthReducePass())
LOOP_PASS("indvars", IndVarSimplifyPass()) LOOP_PASS("indvars", IndVarSimplifyPass())
LOOP_PASS("loop-unroll-and-jam", LoopUnrollAndJamPass())
LOOP_PASS("loop-unroll-full", LoopFullUnrollPass()) LOOP_PASS("loop-unroll-full", LoopFullUnrollPass())
LOOP_PASS("print-access-info", LoopAccessInfoPrinterPass(dbgs())) LOOP_PASS("print-access-info", LoopAccessInfoPrinterPass(dbgs()))
LOOP_PASS("print<ddg>", DDGAnalysisPrinterPass(dbgs())) LOOP_PASS("print<ddg>", DDGAnalysisPrinterPass(dbgs()))

View File

@ -0,0 +1,34 @@
; RUN: opt -disable-output -debug-pass-manager \
; RUN: -passes='no-op-loopnest' %s 2>&1 \
; RUN: | FileCheck %s
; @f()
; / \
; loop.0 loop.1
; / \ \
; loop.0.0 loop.0.1 loop.1.0
;
; CHECK: Running pass: NoOpLoopNestPass on Loop at depth 1 containing: %loop.0<header><exiting>,%loop.0.0,%loop.0.1,%loop.0.1.preheader,%loop.0.loopexit<latch>,%loop.0.0.preheader
; CHECK: Running pass: NoOpLoopNestPass on Loop at depth 1 containing: %loop.1<header>,%loop.1.bb1,%loop.1.bb2<exiting>,%loop.1.0,%loop.1.0.preheader,%loop.1.loopexit,%loop.1.backedge<latch>
; CHECK-NOT: Running pass: NoOpLoopNestPass on Loop at depth 2
define void @f() {
entry:
br label %loop.0
loop.0:
br i1 undef, label %loop.0.0, label %loop.1
loop.0.0:
br i1 undef, label %loop.0.0, label %loop.0.1
loop.0.1:
br i1 undef, label %loop.0.1, label %loop.0
loop.1:
br i1 undef, label %loop.1, label %loop.1.bb1
loop.1.bb1:
br i1 undef, label %loop.1, label %loop.1.bb2
loop.1.bb2:
br i1 undef, label %end, label %loop.1.0
loop.1.0:
br i1 undef, label %loop.1.0, label %loop.1
end:
ret void
}

View File

@ -18,6 +18,8 @@
; CHECK: no-op-function ; CHECK: no-op-function
; CHECK: Function alias analyses: ; CHECK: Function alias analyses:
; CHECK: basic-aa ; CHECK: basic-aa
; CHECK: LoopNest passes:
; CHECK: no-op-loopnest
; CHECK: Loop passes: ; CHECK: Loop passes:
; CHECK: no-op-loop ; CHECK: no-op-loop
; CHECK: Loop passes with params: ; CHECK: Loop passes with params: