Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ include/llvm/Passes/PassBuilder.h @@ -16,9 +16,11 @@ #ifndef LLVM_PASSES_PASSBUILDER_H #define LLVM_PASSES_PASSBUILDER_H +#include "llvm/ADT/Optional.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Analysis/LoopPassManager.h" #include "llvm/IR/PassManager.h" +#include namespace llvm { class StringRef; @@ -242,20 +244,36 @@ bool parseAAPipeline(AAManager &AA, StringRef PipelineText); private: - bool parseModulePassName(ModulePassManager &MPM, StringRef Name, - bool DebugLogging); - bool parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name); - bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name); - bool parseLoopPassName(LoopPassManager &LPM, StringRef Name); + /// A struct to capture parsed pass pipeline names. + struct PipelineElement { + StringRef Name; + std::vector InnerPipeline; + }; + + static Optional> + parsePipelineText(StringRef Text); + + bool parseModulePass(ModulePassManager &MPM, const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging); + bool parseCGSCCPass(CGSCCPassManager &CGPM, const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging); + bool parseFunctionPass(FunctionPassManager &FPM, const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging); + bool parseLoopPass(LoopPassManager &LPM, const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging); bool parseAAPassName(AAManager &AA, StringRef Name); - bool parseLoopPassPipeline(LoopPassManager &LPM, StringRef &PipelineText, + + bool parseLoopPassPipeline(LoopPassManager &LPM, + ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging); bool parseFunctionPassPipeline(FunctionPassManager &FPM, - StringRef &PipelineText, bool VerifyEachPass, - bool DebugLogging); - bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, StringRef &PipelineText, + ArrayRef Pipeline, + bool VerifyEachPass, bool DebugLogging); + bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, + ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging); - bool parseModulePassPipeline(ModulePassManager &MPM, StringRef &PipelineText, + bool parseModulePassPipeline(ModulePassManager &MPM, + ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging); }; } Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -277,6 +277,14 @@ if (Name.startswith("default") || Name.startswith("lto")) return DefaultAliasRegex.match(Name); + // Explicitly handle pass manager names. + if (Name == "module") + return true; + if (Name == "cgscc") + return true; + if (Name == "function") + return true; + #define MODULE_PASS(NAME, CREATE_PASS) \ if (Name == NAME) \ return true; @@ -290,6 +298,12 @@ #endif static bool isCGSCCPassName(StringRef Name) { + // Explicitly handle pass manager names. + if (Name == "cgscc") + return true; + if (Name == "function") + return true; + #define CGSCC_PASS(NAME, CREATE_PASS) \ if (Name == NAME) \ return true; @@ -302,6 +316,12 @@ } static bool isFunctionPassName(StringRef Name) { + // Explicitly handle pass manager names. + if (Name == "function") + return true; + if (Name == "loop") + return true; + #define FUNCTION_PASS(NAME, CREATE_PASS) \ if (Name == NAME) \ return true; @@ -314,6 +334,10 @@ } static bool isLoopPassName(StringRef Name) { + // Explicitly handle pass manager names. + if (Name == "loop") + return true; + #define LOOP_PASS(NAME, CREATE_PASS) \ if (Name == NAME) \ return true; @@ -325,8 +349,68 @@ return false; } -bool PassBuilder::parseModulePassName(ModulePassManager &MPM, StringRef Name, - bool DebugLogging) { +Optional> +PassBuilder::parsePipelineText(StringRef Text) { + std::vector ResultPipeline; + + SmallVector *, 4> PipelineStack = { + &ResultPipeline}; + for (;;) { + std::vector &Pipeline = *PipelineStack.back(); + size_t Pos = Text.find_first_of(",()"); + Pipeline.push_back({Text.substr(0, Pos), {}}); + + // If we have a single terminating name, we're done. + if (Pos == Text.npos) + break; + + char Sep = Text[Pos]; + Text = Text.substr(Pos + 1); + if (Sep == ',') + // Just a name ending in a comma, continue. + continue; + + if (Sep == '(') { + // Push the inner pipeline onto the stack to continue processing. + PipelineStack.push_back(&Pipeline.back().InnerPipeline); + continue; + } + + assert(Sep == ')' && "Bogus separator!"); + // When handling the close parenthesis, we greedily consume them to avoid + // empty strings in the pipeline. + do { + // If we try to pop the outer pipeline we have unbalanced parentheses. + if (PipelineStack.size() == 1) + return None; + + PipelineStack.pop_back(); + } while (Text.consume_front(")")); + + // Check if we've finished parsing. + if (Text.empty()) + break; + + // Otherwise, the end of an inner pipeline always has to be followed by + // a comma, and then we can continue. + if (!Text.consume_front(",")) + return None; + } + + if (PipelineStack.size() > 1) + // Unbalanced paretheses. + return None; + + assert(PipelineStack.back() == &ResultPipeline && + "Wrong pipeline at the bottom of the stack!"); + return {std::move(ResultPipeline)}; +} + +bool PassBuilder::parseModulePass(ModulePassManager &MPM, + const PipelineElement &E, bool VerifyEachPass, + bool DebugLogging) { + auto &Name = E.Name; + auto &InnerPipeline = E.InnerPipeline; // Manually handle aliases for pre-configured pipeline fragments. if (Name.startswith("default") || Name.startswith("lto")) { SmallVector Matches; @@ -353,6 +437,34 @@ return true; } + // Now handle complex passes like the pass managers. + if (Name == "module") { + ModulePassManager NestedMPM(DebugLogging); + if (!parseModulePassPipeline(NestedMPM, InnerPipeline, VerifyEachPass, + DebugLogging)) + return false; + MPM.addPass(std::move(NestedMPM)); + return true; + } + if (Name == "cgscc") { + CGSCCPassManager CGPM(DebugLogging); + if (!parseCGSCCPassPipeline(CGPM, InnerPipeline, VerifyEachPass, + DebugLogging)) + return false; + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM), + DebugLogging)); + return true; + } + if (Name == "function") { + FunctionPassManager FPM(DebugLogging); + if (!parseFunctionPassPipeline(FPM, InnerPipeline, VerifyEachPass, + DebugLogging)) + return false; + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + return true; + } + + // Finally expand the basic registered passes from the .inc file. #define MODULE_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ MPM.addPass(CREATE_PASS); \ @@ -374,7 +486,33 @@ return false; } -bool PassBuilder::parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name) { +bool PassBuilder::parseCGSCCPass(CGSCCPassManager &CGPM, + const PipelineElement &E, bool VerifyEachPass, + bool DebugLogging) { + auto &Name = E.Name; + auto &InnerPipeline = E.InnerPipeline; + // First handle complex passes like the pass managers. + if (Name == "cgscc") { + CGSCCPassManager NestedCGPM(DebugLogging); + if (!parseCGSCCPassPipeline(NestedCGPM, InnerPipeline, VerifyEachPass, + DebugLogging)) + return false; + // Add the nested pass manager with the appropriate adaptor. + CGPM.addPass(std::move(NestedCGPM)); + return true; + } + if (Name == "function") { + FunctionPassManager FPM(DebugLogging); + if (!parseFunctionPassPipeline(FPM, InnerPipeline, VerifyEachPass, + DebugLogging)) + return false; + // Add the nested pass manager with the appropriate adaptor. + CGPM.addPass( + createCGSCCToFunctionPassAdaptor(std::move(FPM), DebugLogging)); + return true; + } + + // Now expand the basic registered passes from the .inc file. #define CGSCC_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ CGPM.addPass(CREATE_PASS); \ @@ -396,8 +534,31 @@ return false; } -bool PassBuilder::parseFunctionPassName(FunctionPassManager &FPM, - StringRef Name) { +bool PassBuilder::parseFunctionPass(FunctionPassManager &FPM, + const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging) { + auto &Name = E.Name; + auto &InnerPipeline = E.InnerPipeline; + // First handle complex passes like the loop pass manager itself. + if (Name == "function") { + FunctionPassManager NestedFPM(DebugLogging); + if (!parseFunctionPassPipeline(NestedFPM, InnerPipeline, VerifyEachPass, + DebugLogging)) + return false; + // Add the nested pass manager with the appropriate adaptor. + FPM.addPass(std::move(NestedFPM)); + return true; + } + if (Name == "loop") { + LoopPassManager LPM(DebugLogging); + if (!parseLoopPassPipeline(LPM, InnerPipeline, VerifyEachPass, DebugLogging)) + return false; + // Add the nested pass manager with the appropriate adaptor. + FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM))); + return true; + } + + // Now expand the basic registered passes from the .inc file. #define FUNCTION_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ FPM.addPass(CREATE_PASS); \ @@ -419,7 +580,22 @@ return false; } -bool PassBuilder::parseLoopPassName(LoopPassManager &FPM, StringRef Name) { +bool PassBuilder::parseLoopPass(LoopPassManager &FPM, const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging) { + auto &Name = E.Name; + auto &InnerPipeline = E.InnerPipeline; + // First handle complex passes like the loop pass manager itself. + if (Name == "loop") { + LoopPassManager NestedLPM(DebugLogging); + if (!parseLoopPassPipeline(NestedLPM, InnerPipeline, VerifyEachPass, + DebugLogging)) + return false; + // Add the nested pass manager with the appropriate adaptor. + FPM.addPass(std::move(NestedLPM)); + return true; + } + + // Now expand the basic registered passes from the .inc file. #define LOOP_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ FPM.addPass(CREATE_PASS); \ @@ -460,148 +636,40 @@ } bool PassBuilder::parseLoopPassPipeline(LoopPassManager &LPM, - StringRef &PipelineText, + ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging) { - for (;;) { - // Parse nested pass managers by recursing. - if (PipelineText.startswith("loop(")) { - LoopPassManager NestedLPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("loop(")); - if (!parseLoopPassPipeline(NestedLPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - LPM.addPass(std::move(NestedLPM)); - } else { - // Otherwise try to parse a pass name. - size_t End = PipelineText.find_first_of(",)"); - if (!parseLoopPassName(LPM, PipelineText.substr(0, End))) - return false; - // TODO: Ideally, we would run a LoopVerifierPass() here in the - // VerifyEachPass case, but we don't have such a verifier yet. - - PipelineText = PipelineText.substr(End); - } - - if (PipelineText.empty() || PipelineText[0] == ')') - return true; - - assert(PipelineText[0] == ','); - PipelineText = PipelineText.substr(1); + for (const auto &Element : Pipeline) { + if (!parseLoopPass(LPM, Element, VerifyEachPass, DebugLogging)) + return false; + // FIXME: No verifier support for Loop passes! } + return true; } bool PassBuilder::parseFunctionPassPipeline(FunctionPassManager &FPM, - StringRef &PipelineText, + ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging) { - for (;;) { - // Parse nested pass managers by recursing. - if (PipelineText.startswith("function(")) { - FunctionPassManager NestedFPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("function(")); - if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - FPM.addPass(std::move(NestedFPM)); - } else if (PipelineText.startswith("loop(")) { - LoopPassManager NestedLPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("loop(")); - if (!parseLoopPassPipeline(NestedLPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - FPM.addPass(createFunctionToLoopPassAdaptor(std::move(NestedLPM))); - } else { - // Otherwise try to parse a pass name. - size_t End = PipelineText.find_first_of(",)"); - if (!parseFunctionPassName(FPM, PipelineText.substr(0, End))) - return false; - if (VerifyEachPass) - FPM.addPass(VerifierPass()); - - PipelineText = PipelineText.substr(End); - } - - if (PipelineText.empty() || PipelineText[0] == ')') - return true; - - assert(PipelineText[0] == ','); - PipelineText = PipelineText.substr(1); + for (const auto &Element : Pipeline) { + if (!parseFunctionPass(FPM, Element, VerifyEachPass, DebugLogging)) + return false; + if (VerifyEachPass) + FPM.addPass(VerifierPass()); } + return true; } bool PassBuilder::parseCGSCCPassPipeline(CGSCCPassManager &CGPM, - StringRef &PipelineText, + ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging) { - for (;;) { - // Parse nested pass managers by recursing. - if (PipelineText.startswith("cgscc(")) { - CGSCCPassManager NestedCGPM(DebugLogging); - - // Parse the inner pipeline into the nested manager. - PipelineText = PipelineText.substr(strlen("cgscc(")); - if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - CGPM.addPass(std::move(NestedCGPM)); - } else if (PipelineText.startswith("function(")) { - FunctionPassManager NestedFPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("function(")); - if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - CGPM.addPass( - createCGSCCToFunctionPassAdaptor(std::move(NestedFPM), DebugLogging)); - } else { - // Otherwise try to parse a pass name. - size_t End = PipelineText.find_first_of(",)"); - if (!parseCGSCCPassName(CGPM, PipelineText.substr(0, End))) - return false; - // FIXME: No verifier support for CGSCC passes! - - PipelineText = PipelineText.substr(End); - } - - if (PipelineText.empty() || PipelineText[0] == ')') - return true; - - assert(PipelineText[0] == ','); - PipelineText = PipelineText.substr(1); + for (const auto &Element : Pipeline) { + if (!parseCGSCCPass(CGPM, Element, VerifyEachPass, DebugLogging)) + return false; + // FIXME: No verifier support for CGSCC passes! } + return true; } void PassBuilder::crossRegisterProxies(LoopAnalysisManager &LAM, @@ -619,71 +687,16 @@ } bool PassBuilder::parseModulePassPipeline(ModulePassManager &MPM, - StringRef &PipelineText, + ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging) { - for (;;) { - // Parse nested pass managers by recursing. - if (PipelineText.startswith("module(")) { - ModulePassManager NestedMPM(DebugLogging); - - // Parse the inner pipeline into the nested manager. - PipelineText = PipelineText.substr(strlen("module(")); - if (!parseModulePassPipeline(NestedMPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Now add the nested manager as a module pass. - MPM.addPass(std::move(NestedMPM)); - } else if (PipelineText.startswith("cgscc(")) { - CGSCCPassManager NestedCGPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("cgscc(")); - if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM), - DebugLogging)); - } else if (PipelineText.startswith("function(")) { - FunctionPassManager NestedFPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("function(")); - if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(NestedFPM))); - } else { - // Otherwise try to parse a pass name. - size_t End = PipelineText.find_first_of(",)"); - if (!parseModulePassName(MPM, PipelineText.substr(0, End), DebugLogging)) - return false; - if (VerifyEachPass) - MPM.addPass(VerifierPass()); - - PipelineText = PipelineText.substr(End); - } - - if (PipelineText.empty() || PipelineText[0] == ')') - return true; - - assert(PipelineText[0] == ','); - PipelineText = PipelineText.substr(1); + for (const auto &Element : Pipeline) { + if (!parseModulePass(MPM, Element, VerifyEachPass, DebugLogging)) + return false; + if (VerifyEachPass) + MPM.addPass(VerifierPass()); } + return true; } // Primary pass pipeline description parsing routine. @@ -692,58 +705,27 @@ bool PassBuilder::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, bool VerifyEachPass, bool DebugLogging) { - // By default, try to parse the pipeline as-if it were within an implicit - // 'module(...)' pass pipeline. If this will parse at all, it needs to - // consume the entire string. - if (parseModulePassPipeline(MPM, PipelineText, VerifyEachPass, DebugLogging)) - return PipelineText.empty(); - - // This isn't parsable as a module pipeline, look for the end of a pass name - // and directly drop down to that layer. - StringRef FirstName = - PipelineText.substr(0, PipelineText.find_first_of(",)")); - assert(!isModulePassName(FirstName) && - "Already handled all module pipeline options."); - - // If this looks like a CGSCC pass, parse the whole thing as a CGSCC - // pipeline. - if (PipelineText.startswith("cgscc(") || isCGSCCPassName(FirstName)) { - CGSCCPassManager CGPM(DebugLogging); - if (!parseCGSCCPassPipeline(CGPM, PipelineText, VerifyEachPass, - DebugLogging) || - !PipelineText.empty()) + auto Pipeline = parsePipelineText(PipelineText); + if (!Pipeline || Pipeline->empty()) + return false; + + // If the first name isn't at the module layer, wrap the pipeline up + // automatically. + StringRef FirstName = Pipeline->front().Name; + + if (!isModulePassName(FirstName)) { + if (isCGSCCPassName(FirstName)) + Pipeline = {{"cgscc", std::move(*Pipeline)}}; + else if (isFunctionPassName(FirstName)) + Pipeline = {{"function", std::move(*Pipeline)}}; + else if (isLoopPassName(FirstName)) + Pipeline = {{"function", {{"loop", std::move(*Pipeline)}}}}; + else + // Unknown pass name! return false; - MPM.addPass( - createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM), DebugLogging)); - return true; } - // Similarly, if this looks like a Function pass, parse the whole thing as - // a Function pipelien. - if (PipelineText.startswith("function(") || isFunctionPassName(FirstName)) { - FunctionPassManager FPM(DebugLogging); - if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass, - DebugLogging) || - !PipelineText.empty()) - return false; - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - return true; - } - - // If this looks like a Loop pass, parse the whole thing as a Loop pipeline. - if (PipelineText.startswith("loop(") || isLoopPassName(FirstName)) { - LoopPassManager LPM(DebugLogging); - if (!parseLoopPassPipeline(LPM, PipelineText, VerifyEachPass, - DebugLogging) || - !PipelineText.empty()) - return false; - FunctionPassManager FPM(DebugLogging); - FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM))); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - return true; - } - - return false; + return parseModulePassPipeline(MPM, *Pipeline, VerifyEachPass, DebugLogging); } bool PassBuilder::parseAAPipeline(AAManager &AA, StringRef PipelineText) { Index: test/Other/pass-pipeline-parsing.ll =================================================================== --- test/Other/pass-pipeline-parsing.ll +++ test/Other/pass-pipeline-parsing.ll @@ -173,6 +173,10 @@ ; CHECK-NESTED-FP-LP: Finished llvm::Function pass manager run ; CHECK-NESTED-FP-LP: 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 +; CHECK-MISSING-COMMA1: unable to parse pass pipeline description define void @f() { entry: Index: test/Transforms/LoopStrengthReduce/quadradic-exit-value.ll =================================================================== --- test/Transforms/LoopStrengthReduce/quadradic-exit-value.ll +++ test/Transforms/LoopStrengthReduce/quadradic-exit-value.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -analyze -iv-users | FileCheck %s -; RUN: opt -passes='function(require),print' -S < %s 2>&1| FileCheck %s +; RUN: opt -passes='function(require,loop(print))' -S < %s 2>&1| FileCheck %s ; Provide legal integer types. target datalayout = "n8:16:32:64"