Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ include/llvm/Passes/PassBuilder.h @@ -19,6 +19,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/IR/PassManager.h" +#include "llvm/Support/Error.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" #include @@ -384,8 +385,9 @@ /// 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. - bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, - bool VerifyEachPass = true, bool DebugLogging = false); + Error parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, + bool VerifyEachPass = true, + bool DebugLogging = false); /// {{@ Parse a textual pass pipeline description into a specific PassManager /// @@ -394,12 +396,15 @@ /// this is the valid pipeline text: /// /// function(lpass) - bool parsePassPipeline(CGSCCPassManager &CGPM, StringRef PipelineText, - bool VerifyEachPass = true, bool DebugLogging = false); - bool parsePassPipeline(FunctionPassManager &FPM, StringRef PipelineText, - bool VerifyEachPass = true, bool DebugLogging = false); - bool parsePassPipeline(LoopPassManager &LPM, StringRef PipelineText, - bool VerifyEachPass = true, bool DebugLogging = false); + Error parsePassPipeline(CGSCCPassManager &CGPM, StringRef PipelineText, + bool VerifyEachPass = true, + bool DebugLogging = false); + Error parsePassPipeline(FunctionPassManager &FPM, StringRef PipelineText, + bool VerifyEachPass = true, + bool DebugLogging = false); + Error parsePassPipeline(LoopPassManager &LPM, StringRef PipelineText, + bool VerifyEachPass = true, + bool DebugLogging = false); /// @}} /// Parse a textual alias analysis pipeline into the provided AA manager. @@ -417,7 +422,7 @@ /// Returns false if the text cannot be parsed cleanly. The specific state of /// the \p AA manager is unspecified if such an error is encountered and this /// returns false. - bool parseAAPipeline(AAManager &AA, StringRef PipelineText); + Error parseAAPipeline(AAManager &AA, StringRef PipelineText); /// Register a callback for a default optimizer pipeline extension /// point @@ -565,28 +570,28 @@ static Optional> parsePipelineText(StringRef Text); - bool parseModulePass(ModulePassManager &MPM, const PipelineElement &E, + Error parseModulePass(ModulePassManager &MPM, const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging); + Error parseCGSCCPass(CGSCCPassManager &CGPM, const PipelineElement &E, bool VerifyEachPass, bool DebugLogging); - bool parseCGSCCPass(CGSCCPassManager &CGPM, const PipelineElement &E, + Error parseFunctionPass(FunctionPassManager &FPM, const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging); + Error parseLoopPass(LoopPassManager &LPM, 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, - ArrayRef Pipeline, - bool VerifyEachPass, bool DebugLogging); - bool parseFunctionPassPipeline(FunctionPassManager &FPM, - ArrayRef Pipeline, - bool VerifyEachPass, bool DebugLogging); - bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, + Error parseLoopPassPipeline(LoopPassManager &LPM, ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging); - bool parseModulePassPipeline(ModulePassManager &MPM, + Error parseFunctionPassPipeline(FunctionPassManager &FPM, + ArrayRef Pipeline, + bool VerifyEachPass, bool DebugLogging); + Error parseCGSCCPassPipeline(CGSCCPassManager &CGPM, ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging); + Error parseModulePassPipeline(ModulePassManager &MPM, + ArrayRef Pipeline, + bool VerifyEachPass, bool DebugLogging); void addPGOInstrPasses(ModulePassManager &MPM, bool DebugLogging, OptimizationLevel Level, bool RunProfileGen, Index: lib/LTO/LTOBackend.cpp =================================================================== --- lib/LTO/LTOBackend.cpp +++ lib/LTO/LTOBackend.cpp @@ -162,7 +162,7 @@ AAManager AA; // Parse a custom AA pipeline if asked to. - if (!PB.parseAAPipeline(AA, "default")) + if (auto Err = PB.parseAAPipeline(AA, "default")) report_fatal_error("Error parsing default AA pipeline"); LoopAnalysisManager LAM(Conf.DebugPassManager); @@ -221,9 +221,9 @@ // Parse a custom AA pipeline if asked to. if (!AAPipelineDesc.empty()) - if (!PB.parseAAPipeline(AA, AAPipelineDesc)) - report_fatal_error("unable to parse AA pipeline description: " + - AAPipelineDesc); + if (auto Err = PB.parseAAPipeline(AA, AAPipelineDesc)) + report_fatal_error("unable to parse AA pipeline description '" + + AAPipelineDesc + "': " + toString(std::move(Err))); LoopAnalysisManager LAM; FunctionAnalysisManager FAM; @@ -246,9 +246,9 @@ MPM.addPass(VerifierPass()); // Now, add all the passes we've been requested to. - if (!PB.parsePassPipeline(MPM, PipelineDesc)) - report_fatal_error("unable to parse pass pipeline description: " + - PipelineDesc); + if (auto Err = PB.parsePassPipeline(MPM, PipelineDesc)) + report_fatal_error("unable to parse pass pipeline description '" + + PipelineDesc + "': " + toString(std::move(Err))); if (!DisableVerify) MPM.addPass(VerifierPass()); Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -58,6 +58,7 @@ #include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Regex.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h" @@ -1402,9 +1403,9 @@ return {std::move(ResultPipeline)}; } -bool PassBuilder::parseModulePass(ModulePassManager &MPM, - const PipelineElement &E, bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parseModulePass(ModulePassManager &MPM, + const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging) { auto &Name = E.Name; auto &InnerPipeline = E.InnerPipeline; @@ -1412,50 +1413,56 @@ if (!InnerPipeline.empty()) { if (Name == "module") { ModulePassManager NestedMPM(DebugLogging); - if (!parseModulePassPipeline(NestedMPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseModulePassPipeline(NestedMPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; MPM.addPass(std::move(NestedMPM)); - return true; + return Error::success(); } if (Name == "cgscc") { CGSCCPassManager CGPM(DebugLogging); - if (!parseCGSCCPassPipeline(CGPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseCGSCCPassPipeline(CGPM, InnerPipeline, VerifyEachPass, + DebugLogging)) + return Err; MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); - return true; + return Error::success(); } if (Name == "function") { FunctionPassManager FPM(DebugLogging); - if (!parseFunctionPassPipeline(FPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseFunctionPassPipeline(FPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - return true; + return Error::success(); } if (auto Count = parseRepeatPassName(Name)) { ModulePassManager NestedMPM(DebugLogging); - if (!parseModulePassPipeline(NestedMPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseModulePassPipeline(NestedMPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; MPM.addPass(createRepeatedPass(*Count, std::move(NestedMPM))); - return true; + return Error::success(); } for (auto &C : ModulePipelineParsingCallbacks) if (C(Name, MPM, InnerPipeline)) - return true; + return Error::success(); // Normal passes can't have pipelines. - return false; + return make_error( + formatv("invalid use of '{0}' pass as module pipeline", Name).str(), + inconvertibleErrorCode()); + ; } // Manually handle aliases for pre-configured pipeline fragments. if (startsWithDefaultPipelineAliasPrefix(Name)) { SmallVector Matches; if (!DefaultAliasRegex.match(Name, &Matches)) - return false; + return make_error( + formatv("unknown default pipeline alias '{0}'", Name).str(), + inconvertibleErrorCode()); + assert(Matches.size() == 3 && "Must capture two matched strings!"); OptimizationLevel L = StringSwitch(Matches[2]) @@ -1467,7 +1474,7 @@ .Case("Oz", Oz); if (L == O0) // At O0 we do nothing at all! - return true; + return Error::success(); if (Matches[1] == "default") { MPM.addPass(buildPerModuleDefaultPipeline(L, DebugLogging)); @@ -1481,38 +1488,40 @@ assert(Matches[1] == "lto" && "Not one of the matched options!"); MPM.addPass(buildLTODefaultPipeline(L, DebugLogging, nullptr)); } - return true; + return Error::success(); } // Finally expand the basic registered passes from the .inc file. #define MODULE_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ MPM.addPass(CREATE_PASS); \ - return true; \ + return Error::success(); \ } #define MODULE_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ MPM.addPass( \ RequireAnalysisPass< \ std::remove_reference::type, Module>()); \ - return true; \ + return Error::success(); \ } \ if (Name == "invalidate<" NAME ">") { \ MPM.addPass(InvalidateAnalysisPass< \ std::remove_reference::type>()); \ - return true; \ + return Error::success(); \ } #include "PassRegistry.def" for (auto &C : ModulePipelineParsingCallbacks) if (C(Name, MPM, InnerPipeline)) - return true; - return false; + return Error::success(); + return make_error( + formatv("unknown module pass '{0}'", Name).str(), + inconvertibleErrorCode()); } -bool PassBuilder::parseCGSCCPass(CGSCCPassManager &CGPM, - const PipelineElement &E, bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parseCGSCCPass(CGSCCPassManager &CGPM, + const PipelineElement &E, bool VerifyEachPass, + bool DebugLogging) { auto &Name = E.Name; auto &InnerPipeline = E.InnerPipeline; @@ -1520,53 +1529,55 @@ if (!InnerPipeline.empty()) { if (Name == "cgscc") { CGSCCPassManager NestedCGPM(DebugLogging); - if (!parseCGSCCPassPipeline(NestedCGPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseCGSCCPassPipeline(NestedCGPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; // Add the nested pass manager with the appropriate adaptor. CGPM.addPass(std::move(NestedCGPM)); - return true; + return Error::success(); } if (Name == "function") { FunctionPassManager FPM(DebugLogging); - if (!parseFunctionPassPipeline(FPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseFunctionPassPipeline(FPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; // Add the nested pass manager with the appropriate adaptor. CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM))); - return true; + return Error::success(); } if (auto Count = parseRepeatPassName(Name)) { CGSCCPassManager NestedCGPM(DebugLogging); - if (!parseCGSCCPassPipeline(NestedCGPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseCGSCCPassPipeline(NestedCGPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; CGPM.addPass(createRepeatedPass(*Count, std::move(NestedCGPM))); - return true; + return Error::success(); } if (auto MaxRepetitions = parseDevirtPassName(Name)) { CGSCCPassManager NestedCGPM(DebugLogging); - if (!parseCGSCCPassPipeline(NestedCGPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseCGSCCPassPipeline(NestedCGPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; CGPM.addPass( createDevirtSCCRepeatedPass(std::move(NestedCGPM), *MaxRepetitions)); - return true; + return Error::success(); } for (auto &C : CGSCCPipelineParsingCallbacks) if (C(Name, CGPM, InnerPipeline)) - return true; + return Error::success(); // Normal passes can't have pipelines. - return false; + return make_error( + formatv("invalid use of '{0}' pass as cgscc pipeline", Name).str(), + inconvertibleErrorCode()); } // Now expand the basic registered passes from the .inc file. #define CGSCC_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ CGPM.addPass(CREATE_PASS); \ - return true; \ + return Error::success(); \ } #define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ @@ -1574,24 +1585,26 @@ std::remove_reference::type, \ LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, \ CGSCCUpdateResult &>()); \ - return true; \ + return Error::success(); \ } \ if (Name == "invalidate<" NAME ">") { \ CGPM.addPass(InvalidateAnalysisPass< \ std::remove_reference::type>()); \ - return true; \ + return Error::success(); \ } #include "PassRegistry.def" for (auto &C : CGSCCPipelineParsingCallbacks) if (C(Name, CGPM, InnerPipeline)) - return true; - return false; + return Error::success(); + return make_error( + formatv("unknown cgscc pass '{0}'", Name).str(), + inconvertibleErrorCode()); } -bool PassBuilder::parseFunctionPass(FunctionPassManager &FPM, - const PipelineElement &E, - bool VerifyEachPass, bool DebugLogging) { +Error PassBuilder::parseFunctionPass(FunctionPassManager &FPM, + const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging) { auto &Name = E.Name; auto &InnerPipeline = E.InnerPipeline; @@ -1599,68 +1612,72 @@ if (!InnerPipeline.empty()) { if (Name == "function") { FunctionPassManager NestedFPM(DebugLogging); - if (!parseFunctionPassPipeline(NestedFPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseFunctionPassPipeline(NestedFPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; // Add the nested pass manager with the appropriate adaptor. FPM.addPass(std::move(NestedFPM)); - return true; + return Error::success(); } if (Name == "loop") { LoopPassManager LPM(DebugLogging); - if (!parseLoopPassPipeline(LPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseLoopPassPipeline(LPM, InnerPipeline, VerifyEachPass, + DebugLogging)) + return Err; // Add the nested pass manager with the appropriate adaptor. FPM.addPass( createFunctionToLoopPassAdaptor(std::move(LPM), DebugLogging)); - return true; + return Error::success(); } if (auto Count = parseRepeatPassName(Name)) { FunctionPassManager NestedFPM(DebugLogging); - if (!parseFunctionPassPipeline(NestedFPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseFunctionPassPipeline(NestedFPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; FPM.addPass(createRepeatedPass(*Count, std::move(NestedFPM))); - return true; + return Error::success(); } for (auto &C : FunctionPipelineParsingCallbacks) if (C(Name, FPM, InnerPipeline)) - return true; + return Error::success(); // Normal passes can't have pipelines. - return false; + return make_error( + formatv("invalid use of '{0}' pass as function pipeline", Name).str(), + inconvertibleErrorCode()); } // Now expand the basic registered passes from the .inc file. #define FUNCTION_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ FPM.addPass(CREATE_PASS); \ - return true; \ + return Error::success(); \ } #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ FPM.addPass( \ RequireAnalysisPass< \ std::remove_reference::type, Function>()); \ - return true; \ + return Error::success(); \ } \ if (Name == "invalidate<" NAME ">") { \ FPM.addPass(InvalidateAnalysisPass< \ std::remove_reference::type>()); \ - return true; \ + return Error::success(); \ } #include "PassRegistry.def" for (auto &C : FunctionPipelineParsingCallbacks) if (C(Name, FPM, InnerPipeline)) - return true; - return false; + return Error::success(); + return make_error( + formatv("unknown function pass '{0}'", Name).str(), + inconvertibleErrorCode()); } -bool PassBuilder::parseLoopPass(LoopPassManager &LPM, const PipelineElement &E, - bool VerifyEachPass, bool DebugLogging) { +Error PassBuilder::parseLoopPass(LoopPassManager &LPM, const PipelineElement &E, + bool VerifyEachPass, bool DebugLogging) { StringRef Name = E.Name; auto &InnerPipeline = E.InnerPipeline; @@ -1668,35 +1685,37 @@ if (!InnerPipeline.empty()) { if (Name == "loop") { LoopPassManager NestedLPM(DebugLogging); - if (!parseLoopPassPipeline(NestedLPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseLoopPassPipeline(NestedLPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; // Add the nested pass manager with the appropriate adaptor. LPM.addPass(std::move(NestedLPM)); - return true; + return Error::success(); } if (auto Count = parseRepeatPassName(Name)) { LoopPassManager NestedLPM(DebugLogging); - if (!parseLoopPassPipeline(NestedLPM, InnerPipeline, VerifyEachPass, - DebugLogging)) - return false; + if (auto Err = parseLoopPassPipeline(NestedLPM, InnerPipeline, + VerifyEachPass, DebugLogging)) + return Err; LPM.addPass(createRepeatedPass(*Count, std::move(NestedLPM))); - return true; + return Error::success(); } for (auto &C : LoopPipelineParsingCallbacks) if (C(Name, LPM, InnerPipeline)) - return true; + return Error::success(); // Normal passes can't have pipelines. - return false; + return make_error( + formatv("invalid use of '{0}' pass as loop pipeline", Name).str(), + inconvertibleErrorCode()); } // Now expand the basic registered passes from the .inc file. #define LOOP_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ LPM.addPass(CREATE_PASS); \ - return true; \ + return Error::success(); \ } #define LOOP_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ @@ -1704,19 +1723,20 @@ std::remove_reference::type, Loop, \ LoopAnalysisManager, LoopStandardAnalysisResults &, \ LPMUpdater &>()); \ - return true; \ + return Error::success(); \ } \ if (Name == "invalidate<" NAME ">") { \ LPM.addPass(InvalidateAnalysisPass< \ std::remove_reference::type>()); \ - return true; \ + return Error::success(); \ } #include "PassRegistry.def" for (auto &C : LoopPipelineParsingCallbacks) if (C(Name, LPM, InnerPipeline)) - return true; - return false; + return Error::success(); + return make_error(formatv("unknown loop pass '{0}'", Name).str(), + inconvertibleErrorCode()); } bool PassBuilder::parseAAPassName(AAManager &AA, StringRef Name) { @@ -1740,41 +1760,42 @@ return false; } -bool PassBuilder::parseLoopPassPipeline(LoopPassManager &LPM, - ArrayRef Pipeline, - bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parseLoopPassPipeline(LoopPassManager &LPM, + ArrayRef Pipeline, + bool VerifyEachPass, + bool DebugLogging) { for (const auto &Element : Pipeline) { - if (!parseLoopPass(LPM, Element, VerifyEachPass, DebugLogging)) - return false; + if (auto Err = parseLoopPass(LPM, Element, VerifyEachPass, DebugLogging)) + return Err; // FIXME: No verifier support for Loop passes! } - return true; + return Error::success(); } -bool PassBuilder::parseFunctionPassPipeline(FunctionPassManager &FPM, - ArrayRef Pipeline, - bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parseFunctionPassPipeline(FunctionPassManager &FPM, + ArrayRef Pipeline, + bool VerifyEachPass, + bool DebugLogging) { for (const auto &Element : Pipeline) { - if (!parseFunctionPass(FPM, Element, VerifyEachPass, DebugLogging)) - return false; + if (auto Err = + parseFunctionPass(FPM, Element, VerifyEachPass, DebugLogging)) + return Err; if (VerifyEachPass) FPM.addPass(VerifierPass()); } - return true; + return Error::success(); } -bool PassBuilder::parseCGSCCPassPipeline(CGSCCPassManager &CGPM, - ArrayRef Pipeline, - bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parseCGSCCPassPipeline(CGSCCPassManager &CGPM, + ArrayRef Pipeline, + bool VerifyEachPass, + bool DebugLogging) { for (const auto &Element : Pipeline) { - if (!parseCGSCCPass(CGPM, Element, VerifyEachPass, DebugLogging)) - return false; + if (auto Err = parseCGSCCPass(CGPM, Element, VerifyEachPass, DebugLogging)) + return Err; // FIXME: No verifier support for CGSCC passes! } - return true; + return Error::success(); } void PassBuilder::crossRegisterProxies(LoopAnalysisManager &LAM, @@ -1790,28 +1811,30 @@ LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); }); } -bool PassBuilder::parseModulePassPipeline(ModulePassManager &MPM, - ArrayRef Pipeline, - bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parseModulePassPipeline(ModulePassManager &MPM, + ArrayRef Pipeline, + bool VerifyEachPass, + bool DebugLogging) { for (const auto &Element : Pipeline) { - if (!parseModulePass(MPM, Element, VerifyEachPass, DebugLogging)) - return false; + if (auto Err = parseModulePass(MPM, Element, VerifyEachPass, DebugLogging)) + return Err; if (VerifyEachPass) MPM.addPass(VerifierPass()); } - return true; + return Error::success(); } // Primary pass pipeline description parsing routine for a \c ModulePassManager // FIXME: Should this routine accept a TargetMachine or require the caller to // pre-populate the analysis managers with target-specific stuff? -bool PassBuilder::parsePassPipeline(ModulePassManager &MPM, - StringRef PipelineText, bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parsePassPipeline(ModulePassManager &MPM, + StringRef PipelineText, + bool VerifyEachPass, bool DebugLogging) { auto Pipeline = parsePipelineText(PipelineText); if (!Pipeline || Pipeline->empty()) - return false; + return make_error( + formatv("invalid pipeline '{0}'", PipelineText).str(), + inconvertibleErrorCode()); // If the first name isn't at the module layer, wrap the pipeline up // automatically. @@ -1828,73 +1851,106 @@ } else { for (auto &C : TopLevelPipelineParsingCallbacks) if (C(MPM, *Pipeline, VerifyEachPass, DebugLogging)) - return true; - - // Unknown pass name! - return false; + return Error::success(); + + // Unknown pass or pipeline name! + auto &InnerPipeline = Pipeline->front().InnerPipeline; + return make_error( + formatv("unknown {0} name '{1}'", + (InnerPipeline.empty() ? "pass" : "pipeline"), FirstName) + .str(), + inconvertibleErrorCode()); } } - return parseModulePassPipeline(MPM, *Pipeline, VerifyEachPass, DebugLogging); + if (auto Err = + parseModulePassPipeline(MPM, *Pipeline, VerifyEachPass, DebugLogging)) + return Err; + return Error::success(); } // Primary pass pipeline description parsing routine for a \c CGSCCPassManager -bool PassBuilder::parsePassPipeline(CGSCCPassManager &CGPM, - StringRef PipelineText, bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parsePassPipeline(CGSCCPassManager &CGPM, + StringRef PipelineText, + bool VerifyEachPass, bool DebugLogging) { auto Pipeline = parsePipelineText(PipelineText); if (!Pipeline || Pipeline->empty()) - return false; + return make_error( + formatv("invalid pipeline '{0}'", PipelineText).str(), + inconvertibleErrorCode()); StringRef FirstName = Pipeline->front().Name; if (!isCGSCCPassName(FirstName, CGSCCPipelineParsingCallbacks)) - return false; - - return parseCGSCCPassPipeline(CGPM, *Pipeline, VerifyEachPass, DebugLogging); + return make_error( + formatv("unknown cgscc pass '{0}' in pipeline '{1}'", FirstName, + PipelineText) + .str(), + inconvertibleErrorCode()); + + if (auto Err = + parseCGSCCPassPipeline(CGPM, *Pipeline, VerifyEachPass, DebugLogging)) + return Err; + return Error::success(); } // Primary pass pipeline description parsing routine for a \c // FunctionPassManager -bool PassBuilder::parsePassPipeline(FunctionPassManager &FPM, - StringRef PipelineText, bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parsePassPipeline(FunctionPassManager &FPM, + StringRef PipelineText, + bool VerifyEachPass, bool DebugLogging) { auto Pipeline = parsePipelineText(PipelineText); if (!Pipeline || Pipeline->empty()) - return false; + return make_error( + formatv("invalid pipeline '{0}'", PipelineText).str(), + inconvertibleErrorCode()); StringRef FirstName = Pipeline->front().Name; if (!isFunctionPassName(FirstName, FunctionPipelineParsingCallbacks)) - return false; - - return parseFunctionPassPipeline(FPM, *Pipeline, VerifyEachPass, - DebugLogging); + return make_error( + formatv("unknown function pass '{0}' in pipeline '{1}'", FirstName, + PipelineText) + .str(), + inconvertibleErrorCode()); + + if (auto Err = parseFunctionPassPipeline(FPM, *Pipeline, VerifyEachPass, + DebugLogging)) + return Err; + return Error::success(); } // Primary pass pipeline description parsing routine for a \c LoopPassManager -bool PassBuilder::parsePassPipeline(LoopPassManager &CGPM, - StringRef PipelineText, bool VerifyEachPass, - bool DebugLogging) { +Error PassBuilder::parsePassPipeline(LoopPassManager &CGPM, + StringRef PipelineText, + bool VerifyEachPass, bool DebugLogging) { auto Pipeline = parsePipelineText(PipelineText); if (!Pipeline || Pipeline->empty()) - return false; + return make_error( + formatv("invalid pipeline '{0}'", PipelineText).str(), + inconvertibleErrorCode()); - return parseLoopPassPipeline(CGPM, *Pipeline, VerifyEachPass, DebugLogging); + if (auto Err = + parseLoopPassPipeline(CGPM, *Pipeline, VerifyEachPass, DebugLogging)) + return Err; + + return Error::success(); } -bool PassBuilder::parseAAPipeline(AAManager &AA, StringRef PipelineText) { +Error PassBuilder::parseAAPipeline(AAManager &AA, StringRef PipelineText) { // If the pipeline just consists of the word 'default' just replace the AA // manager with our default one. if (PipelineText == "default") { AA = buildDefaultAAPipeline(); - return true; + return Error::success(); } while (!PipelineText.empty()) { StringRef Name; std::tie(Name, PipelineText) = PipelineText.split(','); if (!parseAAPassName(AA, Name)) - return false; + return make_error( + formatv("unknown alias analysis name '{0}'", Name).str(), + inconvertibleErrorCode()); } - return true; + return Error::success(); } Index: test/Other/pass-pipeline-parsing.ll =================================================================== --- test/Other/pass-pipeline-parsing.ll +++ test/Other/pass-pipeline-parsing.ll @@ -54,52 +54,52 @@ ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-module)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED1 -; CHECK-UNBALANCED1: unable to parse pass pipeline description +; CHECK-UNBALANCED1: invalid pipeline 'no-op-module)' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='module(no-op-module))' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED2 -; CHECK-UNBALANCED2: unable to parse pass pipeline description +; CHECK-UNBALANCED2: invalid pipeline 'module(no-op-module))' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='module(no-op-module' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED3 -; CHECK-UNBALANCED3: unable to parse pass pipeline description +; CHECK-UNBALANCED3: invalid pipeline 'module(no-op-module' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-function)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED4 -; CHECK-UNBALANCED4: unable to parse pass pipeline description +; CHECK-UNBALANCED4: invalid pipeline 'no-op-function)' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='function(no-op-function))' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED5 -; CHECK-UNBALANCED5: unable to parse pass pipeline description +; CHECK-UNBALANCED5: invalid pipeline 'function(no-op-function))' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='function(function(no-op-function)))' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED6 -; CHECK-UNBALANCED6: unable to parse pass pipeline description +; CHECK-UNBALANCED6: invalid pipeline 'function(function(no-op-function)))' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='function(no-op-function' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED7 -; CHECK-UNBALANCED7: unable to parse pass pipeline description +; CHECK-UNBALANCED7: invalid pipeline 'function(no-op-function' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='function(function(no-op-function)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED8 -; CHECK-UNBALANCED8: unable to parse pass pipeline description +; CHECK-UNBALANCED8: invalid pipeline 'function(function(no-op-function)' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-module,)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED9 -; CHECK-UNBALANCED9: unable to parse pass pipeline description +; CHECK-UNBALANCED9: invalid pipeline 'no-op-module,)' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-function,)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED10 -; CHECK-UNBALANCED10: unable to parse pass pipeline description +; CHECK-UNBALANCED10: invalid pipeline 'no-op-function,)' ; RUN: opt -disable-output -debug-pass-manager \ ; RUN: -passes=no-op-cgscc,no-op-cgscc %s 2>&1 \ @@ -176,37 +176,86 @@ ; 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 +; CHECK-MISSING-COMMA1: invalid pipeline 'function(no-op-function)function(no-op-function)' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='function()' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-EMPTY-INNER-PIPELINE -; CHECK-EMPTY-INNER-PIPELINE: unable to parse pass pipeline description +; CHECK-EMPTY-INNER-PIPELINE: unknown function pass '' ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-module(no-op-module,whatever)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-PIPELINE-ON-MODULE-PASS -; CHECK-PIPELINE-ON-MODULE-PASS: unable to parse pass pipeline description +; CHECK-PIPELINE-ON-MODULE-PASS: invalid use of 'no-op-module' pass as module pipeline ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-cgscc(no-op-cgscc,whatever)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-PIPELINE-ON-CGSCC-PASS -; CHECK-PIPELINE-ON-CGSCC-PASS: unable to parse pass pipeline description +; CHECK-PIPELINE-ON-CGSCC-PASS: invalid use of 'no-op-cgscc' pass as cgscc pipeline ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-function(no-op-function,whatever)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-PIPELINE-ON-FUNCTION-PASS -; CHECK-PIPELINE-ON-FUNCTION-PASS: unable to parse pass pipeline description +; CHECK-PIPELINE-ON-FUNCTION-PASS: invalid use of 'no-op-function' pass as function pipeline ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-loop(no-op-loop,whatever)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-PIPELINE-ON-LOOP-PASS -; CHECK-PIPELINE-ON-LOOP-PASS: unable to parse pass pipeline description +; CHECK-PIPELINE-ON-LOOP-PASS: invalid use of 'no-op-loop' pass as loop pipeline ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-function()' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-EMPTY-PIPELINE-ON-PASS -; CHECK-EMPTY-PIPELINE-ON-PASS: unable to parse pass pipeline description +; CHECK-EMPTY-PIPELINE-ON-PASS: invalid use of 'no-op-function' pass as function pipeline + +; RUN: not opt -passes='no-op-module,bad' \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=CHECK-UNKNOWN-MODULE +; CHECK-UNKNOWN-MODULE: opt: unknown module pass 'bad' + +; RUN: not opt -passes='no-op-loop,bad' \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=CHECK-UNKNOWN-LOOP +; CHECK-UNKNOWN-LOOP: opt: unknown loop pass 'bad' + +; RUN: not opt -passes='no-op-cgscc,bad' \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=CHECK-UNKNOWN-CGSCC +; CHECK-UNKNOWN-CGSCC: opt: unknown cgscc pass 'bad' + +; RUN: not opt -passes='no-op-function,bad' \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=CHECK-UNKNOWN-FUNCTION +; RUN: not opt -passes='function(bad,pipeline,text)' \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=CHECK-UNKNOWN-FUNCTION +; RUN: not opt -passes='module(no-op-module,function(bad,pipeline,text))' \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=CHECK-UNKNOWN-FUNCTION +; RUN: not opt -passes='no-op-module,function(bad,pipeline,text)' \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=CHECK-UNKNOWN-FUNCTION +; RUN: not opt -passes='module(cgscc(function(bad,pipeline,text)))' \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=CHECK-UNKNOWN-FUNCTION +; CHECK-UNKNOWN-FUNCTION: opt: unknown function pass 'bad' + +; RUN: not opt -aa-pipeline=bad -passes=no-op-function \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=AA-PIPELINE-ERR +; AA-PIPELINE-ERR: unknown alias analysis name 'bad' +; RUN: opt -passes-ep-peephole=bad -passes=no-op-function \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=PASSES-EP-PEEPHOLE-ERR +; PASSES-EP-PEEPHOLE-ERR: Could not parse pipeline 'bad'. I'm going to ignore it. +; RUN: opt -passes-ep-late-loop-optimizations=bad -passes=no-op-function \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=PASSES-EP-LATELOOPOPT-ERR +; PASSES-EP-LATELOOPOPT-ERR: Could not parse pipeline 'bad'. I'm going to ignore it. +; RUN: opt -passes-ep-loop-optimizer-end=bad -passes=no-op-function \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=PASSES-EP-LOOPOPTEND-ERR +; PASSES-EP-LOOPOPTEND-ERR: Could not parse pipeline 'bad'. I'm going to ignore it. +; RUN: opt -passes-ep-scalar-optimizer-late=bad -passes=no-op-function \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=PASSES-EP-SCALAROPTLATE-ERR +; PASSES-EP-SCALAROPTLATE-ERR: Could not parse pipeline 'bad'. I'm going to ignore it. +; RUN: opt -passes-ep-cgscc-optimizer-late=bad -passes=no-op-function \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=PASSES-EP-CGSCCOPTLATE-ERR +; PASSES-EP-CGSCCOPTLATE-ERR: Could not parse pipeline 'bad'. I'm going to ignore it. +; RUN: opt -passes-ep-vectorizer-start=bad -passes=no-op-function \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=PASSES-EP-VECTORIZERSTART-ERR +; PASSES-EP-VECTORIZERSTART-ERR: Could not parse pipeline 'bad'. I'm going to ignore it. +; RUN: opt -passes-ep-pipeline-start=bad -passes=no-op-function \ +; RUN: /dev/null -disable-output 2>&1 | FileCheck %s -check-prefix=PASSES-EP-PIPELINESTART-ERR +; PASSES-EP-PIPELINESTART-ERR: Could not parse pipeline 'bad'. I'm going to ignore it. define void @f() { entry: Index: test/tools/llvm-lto2/X86/pipeline.ll =================================================================== --- test/tools/llvm-lto2/X86/pipeline.ll +++ test/tools/llvm-lto2/X86/pipeline.ll @@ -32,11 +32,11 @@ ; RUN: -r %t1.bc,patatino,px -opt-pipeline foogoo 2>&1 | \ ; RUN: FileCheck %s --check-prefix=ERR -; ERR: LLVM ERROR: unable to parse pass pipeline description: foogoo +; ERR: LLVM ERROR: unable to parse pass pipeline description 'foogoo': unknown pass name 'foogoo' ; RUN: not llvm-lto2 run %t1.bc -o %t.o \ ; RUN: -r %t1.bc,patatino,px -aa-pipeline patatino \ ; RUN: -opt-pipeline loweratomic 2>&1 | \ ; RUN: FileCheck %s --check-prefix=AAERR -; AAERR: LLVM ERROR: unable to parse AA pipeline description: patatino +; AAERR: LLVM ERROR: unable to parse AA pipeline description 'patatino': unknown alias analysis name 'patatino' Index: test/tools/llvm-opt-fuzzer/command-line.ll =================================================================== --- test/tools/llvm-opt-fuzzer/command-line.ll +++ test/tools/llvm-opt-fuzzer/command-line.ll @@ -13,7 +13,7 @@ ; Don't start with incorrect passes specified ; RUN: not llvm-opt-fuzzer %t -ignore_remaining_args=1 -mtriple x86_64 -passes no-pass 2>&1 | FileCheck -check-prefix=PIPELINE %s -; PIPELINE: can't parse pass pipeline +; PIPELINE: unknown pass name 'no-pass' ; Correct command line ; RUN: llvm-opt-fuzzer %t -ignore_remaining_args=1 -mtriple x86_64 -passes instcombine 2>&1 | FileCheck -check-prefix=CORRECT %s Index: tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp =================================================================== --- tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp +++ tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp @@ -144,9 +144,10 @@ PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - bool Ok = PB.parsePassPipeline(MPM, PassPipeline, false, false); - assert(Ok && "Should have been checked during fuzzer initialization"); - (void)Ok; // silence unused variable warning on release builds + auto Err = PB.parsePassPipeline(MPM, PassPipeline, false, false); + assert(!Err && "Should have been checked during fuzzer initialization"); + // Only fail with assert above, otherwise ignore the parsing error. + consumeError(std::move(Err)); // Run passes which we need to test // @@ -235,8 +236,8 @@ PassBuilder PB(TM.get()); ModulePassManager MPM; - if (!PB.parsePassPipeline(MPM, PassPipeline, false, false)) { - errs() << *argv[0] << ": can't parse pass pipeline\n"; + if (auto Err = PB.parsePassPipeline(MPM, PassPipeline, false, false)) { + errs() << *argv[0] << ": " << toString(std::move(Err)) << "\n"; exit(1); } Index: tools/opt/NewPMDriver.cpp =================================================================== --- tools/opt/NewPMDriver.cpp +++ tools/opt/NewPMDriver.cpp @@ -124,12 +124,12 @@ // Verify the pipeline is parseable: PassManagerT PM; - if (PB.parsePassPipeline(PM, PipelineText)) - return true; - - errs() << "Could not parse pipeline '" << PipelineText - << "'. I'm going to igore it.\n"; - return false; + if (auto Err = PB.parsePassPipeline(PM, PipelineText)) { + errs() << "Could not parse pipeline '" << PipelineText + << "'. I'm going to ignore it.\n"; + return false; + } + return true; } /// If one of the EPPipeline command line options was given, register callbacks @@ -137,50 +137,61 @@ static void registerEPCallbacks(PassBuilder &PB, bool VerifyEachPass, bool DebugLogging) { if (tryParsePipelineText(PB, PeepholeEPPipeline)) - PB.registerPeepholeEPCallback([&PB, VerifyEachPass, DebugLogging]( - FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) { - PB.parsePassPipeline(PM, PeepholeEPPipeline, VerifyEachPass, - DebugLogging); - }); + PB.registerPeepholeEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse PeepholeEP pipeline: "); + Err(PB.parsePassPipeline(PM, PeepholeEPPipeline, VerifyEachPass, + DebugLogging)); + }); if (tryParsePipelineText(PB, LateLoopOptimizationsEPPipeline)) PB.registerLateLoopOptimizationsEPCallback( [&PB, VerifyEachPass, DebugLogging]( LoopPassManager &PM, PassBuilder::OptimizationLevel Level) { - PB.parsePassPipeline(PM, LateLoopOptimizationsEPPipeline, - VerifyEachPass, DebugLogging); + ExitOnError Err("Unable to parse LateLoopOptimizationsEP pipeline: "); + Err(PB.parsePassPipeline(PM, LateLoopOptimizationsEPPipeline, + VerifyEachPass, DebugLogging)); }); if (tryParsePipelineText(PB, LoopOptimizerEndEPPipeline)) - PB.registerLoopOptimizerEndEPCallback([&PB, VerifyEachPass, DebugLogging]( - LoopPassManager &PM, PassBuilder::OptimizationLevel Level) { - PB.parsePassPipeline(PM, LoopOptimizerEndEPPipeline, VerifyEachPass, - DebugLogging); - }); + PB.registerLoopOptimizerEndEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + LoopPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse LoopOptimizerEndEP pipeline: "); + Err(PB.parsePassPipeline(PM, LoopOptimizerEndEPPipeline, + VerifyEachPass, DebugLogging)); + }); if (tryParsePipelineText(PB, ScalarOptimizerLateEPPipeline)) PB.registerScalarOptimizerLateEPCallback( [&PB, VerifyEachPass, DebugLogging]( FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) { - PB.parsePassPipeline(PM, ScalarOptimizerLateEPPipeline, - VerifyEachPass, DebugLogging); + ExitOnError Err("Unable to parse ScalarOptimizerLateEP pipeline: "); + Err(PB.parsePassPipeline(PM, ScalarOptimizerLateEPPipeline, + VerifyEachPass, DebugLogging)); }); if (tryParsePipelineText(PB, CGSCCOptimizerLateEPPipeline)) - PB.registerCGSCCOptimizerLateEPCallback([&PB, VerifyEachPass, DebugLogging]( - CGSCCPassManager &PM, PassBuilder::OptimizationLevel Level) { - PB.parsePassPipeline(PM, CGSCCOptimizerLateEPPipeline, VerifyEachPass, - DebugLogging); - }); + PB.registerCGSCCOptimizerLateEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + CGSCCPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse CGSCCOptimizerLateEP pipeline: "); + Err(PB.parsePassPipeline(PM, CGSCCOptimizerLateEPPipeline, + VerifyEachPass, DebugLogging)); + }); if (tryParsePipelineText(PB, VectorizerStartEPPipeline)) - PB.registerVectorizerStartEPCallback([&PB, VerifyEachPass, DebugLogging]( - FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) { - PB.parsePassPipeline(PM, VectorizerStartEPPipeline, VerifyEachPass, - DebugLogging); - }); + PB.registerVectorizerStartEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse VectorizerStartEP pipeline: "); + Err(PB.parsePassPipeline(PM, VectorizerStartEPPipeline, + VerifyEachPass, DebugLogging)); + }); if (tryParsePipelineText(PB, PipelineStartEPPipeline)) PB.registerPipelineStartEPCallback( [&PB, VerifyEachPass, DebugLogging](ModulePassManager &PM) { - PB.parsePassPipeline(PM, PipelineStartEPPipeline, VerifyEachPass, - DebugLogging); + ExitOnError Err("Unable to parse PipelineStartEP pipeline: "); + Err(PB.parsePassPipeline(PM, PipelineStartEPPipeline, VerifyEachPass, + DebugLogging)); }); } @@ -258,8 +269,8 @@ // Specially handle the alias analysis manager so that we can register // a custom pipeline of AA passes with it. AAManager AA; - if (!PB.parseAAPipeline(AA, AAPipeline)) { - errs() << Arg0 << ": unable to parse AA pipeline description.\n"; + if (auto Err = PB.parseAAPipeline(AA, AAPipeline)) { + errs() << Arg0 << ": " << toString(std::move(Err)) << "\n"; return false; } @@ -284,8 +295,9 @@ if (EnableDebugify) MPM.addPass(NewPMDebugifyPass()); - if (!PB.parsePassPipeline(MPM, PassPipeline, VerifyEachPass, DebugPM)) { - errs() << Arg0 << ": unable to parse pass pipeline description.\n"; + if (auto Err = + PB.parsePassPipeline(MPM, PassPipeline, VerifyEachPass, DebugPM)) { + errs() << Arg0 << ": " << toString(std::move(Err)) << "\n"; return false; } Index: unittests/IR/CMakeLists.txt =================================================================== --- unittests/IR/CMakeLists.txt +++ unittests/IR/CMakeLists.txt @@ -40,3 +40,5 @@ VerifierTest.cpp WaymarkTest.cpp ) + +target_link_libraries(IRTests PRIVATE LLVMTestingSupport) Index: unittests/IR/PassBuilderCallbacksTest.cpp =================================================================== --- unittests/IR/PassBuilderCallbacksTest.cpp +++ unittests/IR/PassBuilderCallbacksTest.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Testing/Support/Error.h" #include #include #include @@ -460,7 +461,7 @@ .WillOnce(Invoke(getAnalysisResult)); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); @@ -494,7 +495,7 @@ .InSequence(PISequence); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); @@ -525,7 +526,7 @@ .Times(0); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); @@ -537,7 +538,7 @@ .WillOnce(Invoke(getAnalysisResult)); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -571,7 +572,7 @@ .InSequence(PISequence); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -602,7 +603,7 @@ .Times(0); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -613,7 +614,7 @@ .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -648,7 +649,7 @@ .InSequence(PISequence); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -680,7 +681,7 @@ .Times(0); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -691,7 +692,7 @@ .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -725,7 +726,7 @@ .InSequence(PISequence); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -757,7 +758,7 @@ .Times(0); StringRef PipelineText = "test-transform"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -772,7 +773,7 @@ EXPECT_CALL(AnalysisHandle, invalidate(HasName(""), _, _)); StringRef PipelineText = "require,invalidate"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -782,7 +783,7 @@ EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _)); StringRef PipelineText = "require,invalidate"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -792,7 +793,7 @@ EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _)); StringRef PipelineText = "require,invalidate"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -803,7 +804,7 @@ StringRef PipelineText = "require,invalidate"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); } @@ -843,13 +844,13 @@ StringRef PipelineText = "another-pipeline(test-transform,invalidate)"; - ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded()) << "Pipeline was: " << PipelineText; PM.run(*M, AM); /// Test the negative case PipelineText = "another-pipeline(instcombine)"; - ASSERT_FALSE(PB.parsePassPipeline(PM, PipelineText, true)) + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Failed()) << "Pipeline was: " << PipelineText; } } // end anonymous namespace Index: unittests/Passes/CMakeLists.txt =================================================================== --- unittests/Passes/CMakeLists.txt +++ unittests/Passes/CMakeLists.txt @@ -12,6 +12,7 @@ PluginsTest.cpp ) export_executable_symbols(PluginsTests) +target_link_libraries(PluginsTests PRIVATE LLVMTestingSupport) set(LLVM_LINK_COMPONENTS) add_llvm_loadable_module(TestPlugin Index: unittests/Passes/PluginsTest.cpp =================================================================== --- unittests/Passes/PluginsTest.cpp +++ unittests/Passes/PluginsTest.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" +#include "llvm/Testing/Support/Error.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" #include "gtest/gtest.h" @@ -54,8 +55,8 @@ PassBuilder PB; ModulePassManager PM; - ASSERT_FALSE(PB.parsePassPipeline(PM, "plugin-pass")); + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, "plugin-pass"), Failed()); Plugin->registerPassBuilderCallbacks(PB); - ASSERT_TRUE(PB.parsePassPipeline(PM, "plugin-pass")); + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, "plugin-pass"), Succeeded()); }