Files
revng-revng/include/revng/Pipeline/Loader.h
Giacomo Vercesi 8b2da15c18 revng-pipeline: introduce artifacts
Add a new key to a Step, named Artifacts. If present, it indicates that
the step has a "default" Kind and Container that can be easily retrieved
without explicitly specifying either when producing an artifact.
2022-04-26 15:05:30 +02:00

220 lines
6.9 KiB
C++

#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <memory>
#include <optional>
#include <string>
#include <vector>
#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 Type;
std::vector<std::string> UsedContainers;
std::vector<std::string> Passes = {};
std::vector<std::string> EnabledWhen = {};
};
struct ArtifactsDeclaration {
std::string Container;
std::string Kind;
ArtifactsDeclaration() : Container(), Kind() {}
bool isValid() const { return !Container.empty() && !Kind.empty(); }
};
struct StepDeclaration {
std::string Name;
std::vector<PipeInvocation> Pipes;
std::vector<std::string> EnabledWhen = {};
ArtifactsDeclaration Artifacts = {};
};
struct PipelineDeclaration {
std::string From;
std::vector<ContainerDeclaration> Containers;
std::vector<StepDeclaration> 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<llvm::Error(const Loader &, LLVMPipe &)>;
private:
llvm::StringMap<ContainerFactory> KnownContainerTypes;
llvm::StringMap<std::function<PipeWrapper(std::vector<std::string>)>>
KnownPipesTypes;
llvm::StringMap<std::function<std::unique_ptr<LLVMPassWrapperBase>()>>
KnownLLVMPipeTypes;
std::set<std::string> EnabledFlags;
std::optional<LoaderCallback> 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<Runner> load(const PipelineDeclaration &) const;
llvm::Expected<Runner> load(llvm::ArrayRef<PipelineDeclaration>) const;
llvm::Expected<Runner> load(llvm::ArrayRef<std::string> Pipelines) const;
template<typename ContainerType>
void addDefaultConstructibleContainer(llvm::StringRef Name) {
auto [_,
inserted] = KnownContainerTypes
.try_emplace(Name, [](llvm::StringRef ContainerName) {
return std::make_unique<ContainerType>(ContainerName);
});
revng_assert(inserted);
}
void addContainerFactory(llvm::StringRef Name, ContainerFactory Factory) {
KnownContainerTypes.try_emplace(Name, std::move(Factory));
}
template<typename LLVMPass>
void registerLLVMPass(llvm::StringRef Name) {
auto [_, inserted] = KnownLLVMPipeTypes.try_emplace(Name, []() {
using Type = LLVMPassWrapper<LLVMPass>;
return std::make_unique<Type>(LLVMPass());
});
revng_assert(inserted);
}
template<typename PipeType>
void registerPipe(llvm::StringRef Name) {
const auto LambdaToEmplace = [](std::vector<std::string> CName) {
return PipeWrapper::makeWrapper<PipeType>(std::move(CName));
};
auto [_, inserted] = KnownPipesTypes.try_emplace(Name, LambdaToEmplace);
revng_assert(inserted);
}
template<typename PipeType>
void registerPipe(llvm::StringRef Name, const PipeType &Pipe) {
const auto LambdaToEmplace =
[Pipe](std::vector<std::string> 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:
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<std::unique_ptr<LLVMPassWrapperBase>>
loadPassFromName(llvm::StringRef Name) const;
bool isInvocationUsed(const std::vector<std::string> &Names) const;
};
} // namespace pipeline
INTROSPECTION_NS(pipeline, ContainerDeclaration, Name, Type);
template<>
struct llvm::yaml::MappingTraits<pipeline::ContainerDeclaration>
: public TupleLikeMappingTraits<pipeline::ContainerDeclaration> {};
LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::ContainerDeclaration)
template<>
struct llvm::yaml::MappingTraits<pipeline::PipeInvocation> {
static void mapping(IO &TheIO, pipeline::PipeInvocation &Info) {
TheIO.mapRequired("Type", Info.Type);
TheIO.mapRequired("UsedContainers", Info.UsedContainers);
TheIO.mapOptional("Passes", Info.Passes);
TheIO.mapOptional("EnabledWhen", Info.EnabledWhen);
}
};
LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::PipeInvocation)
template<>
struct llvm::yaml::MappingTraits<pipeline::StepDeclaration> {
static void mapping(IO &TheIO, pipeline::StepDeclaration &Info) {
TheIO.mapRequired("Name", Info.Name);
TheIO.mapOptional("Pipes", Info.Pipes);
TheIO.mapOptional("EnabledWhen", Info.EnabledWhen);
TheIO.mapOptional("Artifacts", Info.Artifacts);
}
};
LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::StepDeclaration)
INTROSPECTION_NS(pipeline, PipelineDeclaration, Containers, Steps);
template<>
struct llvm::yaml::MappingTraits<pipeline::PipelineDeclaration>
: public TupleLikeMappingTraits<pipeline::PipelineDeclaration> {
static void mapping(IO &TheIO, pipeline::PipelineDeclaration &Info) {
TheIO.mapOptional("From", Info.From);
TheIO.mapRequired("Containers", Info.Containers);
TheIO.mapRequired("Steps", Info.Steps);
}
};
template<>
struct llvm::yaml::MappingTraits<pipeline::ArtifactsDeclaration> {
static void mapping(IO &TheIO, pipeline::ArtifactsDeclaration &Info) {
TheIO.mapRequired("Container", Info.Container);
TheIO.mapRequired("Kind", Info.Kind);
}
};