#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/YAMLTraits.h" #include "revng/Pipeline/GenericLLVMPipe.h" #include "revng/Pipeline/LLVMContainer.h" #include "revng/Pipeline/Runner.h" #include "revng/Pipeline/SavableObject.h" #include "revng/Support/Assert.h" #include "revng/TupleTree/Introspection.h" #include "revng/TupleTree/TupleTree.h" namespace pipeline { // The following classes are used to drive the grammar of pipelines YAML files struct ContainerDeclaration { std::string Name; std::string Type; }; struct PipeInvocation { std::string Name; std::vector UsedContainers; std::vector Passes = {}; std::vector EnabledWhen = {}; }; struct StepDeclaration { std::string Name; std::vector Pipes; std::vector EnabledWhen = {}; }; struct PipelineDeclaration { std::string From; std::vector Containers; std::vector Steps; }; class PipelineContext; /// A Loader produces a pipeline runner starting from the YAML version of a /// pipeline. /// /// The loader must be configured with appropriate containers and pipes bindings /// if one wishes to register all those available one can simply use /// Registry::registerAllContainersAndPipes. class Loader { public: using LoaderCallback = std::function; private: llvm::StringMap KnownContainerTypes; llvm::StringMap)>> KnownPipesTypes; llvm::StringMap()>> KnownLLVMPipeTypes; std::set EnabledFlags; std::optional OnLLVMContainerCreationAction = std::nullopt; Context *PipelineContext; public: explicit Loader(Context &C) : PipelineContext(&C) {} public: const Context &getContext() const { return *PipelineContext; } Context &getContext() { return *PipelineContext; } public: llvm::Expected load(const PipelineDeclaration &) const; llvm::Expected load(llvm::ArrayRef) const; llvm::Expected load(llvm::ArrayRef Pipelines) const; template void addDefaultConstructibleContainer(llvm::StringRef Name) { auto [_, inserted] = KnownContainerTypes .try_emplace(Name, [](llvm::StringRef ContainerName) { return std::make_unique(ContainerName); }); revng_assert(inserted); } void addContainerFactory(llvm::StringRef Name, ContainerFactory Factory) { KnownContainerTypes.try_emplace(Name, std::move(Factory)); } template void registerLLVMPass(llvm::StringRef Name) { auto [_, inserted] = KnownLLVMPipeTypes.try_emplace(Name, []() { using Type = LLVMPassWrapper; return std::make_unique(LLVMPass()); }); revng_assert(inserted); } template void registerPipe(llvm::StringRef Name) { const auto LambdaToEmplace = [](std::vector CName) { return PipeWrapper::makeWrapper(std::move(CName)); }; auto [_, inserted] = KnownPipesTypes.try_emplace(Name, LambdaToEmplace); revng_assert(inserted); } template void registerPipe(llvm::StringRef Name, const PipeType &Pipe) { const auto LambdaToEmplace = [Pipe](std::vector ContainerNames) { return PipeWrapper(Pipe, std::move(ContainerNames)); }; auto [_, inserted] = KnownPipesTypes.try_emplace(Name, LambdaToEmplace); revng_assert(inserted); } void registerEnabledFlags(auto &NamesRange) { for (const auto &Name : NamesRange) EnabledFlags.insert(Name); } void setLLVMPipeConfigurer(LoaderCallback CallBack) { OnLLVMContainerCreationAction = std::move(CallBack); } private: void emitTerminators(Runner &Runner) const; llvm::Error parseSteps(Runner &Runner, const PipelineDeclaration &Declaration) const; llvm::Error parseDeclarations(Runner &Runner, const PipelineDeclaration &Declaration) const; llvm::Error parseStepDeclaration(Runner &Runner, const StepDeclaration &, std::string &LastAddedStep) const; llvm::Error parseInvocation(Step &Step, const PipeInvocation &Invocation) const; llvm::Error parseContainerDeclaration(Runner &Runner, const ContainerDeclaration &) const; llvm::Error parseLLVMPass(Step &Step, const PipeInvocation &Invocation) const; llvm::Expected> loadPassFromName(llvm::StringRef Name) const; bool isInvocationUsed(const std::vector &Names) const; }; } // namespace pipeline INTROSPECTION_NS(pipeline, ContainerDeclaration, Name, Type); template<> struct llvm::yaml::MappingTraits : public TupleLikeMappingTraits {}; LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::ContainerDeclaration) template<> struct llvm::yaml::MappingTraits { static void mapping(IO &io, pipeline::PipeInvocation &info) { io.mapRequired("Name", info.Name); io.mapRequired("UsedContainers", info.UsedContainers); io.mapOptional("Passes", info.Passes); io.mapOptional("EnabledWhen", info.EnabledWhen); } }; LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::PipeInvocation) template<> struct llvm::yaml::MappingTraits { static void mapping(IO &io, pipeline::StepDeclaration &info) { io.mapRequired("Name", info.Name); io.mapOptional("Pipes", info.Pipes); io.mapOptional("EnabledWhen", info.EnabledWhen); } }; LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::StepDeclaration) INTROSPECTION_NS(pipeline, PipelineDeclaration, Containers, Steps); template<> struct llvm::yaml::MappingTraits : public TupleLikeMappingTraits { static void mapping(IO &io, pipeline::PipelineDeclaration &info) { io.mapOptional("From", info.From); io.mapRequired("Containers", info.Containers); io.mapRequired("Steps", info.Steps); } };