diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h --- a/llvm/include/llvm/Passes/PassBuilder.h +++ b/llvm/include/llvm/Passes/PassBuilder.h @@ -472,10 +472,21 @@ /// module(function(loop(lpass1,lpass2,lpass3))) /// /// This shortcut is especially useful for debugging and testing small pass - /// combinations. Note that these shortcuts don't introduce any other magic. - /// If the sequence of passes aren't all the exact same kind of pass, it will - /// be an error. You cannot mix different levels implicitly, you must - /// explicitly form a pass manager in which to nest passes. + /// combinations. + /// + /// The sequence of passes aren't necessarily the exact same kind of pass. + /// You can mix different levels implicitly if adaptor passes are defined to + /// make them work. For example, + /// + /// mpass1,fpass1,fpass2,mpass2,lpass1 + /// + /// This pipeline uses only one pass manager: the top-level module manager. + /// fpass1,fpass2 and lpass1 are added into the the top-level module manager + /// using only adaptor passes. No nested function/loop pass managers are + /// added. The purpose is to allow easy pass testing when the user + /// specifically want the pass to run under a adaptor directly. This is + /// preferred when a pipeline is largely of one type, but one or just a few + /// passes are of different types(See PassBuilder.cpp for examples). Error parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, bool VerifyEachPass = true, bool DebugLogging = false); 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 @@ -2198,6 +2198,40 @@ std::remove_reference::type>()); \ return Error::success(); \ } +#define CGSCC_PASS(NAME, CREATE_PASS) \ + if (Name == NAME) { \ + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(CREATE_PASS)); \ + return Error::success(); \ + } +#define FUNCTION_PASS(NAME, CREATE_PASS) \ + if (Name == NAME) { \ + MPM.addPass(createModuleToFunctionPassAdaptor(CREATE_PASS)); \ + return Error::success(); \ + } +#define FUNCTION_PASS_WITH_PARAMS(NAME, CREATE_PASS, PARSER) \ + if (checkParametrizedPassName(Name, NAME)) { \ + auto Params = parsePassParameters(PARSER, Name, NAME); \ + if (!Params) \ + return Params.takeError(); \ + MPM.addPass(createModuleToFunctionPassAdaptor(CREATE_PASS(Params.get()))); \ + return Error::success(); \ + } +#define LOOP_PASS(NAME, CREATE_PASS) \ + if (Name == NAME) { \ + MPM.addPass(createModuleToFunctionPassAdaptor( \ + createFunctionToLoopPassAdaptor(CREATE_PASS, false, DebugLogging))); \ + return Error::success(); \ + } +#define LOOP_PASS_WITH_PARAMS(NAME, CREATE_PASS, PARSER) \ + if (checkParametrizedPassName(Name, NAME)) { \ + auto Params = parsePassParameters(PARSER, Name, NAME); \ + if (!Params) \ + return Params.takeError(); \ + MPM.addPass( \ + createModuleToFunctionPassAdaptor(createFunctionToLoopPassAdaptor( \ + CREATE_PASS(Params.get()), false, DebugLogging))); \ + return Error::success(); \ + } #include "PassRegistry.def" for (auto &C : ModulePipelineParsingCallbacks) @@ -2281,6 +2315,35 @@ std::remove_reference::type>()); \ return Error::success(); \ } +#define FUNCTION_PASS(NAME, CREATE_PASS) \ + if (Name == NAME) { \ + CGPM.addPass(createCGSCCToFunctionPassAdaptor(CREATE_PASS)); \ + return Error::success(); \ + } +#define FUNCTION_PASS_WITH_PARAMS(NAME, CREATE_PASS, PARSER) \ + if (checkParametrizedPassName(Name, NAME)) { \ + auto Params = parsePassParameters(PARSER, Name, NAME); \ + if (!Params) \ + return Params.takeError(); \ + CGPM.addPass(createCGSCCToFunctionPassAdaptor(CREATE_PASS(Params.get()))); \ + return Error::success(); \ + } +#define LOOP_PASS(NAME, CREATE_PASS) \ + if (Name == NAME) { \ + CGPM.addPass(createCGSCCToFunctionPassAdaptor( \ + createFunctionToLoopPassAdaptor(CREATE_PASS, false, DebugLogging))); \ + return Error::success(); \ + } +#define LOOP_PASS_WITH_PARAMS(NAME, CREATE_PASS, PARSER) \ + if (checkParametrizedPassName(Name, NAME)) { \ + auto Params = parsePassParameters(PARSER, Name, NAME); \ + if (!Params) \ + return Params.takeError(); \ + CGPM.addPass( \ + createCGSCCToFunctionPassAdaptor(createFunctionToLoopPassAdaptor( \ + CREATE_PASS(Params.get()), false, DebugLogging))); \ + return Error::success(); \ + } #include "PassRegistry.def" for (auto &C : CGSCCPipelineParsingCallbacks) @@ -2364,6 +2427,25 @@ std::remove_reference::type>()); \ return Error::success(); \ } +// FIXME: UseMemorySSA is set to false. Maybe we could do things like: +// bool UseMemorySSA = !("canon-freeze" || "loop-predication" || +// "guard-widening"); +// The risk is that it may become obsolete if we're not careful. +#define LOOP_PASS(NAME, CREATE_PASS) \ + if (Name == NAME) { \ + FPM.addPass( \ + createFunctionToLoopPassAdaptor(CREATE_PASS, false, DebugLogging)); \ + return Error::success(); \ + } +#define LOOP_PASS_WITH_PARAMS(NAME, CREATE_PASS, PARSER) \ + if (checkParametrizedPassName(Name, NAME)) { \ + auto Params = parsePassParameters(PARSER, Name, NAME); \ + if (!Params) \ + return Params.takeError(); \ + FPM.addPass(createFunctionToLoopPassAdaptor(CREATE_PASS(Params.get()), \ + false, DebugLogging)); \ + return Error::success(); \ + } #include "PassRegistry.def" for (auto &C : FunctionPipelineParsingCallbacks) diff --git a/llvm/test/Other/pass-pipeline-parsing.ll b/llvm/test/Other/pass-pipeline-parsing.ll --- a/llvm/test/Other/pass-pipeline-parsing.ll +++ b/llvm/test/Other/pass-pipeline-parsing.ll @@ -173,6 +173,37 @@ ; CHECK-NESTED-FP-LP: Finished llvm::Function pass manager run ; CHECK-NESTED-FP-LP: Finished llvm::Module pass manager run +; RUN: opt -disable-output -debug-pass-manager \ +; RUN: -passes='module(no-op-function,no-op-loop,no-op-cgscc,cgscc(no-op-function,no-op-loop),function(no-op-loop))' %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-ADAPTORS +; CHECK-ADAPTORS: Starting llvm::Module pass manager run +; CHECK-ADAPTORS: Starting llvm::Module pass manager run +; CHECK-ADAPTORS: Running pass: ModuleToFunctionPassAdaptor<{{.*}}NoOpFunctionPass> +; CHECK-ADAPTORS: Running pass: ModuleToFunctionPassAdaptor<{{.*}}FunctionToLoopPassAdaptor<{{.*}}NoOpLoopPass>{{.*}}> +; CHECK-ADAPTORS: Running pass: ModuleToPostOrderCGSCCPassAdaptor<{{.*}}NoOpCGSCCPass> +; CHECK-ADAPTORS: Running pass: ModuleToPostOrderCGSCCPassAdaptor<{{.*}}LazyCallGraph{{.*}}> +; CHECK-ADAPTORS: Starting CGSCC pass manager run +; CHECK-ADAPTORS: Running pass: CGSCCToFunctionPassAdaptor<{{.*}}NoOpFunctionPass> +; CHECK-ADAPTORS: Running pass: CGSCCToFunctionPassAdaptor<{{.*}}FunctionToLoopPassAdaptor<{{.*}}NoOpLoopPass>{{.*}}> +; CHECK-ADAPTORS: Finished CGSCC pass manager run +; CHECK-ADAPTORS: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}> +; CHECK-ADAPTORS: Starting llvm::Function pass manager run +; CHECK-ADAPTORS: Running pass: FunctionToLoopPassAdaptor<{{.*}}NoOpLoopPass> +; CHECK-ADAPTORS: Finished llvm::Function pass manager run +; CHECK-ADAPTORS: Finished llvm::Module pass manager run +; CHECK-ADAPTORS: Finished llvm::Module pass manager run + +; RUN: opt -disable-output -debug-pass-manager \ +; RUN: -passes='cgscc(print)' %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-PRINT-IN-CGSCC +; CHECK-PRINT-IN-CGSCC: Starting llvm::Module pass manager run +; CHECK-PRINT-IN-CGSCC: Running pass: ModuleToPostOrderCGSCCPassAdaptor<{{.*}}LazyCallGraph{{.*}}> +; CHECK-PRINT-IN-CGSCC: Starting CGSCC pass manager run +; CHECK-PRINT-IN-CGSCC: Running pass: CGSCCToFunctionPassAdaptor<{{.*}}PrintFunctionPass> +; CHECK-PRINT-IN-CGSCC: Finished CGSCC pass manager run +; CHECK-PRINT-IN-CGSCC: Running pass: VerifierPass +; CHECK-PRINT-IN-CGSCC: Finished llvm::Module pass manager run + ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='function(no-op-function)function(no-op-function)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-MISSING-COMMA1