Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ include/llvm/Passes/PassBuilder.h @@ -29,6 +29,10 @@ class TargetMachine; class ModuleSummaryIndex; +namespace yaml { +class Input; +} + /// A struct capturing PGO tunables. struct PGOOptions { enum PGOAction { NoAction, IRInstr, IRUse, SampleUse }; @@ -403,6 +407,35 @@ bool VerifyEachPass = true, bool DebugLogging = false); + /// This is equivalent to parsePassPipeline, but using a YAML input structured + /// as followed: + /// - name: module: + /// elements: + /// - name: function + /// elements: + /// - name: fpass1 + /// - name: fpass2 + /// - name: fpass3 + /// - name: module: + /// elements: + /// - name: cgscc + /// elements: + /// - name: cgpass1 + /// - name: cgpass2 + /// - name: cgpass3 + /// - name: module: + /// elements: + /// - name: function + /// elements: + /// - name: loop: + /// elements: + /// - name: lpass1 + /// - name: lpass2 + /// - name: lpass3 + Error parsePassPipeline(ModulePassManager &MPM, yaml::Input &PipelineYAML, + bool VerifyEachPass = true, + bool DebugLogging = false); + /// {{@ Parse a textual pass pipeline description into a specific PassManager /// /// Automatic deduction of an appropriate pass manager stack is not supported. @@ -596,6 +629,13 @@ static Optional> parsePipelineText(StringRef Text); + static Optional> + parsePipelineYAML(yaml::Input &Yin); + + Error normalizeAndParseModulePassPipleline( + ModulePassManager &MPM, + std::vector &&Pipeline, bool VerifyEachPass, + bool DebugLogging); Error parseModulePass(ModulePassManager &MPM, const PipelineElement &E, bool VerifyEachPass, bool DebugLogging); Error parseCGSCCPass(CGSCCPassManager &CGPM, const PipelineElement &E, Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -61,6 +61,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/YAMLTraits.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" @@ -1608,6 +1609,24 @@ return {std::move(ResultPipeline)}; } +LLVM_YAML_IS_SEQUENCE_VECTOR(PassBuilder::PipelineElement) + +template <> struct yaml::MappingTraits { + static void mapping(yaml::IO &io, PassBuilder::PipelineElement &PE) { + io.mapRequired("name", PE.Name); + io.mapOptional("elements", PE.InnerPipeline); + } +}; + +Optional> +PassBuilder::parsePipelineYAML(yaml::Input &Yin) { + std::vector Yang; + Yin >> Yang; + if (Yin.error()) + return None; + return {std::move(Yang)}; +} + Error PassBuilder::parseModulePass(ModulePassManager &MPM, const PipelineElement &E, bool VerifyEachPass, bool DebugLogging) { @@ -2037,37 +2056,29 @@ 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? -Error PassBuilder::parsePassPipeline(ModulePassManager &MPM, - StringRef PipelineText, - bool VerifyEachPass, bool DebugLogging) { - auto Pipeline = parsePipelineText(PipelineText); - if (!Pipeline || Pipeline->empty()) - return make_error( - formatv("invalid pipeline '{0}'", PipelineText).str(), - inconvertibleErrorCode()); - +Error PassBuilder::normalizeAndParseModulePassPipleline( + ModulePassManager &MPM, + std::vector &&Pipeline, bool VerifyEachPass, + bool DebugLogging) { // If the first name isn't at the module layer, wrap the pipeline up // automatically. - StringRef FirstName = Pipeline->front().Name; + StringRef FirstName = Pipeline.front().Name; if (!isModulePassName(FirstName, ModulePipelineParsingCallbacks)) { if (isCGSCCPassName(FirstName, CGSCCPipelineParsingCallbacks)) { - Pipeline = {{"cgscc", std::move(*Pipeline)}}; + Pipeline = {{"cgscc", std::move(Pipeline)}}; } else if (isFunctionPassName(FirstName, FunctionPipelineParsingCallbacks)) { - Pipeline = {{"function", std::move(*Pipeline)}}; + Pipeline = {{"function", std::move(Pipeline)}}; } else if (isLoopPassName(FirstName, LoopPipelineParsingCallbacks)) { - Pipeline = {{"function", {{"loop", std::move(*Pipeline)}}}}; + Pipeline = {{"function", {{"loop", std::move(Pipeline)}}}}; } else { for (auto &C : TopLevelPipelineParsingCallbacks) - if (C(MPM, *Pipeline, VerifyEachPass, DebugLogging)) + if (C(MPM, Pipeline, VerifyEachPass, DebugLogging)) return Error::success(); // Unknown pass or pipeline name! - auto &InnerPipeline = Pipeline->front().InnerPipeline; + auto &InnerPipeline = Pipeline.front().InnerPipeline; return make_error( formatv("unknown {0} name '{1}'", (InnerPipeline.empty() ? "pass" : "pipeline"), FirstName) @@ -2077,11 +2088,38 @@ } if (auto Err = - parseModulePassPipeline(MPM, *Pipeline, VerifyEachPass, DebugLogging)) + parseModulePassPipeline(MPM, Pipeline, VerifyEachPass, DebugLogging)) return Err; 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? +Error PassBuilder::parsePassPipeline(ModulePassManager &MPM, + StringRef PipelineText, + bool VerifyEachPass, bool DebugLogging) { + auto Pipeline = parsePipelineText(PipelineText); + if (!Pipeline || Pipeline->empty()) + return make_error( + formatv("invalid pipeline '{0}'", PipelineText).str(), + inconvertibleErrorCode()); + + return normalizeAndParseModulePassPipleline(MPM, std::move(*Pipeline), + VerifyEachPass, DebugLogging); +} + +Error PassBuilder::parsePassPipeline(ModulePassManager &MPM, + yaml::Input &PipelineYAML, + bool VerifyEachPass, bool DebugLogging) { + auto Pipeline = parsePipelineYAML(PipelineYAML); + if (!Pipeline || Pipeline->empty()) + return make_error("invalid YAML pipeline '{0}'", + inconvertibleErrorCode()); + return normalizeAndParseModulePassPipleline(MPM, std::move(*Pipeline), + VerifyEachPass, DebugLogging); +} + // Primary pass pipeline description parsing routine for a \c CGSCCPassManager Error PassBuilder::parsePassPipeline(CGSCCPassManager &CGPM, StringRef PipelineText, Index: test/MC/X86/intel-syntax-2.s =================================================================== --- test/MC/X86/intel-syntax-2.s +++ test/MC/X86/intel-syntax-2.s @@ -29,3 +29,8 @@ // CHECK: fdivp %st, %st(1) fdivr // CHECK: fdivrp %st, %st(1) + +_test4: +.intel_syntax +// CHECK: movl $26, -4(%rsp) + mov DWORD PTR [RSP - 4], 1ah Index: unittests/IR/PassBuilderCallbacksTest.cpp =================================================================== --- unittests/IR/PassBuilderCallbacksTest.cpp +++ unittests/IR/PassBuilderCallbacksTest.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include using namespace llvm; @@ -978,4 +979,27 @@ ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Failed()) << "Pipeline was: " << PipelineText; } + +TEST_F(ModuleCallbacksTest, YAMLSimplePipelineTest) { + StringRef PipelineYAML = R"( +- name: test-transform +)"; + yaml::Input Yin{PipelineYAML}; + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, Yin, true), Succeeded()) + << "Pipeline was: " << PipelineYAML; +} + +TEST_F(ModuleCallbacksTest, YAMLPipelineWithElementsTest) { + StringRef PipelineYAML = R"( +- name: module + elements: + - name: test-transform + - name: invalidate +)"; + + yaml::Input Yin{PipelineYAML}; + ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, Yin, true), Succeeded()) + << "Pipeline was: " << PipelineYAML; +} + } // end anonymous namespace