Files
revng-revng/lib/Pipeline/Runner.cpp
Massimo Fioravanti c05b5dbb28 Steps now represent the *end* of a step
A special "begin" step has been introduced.
2022-03-28 12:17:05 +02:00

257 lines
7.9 KiB
C++

/// \file Runner.cpp
/// \brief a runner top object of a pipeline structure, it is able to run the
/// pipeline.
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/Support/Error.h"
#include "revng/Pipeline/Errors.h"
#include "revng/Pipeline/Runner.h"
#include "revng/Pipeline/Target.h"
using namespace std;
using namespace llvm;
using namespace pipeline;
class PipelineExecutionEntry {
public:
Step *ToExecute;
ContainerToTargetsMap Objectives;
PipelineExecutionEntry(Step &ToExecute, ContainerToTargetsMap Objectives) :
ToExecute(&ToExecute), Objectives(std::move(Objectives)) {}
};
static Error getObjectives(Runner &Runner,
llvm::StringRef EndingStepName,
const ContainerToTargetsMap &Targets,
ContainerToTargetsMap &ToLoad,
std::vector<PipelineExecutionEntry> &ToExec) {
ContainerToTargetsMap PartialGoals = Targets;
auto *CurrentStep = &(Runner[EndingStepName]);
while (CurrentStep != nullptr) {
if (PartialGoals.empty())
break;
PartialGoals = CurrentStep->analyzeGoals(PartialGoals, ToLoad);
ToExec.emplace_back(*CurrentStep, PartialGoals);
CurrentStep = CurrentStep->hasPredecessor() ?
&CurrentStep->getPredecessor() :
nullptr;
}
if (not PartialGoals.empty())
return make_error<UnsatisfiableRequestError>(Targets, PartialGoals);
reverse(ToExec.begin(), ToExec.end());
return Error::success();
}
using StatusMap = llvm::StringMap<ContainerToTargetsMap>;
static void explainPipeline(const ContainerToTargetsMap &Targets,
const ContainerToTargetsMap &ToLoad,
ArrayRef<PipelineExecutionEntry> Requirements,
raw_ostream &OS) {
OS.changeColor(llvm::raw_ostream::Colors::GREEN);
OS << "Objectives: \n";
prettyPrintStatus(Targets, OS, 1);
if (Requirements.size() <= 1) {
OS.changeColor(llvm::raw_ostream::Colors::GREEN);
OS << "Already satisfied\n";
return;
}
OS << "\n";
OS.changeColor(llvm::raw_ostream::Colors::GREEN);
OS << "Deduced Step Level Requirements: \n";
for (const PipelineExecutionEntry &Entry : llvm::reverse(Requirements)) {
OS.indent(1);
OS.changeColor(llvm::raw_ostream::Colors::MAGENTA);
OS << Entry.ToExecute->getName() << "\n";
prettyPrintStatus(Entry.Objectives, OS, 2);
}
OS.resetColor();
}
Error Runner::getInvalidations(StatusMap &Invalidated) const {
for (const auto &NextS : *this) {
if (not NextS.hasPredecessor())
continue;
const Step &S = NextS.getPredecessor();
ContainerToTargetsMap &Inputs = Invalidated[S.getName()];
ContainerToTargetsMap &Outputs = Invalidated[NextS.getName()];
auto Deduced = NextS.deduceResults(Inputs);
NextS.containers().intersect(Deduced);
Outputs.merge(Deduced);
}
return Error::success();
}
Step &Runner::addStep(Step &&NewStep) {
std::string Name = NewStep.getName().str();
auto Info = Steps.try_emplace(Name, std::move(NewStep));
revng_assert(Info.second);
ReversePostOrderIndexes.emplace_back(&Info.first->second);
return *ReversePostOrderIndexes.back();
}
llvm::Error Runner::getInvalidations(const Target &Target,
InvalidationMap &Invalidations) const {
for (const auto &Step : *this)
for (const auto &Container : Step.containers()) {
if (Container.second == nullptr)
continue;
if (Container.second->enumerate().contains(Target)) {
Invalidations[Step.getName()].add(Container.first(), Target);
}
}
if (auto Error = getInvalidations(Invalidations); !!Error)
return Error;
return llvm::Error::success();
}
Error Runner::invalidate(const Target &Target) {
llvm::StringMap<ContainerToTargetsMap> Invalidations;
if (auto Error = getInvalidations(Target, Invalidations); !!Error)
return Error;
return invalidate(Invalidations);
}
llvm::Expected<PipelineFileMapping>
PipelineFileMapping::parse(StringRef ToParse) {
SmallVector<StringRef, 4> Splitted;
ToParse.split(Splitted, ':', 2);
if (Splitted.size() != 3) {
auto *Message = "could not parse %s into three strings "
"step:container:inputfile";
return createStringError(inconvertibleErrorCode(),
Message,
ToParse.str().c_str());
}
return PipelineFileMapping(Splitted[0], Splitted[1], Splitted[2]);
}
Error PipelineFileMapping::loadFromDisk(Runner &LoadInto) const {
if (not LoadInto.containsStep(Step))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"No known step " + Step);
if (not LoadInto[Step].containers().containsOrCanCreate(Container))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"No known container " + Container);
return LoadInto[Step].containers()[Container].loadFromDisk(InputFile);
}
Error PipelineFileMapping::storeToDisk(const Runner &LoadInto) const {
if (not LoadInto.containsStep(Step))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"No known step " + Step);
if (not LoadInto[Step].containers().containsOrCanCreate(Container))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"No known container " + Container);
return LoadInto[Step].containers().at(Container).storeToDisk(InputFile);
}
Error Runner::storeToDisk(llvm::StringRef DirPath) const {
for (const auto &Step : Steps)
if (auto Error = Step.second.storeToDisk(DirPath); !!Error)
return Error;
return TheContext->storeToDisk(DirPath);
}
Error Runner::loadFromDisk(llvm::StringRef DirPath) {
if (auto Error = TheContext->loadFromDisk(DirPath); !!Error)
return Error;
for (auto &Step : Steps)
if (auto Error = Step.second.loadFromDisk(DirPath); !!Error)
return Error;
return Error::success();
}
Error Runner::run(llvm::StringRef EndingStepName,
const ContainerToTargetsMap &Targets,
llvm::raw_ostream *DiagnosticLog) {
ContainerToTargetsMap ToLoad;
vector<PipelineExecutionEntry> ToExec;
if (auto
Error = getObjectives(*this, EndingStepName, Targets, ToLoad, ToExec);
Error)
return Error;
if (DiagnosticLog != nullptr)
explainPipeline(Targets, ToLoad, ToExec, *DiagnosticLog);
if (ToExec.size() <= 1)
return Error::success();
auto &FirstStepContainers = ToExec.front().ToExecute->containers();
auto CurrentContainer(FirstStepContainers.cloneFiltered(ToLoad));
for (auto &StepGoalsPairs :
llvm::make_range(ToExec.begin() + 1, ToExec.end())) {
auto &[Step, Goals] = StepGoalsPairs;
CurrentContainer = Step->cloneAndRun(*TheContext,
std::move(CurrentContainer),
DiagnosticLog);
}
if (DiagnosticLog != nullptr) {
*DiagnosticLog << "Produced:\n";
CurrentContainer.enumerate().dump(*DiagnosticLog);
}
return Error::success();
}
Error Runner::invalidate(const StatusMap &Invalidations) {
for (const auto &Step : Invalidations) {
const auto &StepName = Step.first();
const auto &ToRemove = Step.second;
if (auto Error = operator[](StepName).invalidate(ToRemove); Error)
return Error;
}
return Error::success();
}
void Runner::getCurrentState(State &Out) const {
for (const auto &Step : Steps) {
const auto &Under = Step.second;
Out.insert({ Under.getName(), Under.containers().enumerate() });
}
}
void Runner::deduceAllPossibleTargets(State &Out) const {
getCurrentState(Out);
for (const auto &NextStep : *this) {
if (not NextStep.hasPredecessor())
continue;
const Step &Step = NextStep.getPredecessor();
Out[NextStep.getName()].merge(NextStep.deduceResults(Out[Step.getName()]));
}
}