diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -319,6 +319,15 @@ static StringRef name() { return "NoOpFunctionAnalysis"; } }; +/// No-op loop nest pass which does nothing. +struct NoOpLoopNestPass : PassInfoMixin { + PreservedAnalyses run(LoopNest &L, LoopAnalysisManager &, + LoopStandardAnalysisResults &, LPMUpdater &) { + return PreservedAnalyses::all(); + } + static StringRef name() { return "NoOpLoopNestPass"; } +}; + /// No-op loop pass which does nothing. struct NoOpLoopPass : PassInfoMixin { PreservedAnalyses run(Loop &L, LoopAnalysisManager &, @@ -378,6 +387,8 @@ PIC->addClassToPassName(CLASS, NAME); #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ 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) \ PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME); #define LOOP_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \ @@ -906,6 +917,28 @@ return callbacksAcceptPassName(Name, Callbacks); } +template +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(Name, Callbacks); +} + template static bool isLoopPassName(StringRef Name, CallbacksT &Callbacks, bool &UseMemorySSA) { @@ -1138,6 +1171,12 @@ MPM.addPass(createModuleToFunctionPassAdaptor(CREATE_PASS(Params.get()))); \ 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) \ if (Name == NAME) { \ MPM.addPass(createModuleToFunctionPassAdaptor( \ @@ -1253,6 +1292,12 @@ CGPM.addPass(createCGSCCToFunctionPassAdaptor(CREATE_PASS(Params.get()))); \ 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) \ if (Name == NAME) { \ CGPM.addPass(createCGSCCToFunctionPassAdaptor( \ @@ -1357,6 +1402,11 @@ // bool UseMemorySSA = !("canon-freeze" || "loop-predication" || // "guard-widening"); // 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) \ if (Name == NAME) { \ FPM.addPass(createFunctionToLoopPassAdaptor(CREATE_PASS, false, false)); \ @@ -1415,6 +1465,11 @@ } // 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) \ if (Name == NAME) { \ LPM.addPass(CREATE_PASS); \ @@ -1542,6 +1597,10 @@ } else if (isFunctionPassName(FirstName, FunctionPipelineParsingCallbacks)) { 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, UseMemorySSA)) { Pipeline = {{"function", {{UseMemorySSA ? "loop-mssa" : "loop", @@ -1736,6 +1795,10 @@ OS << "Function alias analyses:\n"; #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" OS << "Loop passes:\n"; diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -454,6 +454,16 @@ "may;must") #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 #define LOOP_ANALYSIS(NAME, CREATE_PASS) #endif @@ -471,11 +481,8 @@ LOOP_PASS("dot-ddg", DDGDotPrinterPass()) LOOP_PASS("invalidate", InvalidateAllAnalysesPass()) LOOP_PASS("licm", LICMPass()) -LOOP_PASS("lnicm", LNICMPass()) -LOOP_PASS("loop-flatten", LoopFlattenPass()) LOOP_PASS("loop-idiom", LoopIdiomRecognizePass()) LOOP_PASS("loop-instsimplify", LoopInstSimplifyPass()) -LOOP_PASS("loop-interchange", LoopInterchangePass()) LOOP_PASS("loop-rotate", LoopRotatePass()) LOOP_PASS("no-op-loop", NoOpLoopPass()) LOOP_PASS("print", PrintLoopPass(dbgs())) @@ -483,7 +490,6 @@ LOOP_PASS("loop-simplifycfg", LoopSimplifyCFGPass()) LOOP_PASS("loop-reduce", LoopStrengthReducePass()) LOOP_PASS("indvars", IndVarSimplifyPass()) -LOOP_PASS("loop-unroll-and-jam", LoopUnrollAndJamPass()) LOOP_PASS("loop-unroll-full", LoopFullUnrollPass()) LOOP_PASS("print-access-info", LoopAccessInfoPrinterPass(dbgs())) LOOP_PASS("print", DDGAnalysisPrinterPass(dbgs())) diff --git a/llvm/test/Other/loopnest-pass-ordering.ll b/llvm/test/Other/loopnest-pass-ordering.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/loopnest-pass-ordering.ll @@ -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
,%loop.0.0,%loop.0.1,%loop.0.1.preheader,%loop.0.loopexit,%loop.0.0.preheader +; CHECK: Running pass: NoOpLoopNestPass on Loop at depth 1 containing: %loop.1
,%loop.1.bb1,%loop.1.bb2,%loop.1.0,%loop.1.0.preheader,%loop.1.loopexit,%loop.1.backedge +; 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 +} diff --git a/llvm/test/Other/print-passes.ll b/llvm/test/Other/print-passes.ll --- a/llvm/test/Other/print-passes.ll +++ b/llvm/test/Other/print-passes.ll @@ -18,6 +18,8 @@ ; CHECK: no-op-function ; CHECK: Function alias analyses: ; CHECK: basic-aa +; CHECK: LoopNest passes: +; CHECK: no-op-loopnest ; CHECK: Loop passes: ; CHECK: no-op-loop ; CHECK: Loop passes with params: