mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
322 lines
10 KiB
C++
322 lines
10 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/Analysis.h"
|
|
#include "revng/Pipeline/ContainerFactory.h"
|
|
#include "revng/Pipeline/GenericLLVMPipe.h"
|
|
#include "revng/Pipeline/LLVMContainer.h"
|
|
#include "revng/Pipeline/Runner.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;
|
|
std::string Role = {};
|
|
};
|
|
|
|
struct AnalysisDeclaration {
|
|
std::string Type;
|
|
std::vector<std::string> UsedContainers;
|
|
std::string Name;
|
|
std::string Step;
|
|
std::string Docs;
|
|
};
|
|
|
|
struct PipeInvocation {
|
|
std::string Type;
|
|
std::vector<std::string> UsedContainers;
|
|
std::vector<std::string> Passes = {};
|
|
std::vector<std::string> EnabledWhen = {};
|
|
std::string Name = "";
|
|
};
|
|
|
|
struct ArtifactsDeclaration {
|
|
std::string Container;
|
|
std::string Kind;
|
|
std::string SingleTargetFilename;
|
|
std::string Docs;
|
|
|
|
ArtifactsDeclaration() : Container(), Kind(), SingleTargetFilename() {}
|
|
|
|
bool isValid() const {
|
|
return !Container.empty() && !Kind.empty() && !SingleTargetFilename.empty();
|
|
}
|
|
};
|
|
|
|
struct StepDeclaration {
|
|
std::string Name;
|
|
std::vector<PipeInvocation> Pipes;
|
|
std::vector<std::string> EnabledWhen = {};
|
|
ArtifactsDeclaration Artifacts = {};
|
|
std::vector<AnalysisDeclaration> Analyses = {};
|
|
};
|
|
|
|
struct BranchDeclaration {
|
|
std::string From;
|
|
std::vector<StepDeclaration> Steps;
|
|
};
|
|
|
|
struct AnalysesListDeclaration {
|
|
std::string Name;
|
|
std::vector<std::string> UsedAnalysesNames;
|
|
};
|
|
|
|
struct PipelineDeclaration {
|
|
std::string Component;
|
|
std::vector<ContainerDeclaration> Containers;
|
|
std::vector<BranchDeclaration> Branches;
|
|
std::vector<AnalysisDeclaration> Analyses = {};
|
|
std::vector<AnalysesListDeclaration> AnalysesLists = {};
|
|
};
|
|
|
|
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<PipeWrapper> KnownPipesTypes;
|
|
llvm::StringMap<AnalysisWrapper> KnownAnalysisTypes;
|
|
llvm::StringMap<std::function<std::unique_ptr<LLVMPassWrapperBase>()>>
|
|
KnownLLVMPipeTypes;
|
|
|
|
llvm::StringMap<std::string> KnownContainerRoles;
|
|
|
|
std::set<std::string> EnabledFlags;
|
|
std::optional<LoaderCallback> OnLLVMContainerCreationAction = std::nullopt;
|
|
Context *PipelineContext = nullptr;
|
|
|
|
public:
|
|
explicit Loader(Context &C) : PipelineContext(&C) {}
|
|
|
|
public:
|
|
const Context &getContext() const { return *PipelineContext; }
|
|
Context &getContext() { return *PipelineContext; }
|
|
|
|
public:
|
|
llvm::Expected<Runner> load(const BranchDeclaration &) const;
|
|
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) {
|
|
bool S = KnownContainerTypes
|
|
.try_emplace(Name, ContainerFactory::create<ContainerType>())
|
|
.second;
|
|
revng_assert(S);
|
|
}
|
|
|
|
void addContainerFactory(llvm::StringRef Name, ContainerFactory Factory) {
|
|
KnownContainerTypes.try_emplace(Name, std::move(Factory));
|
|
}
|
|
|
|
const ContainerFactory &
|
|
getContainerFactory(llvm::StringRef ContainerName) const {
|
|
return KnownContainerTypes.find(ContainerName)->second;
|
|
}
|
|
|
|
void addContainerRole(llvm::StringRef Name, llvm::StringRef Role) {
|
|
KnownContainerRoles.try_emplace(Role, Name.str());
|
|
}
|
|
|
|
const llvm::StringMap<PipeWrapper> &getPipes() const {
|
|
return KnownPipesTypes;
|
|
}
|
|
|
|
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 AnalysisType>
|
|
void registerAnalysis(llvm::StringRef Name, const AnalysisType &Analysis) {
|
|
bool S = KnownAnalysisTypes
|
|
.try_emplace(Name, AnalysisWrapper::make(Analysis, {}))
|
|
.second;
|
|
revng_assert(S);
|
|
}
|
|
|
|
template<typename PipeType>
|
|
void registerPipe(llvm::StringRef Name) {
|
|
bool S = KnownPipesTypes.try_emplace(Name, PipeWrapper::make<PipeType>({}))
|
|
.second;
|
|
revng_assert(S);
|
|
}
|
|
|
|
void registerEnabledFlags(auto &NamesRange) {
|
|
for (const auto &Name : NamesRange)
|
|
EnabledFlags.insert(Name);
|
|
}
|
|
|
|
void setLLVMPipeConfigurer(LoaderCallback CallBack) {
|
|
OnLLVMContainerCreationAction = std::move(CallBack);
|
|
}
|
|
|
|
public:
|
|
const llvm::StringMap<PipeWrapper> &getRegisteredPipes() {
|
|
return KnownPipesTypes;
|
|
}
|
|
|
|
const llvm::StringMap<AnalysisWrapper> &getRegisteredAnalyses() {
|
|
return KnownAnalysisTypes;
|
|
}
|
|
|
|
private:
|
|
llvm::Error parseSteps(Runner &Runner,
|
|
const BranchDeclaration &Declaration,
|
|
const llvm::StringMap<std::string> &ReadOnlyNames,
|
|
const llvm::StringRef Component) const;
|
|
llvm::Error
|
|
parseDeclarations(Runner &Runner,
|
|
const PipelineDeclaration &Declaration,
|
|
llvm::StringMap<std::string> &ReadOnlyNames) const;
|
|
|
|
llvm::Error
|
|
parseStepDeclaration(Runner &Runner,
|
|
const StepDeclaration &,
|
|
std::string &LastAddedStep,
|
|
const llvm::StringMap<std::string> &ReadOnlyNames,
|
|
const llvm::StringRef Component) const;
|
|
|
|
llvm::Expected<PipeWrapper>
|
|
parseInvocation(Step &Step,
|
|
const PipeInvocation &Invocation,
|
|
const llvm::StringMap<std::string> &ReadOnlyNames) const;
|
|
llvm::Expected<AnalysisWrapper>
|
|
parseAnalysis(const AnalysisDeclaration &Declaration) const;
|
|
llvm::Error
|
|
parseContainerDeclaration(Runner &Runner,
|
|
const ContainerDeclaration &,
|
|
llvm::StringMap<std::string> &ReadOnlyNames) const;
|
|
|
|
llvm::Expected<PipeWrapper>
|
|
parseLLVMPass(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, Role);
|
|
template<>
|
|
struct llvm::yaml::MappingTraits<pipeline::ContainerDeclaration> {
|
|
static void mapping(IO &TheIO, pipeline::ContainerDeclaration &Info) {
|
|
TheIO.mapRequired("Name", Info.Name);
|
|
TheIO.mapRequired("Type", Info.Type);
|
|
TheIO.mapOptional("Role", Info.Role);
|
|
}
|
|
};
|
|
|
|
INTROSPECTION_NS(pipeline, AnalysesListDeclaration, Name, UsedAnalysesNames);
|
|
template<>
|
|
struct llvm::yaml::MappingTraits<pipeline::AnalysesListDeclaration> {
|
|
static void mapping(IO &TheIO, pipeline::AnalysesListDeclaration &Info) {
|
|
TheIO.mapRequired("Name", Info.Name);
|
|
TheIO.mapOptional("Analyses", Info.UsedAnalysesNames);
|
|
}
|
|
};
|
|
|
|
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);
|
|
TheIO.mapOptional("Name", Info.Name);
|
|
}
|
|
};
|
|
|
|
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);
|
|
TheIO.mapOptional("Analyses", Info.Analyses);
|
|
}
|
|
};
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::StepDeclaration)
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::AnalysisDeclaration)
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::BranchDeclaration)
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(pipeline::AnalysesListDeclaration)
|
|
|
|
template<>
|
|
struct llvm::yaml::MappingTraits<pipeline::PipelineDeclaration> {
|
|
static void mapping(IO &TheIO, pipeline::PipelineDeclaration &Info) {
|
|
TheIO.mapRequired("Component", Info.Component);
|
|
TheIO.mapOptional("Containers", Info.Containers);
|
|
TheIO.mapOptional("Branches", Info.Branches);
|
|
TheIO.mapOptional("Analyses", Info.Analyses);
|
|
TheIO.mapOptional("AnalysesLists", Info.AnalysesLists);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct llvm::yaml::MappingTraits<pipeline::BranchDeclaration> {
|
|
static void mapping(IO &TheIO, pipeline::BranchDeclaration &Info) {
|
|
TheIO.mapOptional("From", Info.From);
|
|
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);
|
|
TheIO.mapRequired("Docs", Info.Docs);
|
|
TheIO.mapRequired("SingleTargetFilename", Info.SingleTargetFilename);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct llvm::yaml::MappingTraits<pipeline::AnalysisDeclaration> {
|
|
static void mapping(IO &TheIO, pipeline::AnalysisDeclaration &Info) {
|
|
TheIO.mapRequired("Name", Info.Name);
|
|
TheIO.mapRequired("Type", Info.Type);
|
|
TheIO.mapOptional("Step", Info.Step);
|
|
TheIO.mapOptional("Docs", Info.Docs);
|
|
TheIO.mapRequired("UsedContainers", Info.UsedContainers);
|
|
}
|
|
};
|