mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
8b2da15c18
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.
241 lines
7.2 KiB
C++
241 lines
7.2 KiB
C++
/// \file Loader.cpp
|
|
/// \brief a loader is a object that acceps a serialized pipeline and yields a
|
|
/// runner object that rappresents that pipeline.
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <optional>
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Error.h"
|
|
|
|
#include "revng/Pipeline/Loader.h"
|
|
#include "revng/Pipeline/Runner.h"
|
|
|
|
using namespace pipeline;
|
|
using namespace std;
|
|
using namespace llvm;
|
|
|
|
llvm::Error Loader::parseStepDeclaration(Runner &Runner,
|
|
const StepDeclaration &Declaration,
|
|
std::string &LastAddedStep) const {
|
|
auto &JustAdded = Runner.emplaceStep(LastAddedStep, Declaration.Name);
|
|
LastAddedStep = Declaration.Name;
|
|
|
|
if (Declaration.Artifacts.isValid()) {
|
|
auto &KindName = Declaration.Artifacts.Kind;
|
|
const Kind *Kind = Runner.getKindsRegistry().find(KindName);
|
|
if (Kind == nullptr) {
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
"Artifact Kind not found");
|
|
}
|
|
if (auto Error = JustAdded.setArtifacts(Declaration.Artifacts.Container,
|
|
Kind);
|
|
!!Error) {
|
|
return Error;
|
|
}
|
|
}
|
|
|
|
for (const auto &Invocation : Declaration.Pipes) {
|
|
if (not isInvocationUsed(Invocation.EnabledWhen))
|
|
continue;
|
|
|
|
if (auto Error = parseInvocation(JustAdded, Invocation); !!Error)
|
|
return Error;
|
|
}
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
llvm::Expected<std::unique_ptr<LLVMPassWrapperBase>>
|
|
Loader::loadPassFromName(llvm::StringRef Name) const {
|
|
|
|
auto It = KnownLLVMPipeTypes.find(Name);
|
|
if (It != KnownLLVMPipeTypes.end())
|
|
return It->second();
|
|
|
|
return PureLLVMPassWrapper::create(Name);
|
|
}
|
|
|
|
llvm::Error
|
|
Loader::parseLLVMPass(Step &Step, const PipeInvocation &Invocation) const {
|
|
|
|
LLVMPipe ToInsert;
|
|
|
|
if (OnLLVMContainerCreationAction.has_value()) {
|
|
auto MaybeError = (*OnLLVMContainerCreationAction)(*this, ToInsert);
|
|
if (!!MaybeError)
|
|
return MaybeError;
|
|
}
|
|
|
|
for (const auto &PassName : Invocation.Passes) {
|
|
auto MaybePass = loadPassFromName(PassName);
|
|
if (not MaybePass)
|
|
return MaybePass.takeError();
|
|
ToInsert.addPass(std::move(*MaybePass));
|
|
}
|
|
|
|
auto Wrapper = PipeWrapper(move(ToInsert), Invocation.UsedContainers);
|
|
Step.addPipe(move(Wrapper));
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
llvm::Error
|
|
Loader::parseInvocation(Step &Step, const PipeInvocation &Invocation) const {
|
|
if (Invocation.Type == "LLVMPipe")
|
|
return parseLLVMPass(Step, Invocation);
|
|
|
|
auto It = KnownPipesTypes.find(Invocation.Type);
|
|
if (It == KnownPipesTypes.end()) {
|
|
auto *Message = "while parsing pipe invocation: No known Pipe with "
|
|
"name %s\n ";
|
|
return createStringError(inconvertibleErrorCode(),
|
|
Message,
|
|
Invocation.Type.c_str());
|
|
}
|
|
auto &Entry = It->second;
|
|
Step.addPipe(Entry(Invocation.UsedContainers));
|
|
return Error::success();
|
|
}
|
|
|
|
using BCDecl = ContainerDeclaration;
|
|
Error Loader::parseContainerDeclaration(Runner &Pipeline,
|
|
const BCDecl &Dec) const {
|
|
auto It = KnownContainerTypes.find(Dec.Type);
|
|
if (It == KnownContainerTypes.end()) {
|
|
auto *Message = "while parsing container declaration: No known container "
|
|
"with name %s\n";
|
|
return createStringError(inconvertibleErrorCode(),
|
|
Message,
|
|
Dec.Type.c_str());
|
|
}
|
|
auto &Entry = It->second;
|
|
Pipeline.addContainerFactory(Dec.Name, Entry);
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
llvm::Expected<Runner>
|
|
Loader::load(llvm::ArrayRef<std::string> Pipelines) const {
|
|
std::vector<PipelineDeclaration> Declarations(Pipelines.size());
|
|
for (size_t I = 0; I < Pipelines.size(); I++) {
|
|
yaml::Input Input(Pipelines[I]);
|
|
|
|
Input >> Declarations[I];
|
|
if (Input.error())
|
|
return createStringError(inconvertibleErrorCode(),
|
|
"Could not parse pipeline\n");
|
|
}
|
|
|
|
return load(Declarations);
|
|
}
|
|
|
|
llvm::Error Loader::parseSteps(Runner &Runner,
|
|
const PipelineDeclaration &Declaration) const {
|
|
|
|
std::string LastAddedStep = Declaration.From.empty() ? "begin" :
|
|
Declaration.From;
|
|
for (const auto &Step : Declaration.Steps) {
|
|
if (not isInvocationUsed(Step.EnabledWhen))
|
|
continue;
|
|
|
|
if (auto Error = parseStepDeclaration(Runner, Step, LastAddedStep); !!Error)
|
|
return Error;
|
|
}
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Error
|
|
Loader::parseDeclarations(Runner &Runner,
|
|
const PipelineDeclaration &Declaration) const {
|
|
for (const auto &Container : Declaration.Containers)
|
|
if (auto Error = parseContainerDeclaration(Runner, Container); !!Error)
|
|
return Error;
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
static bool
|
|
requirementsMet(llvm::ArrayRef<const PipelineDeclaration *> Scheduled,
|
|
const PipelineDeclaration &ToSchedule) {
|
|
if (ToSchedule.From.empty())
|
|
return true;
|
|
|
|
for (const auto *Declaration : Scheduled)
|
|
for (const auto &StepName : Declaration->Steps)
|
|
if (StepName.Name == ToSchedule.From)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static llvm::Error
|
|
sortPipeline(llvm::SmallVector<const PipelineDeclaration *, 2> &ToSort) {
|
|
llvm::SmallVector<const PipelineDeclaration *> Sorted;
|
|
|
|
const auto RequirementsMet = [&](const PipelineDeclaration *Declaration) {
|
|
if (not requirementsMet(Sorted, *Declaration))
|
|
return false;
|
|
|
|
Sorted.push_back(Declaration);
|
|
return true;
|
|
};
|
|
|
|
while (not ToSort.empty()) {
|
|
size_t InitialSize = ToSort.size();
|
|
llvm::erase_if(ToSort, RequirementsMet);
|
|
if (InitialSize == ToSort.size())
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
"Could not satisfy all requirements");
|
|
}
|
|
|
|
ToSort = std::move(Sorted);
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
llvm::Expected<Runner>
|
|
Loader::load(llvm::ArrayRef<PipelineDeclaration> Pipelines) const {
|
|
Runner ToReturn(*PipelineContext);
|
|
|
|
llvm::SmallVector<const PipelineDeclaration *, 2> ToSort;
|
|
for (const auto &Pipeline : Pipelines)
|
|
ToSort.push_back(&Pipeline);
|
|
|
|
if (auto Error = sortPipeline(ToSort); Error)
|
|
return std::move(Error);
|
|
|
|
for (const auto *Declaration : ToSort)
|
|
if (auto Error = parseDeclarations(ToReturn, *Declaration); Error)
|
|
return std::move(Error);
|
|
|
|
ToReturn.emplaceStep("", "begin");
|
|
|
|
for (const auto *Declaration : ToSort)
|
|
if (auto Error = parseSteps(ToReturn, *Declaration); Error)
|
|
return std::move(Error);
|
|
|
|
return ToReturn;
|
|
}
|
|
|
|
llvm::Expected<Runner>
|
|
Loader::load(const PipelineDeclaration &Declaration) const {
|
|
ArrayRef<PipelineDeclaration> Pipelines(&Declaration, 1);
|
|
return load(Pipelines);
|
|
}
|
|
|
|
bool Loader::isInvocationUsed(const vector<string> &Invocation) const {
|
|
if (Invocation.size() == 0)
|
|
return true;
|
|
|
|
const auto IsStringEnabled = [this](const std::string &Name) {
|
|
if (not Name.starts_with("~"))
|
|
return EnabledFlags.count(Name) != 0;
|
|
|
|
string ActualName(Name.begin() + 1, Name.end());
|
|
return EnabledFlags.count(ActualName) == 0;
|
|
};
|
|
return llvm::any_of(Invocation, IsStringEnabled);
|
|
}
|