Files
revng-revng/lib/Pipeline/Target.cpp
T
Massimo Fioravanti db15f7df9a Propagate info about inputs and outputs of pipes
This comit propagates the deduced info about inputs and outputs of pipes
all the way up to the runner, so that the requested output of a pipe can
be passed to its invocation.
2024-06-20 10:24:49 +02:00

172 lines
5.1 KiB
C++

/// \file Runner.cpp
/// A target is a object that is associated to the content of a container to
/// describe it without knowing what is the real type of the content itself.
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Error.h"
#include "revng/Pipeline/Container.h"
#include "revng/Pipeline/Context.h"
#include "revng/Pipeline/Kind.h"
#include "revng/Pipeline/KindsRegistry.h"
#include "revng/Pipeline/Target.h"
#include "revng/Support/Assert.h"
using namespace pipeline;
using namespace std;
using namespace llvm;
bool TargetsList::contains(const Target &Target) const {
return find(*this, Target) != end();
}
void TargetsList::merge(const TargetsList &Source) {
copy(Source, back_inserter(Contained));
llvm::sort(Contained);
Contained.erase(unique(Contained.begin(), Contained.end()), Contained.end());
}
void ContainerToTargetsMap::erase(const ContainerToTargetsMap &Other) {
for (const auto &Container : Other.Status) {
const auto &ContainerName = Container.first();
const auto &ContainerSymbols = Container.second;
if (Status.find(ContainerName) == Status.end())
continue;
auto &ToRemoveFrom = Status[ContainerName];
for (auto &Symbol : ContainerSymbols)
ToRemoveFrom.erase(Symbol);
}
}
void ContainerToTargetsMap::merge(const ContainerToTargetsMap &Other) {
for (const auto &Container : Other.Status) {
const auto &ContainerName = Container.first();
const auto &ContainerSymbols = Container.second;
auto &ToMergeIn = Status[ContainerName];
ToMergeIn.merge(ContainerSymbols);
}
}
// NOTE: this operator needs to be stable w.r.t. library load order and memory
// layout
int Target::operator<=>(const Target &Other) const {
if (K->id() < Other.K->id())
return -1;
if (K->id() > Other.K->id())
return 1;
if (Components.size() != Other.Components.size()) {
if (Components.size() > Other.Components.size())
return -1;
if (Components.size() < Other.Components.size())
return 1;
}
for (const auto &[l, r] : zip(Components, Other.Components)) {
if (l < r)
return -1;
if (l > r)
return 1;
}
return 0;
}
std::string Target::serialize() const {
std::string ToReturn;
if (Components.size() == 0) {
return ":" + K->name().str();
}
for (size_t I = 0; I < Components.size() - 1; I++)
ToReturn += Components[I] + "/";
ToReturn += Components.back();
ToReturn += ":";
ToReturn += K->name();
return ToReturn;
}
llvm::Expected<Target> Target::deserialize(Context &Ctx,
const KindsRegistry &Dict,
llvm::StringRef String) {
if (String.contains('*'))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"String cannot contain *");
TargetsList Out;
if (auto Error = parseTarget(Ctx, String, Dict, Out); Error) {
return std::move(Error);
}
revng_assert(Out.size() == 1);
return Out.front();
}
llvm::Error pipeline::parseTarget(const Context &Ctx,
llvm::StringRef AsString,
const KindsRegistry &Dict,
TargetsList &Out) {
size_t Pos = AsString.rfind(':');
if (Pos == llvm::StringRef::npos) {
auto *Message = "String '%s' was not in expected form <path:kind>";
return llvm::createStringError(llvm::inconvertibleErrorCode(),
Message,
AsString.str().c_str());
}
llvm::StringRef Name(AsString.data(), Pos);
llvm::StringRef KindName = AsString.drop_front(Pos + 1);
llvm::SmallVector<llvm::StringRef, 4> Path;
Name.split(Path, '/');
auto It = llvm::find_if(Dict, [&](Kind &K) { return KindName == K.name(); });
if (It == Dict.end())
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"No known Kind '%s' in dictionary",
KindName.str().c_str());
if (AsString[0] == ':') {
Out.push_back(Target({}, *It));
return llvm::Error::success();
}
if (find(AsString, '*') != AsString.end()) {
It->appendAllTargets(Ctx, Out);
return llvm::Error::success();
}
Out.push_back(Target(std::move(Path), *It));
return llvm::Error::success();
}
llvm::Error pipeline::parseTarget(const Context &Ctx,
ContainerToTargetsMap &CurrentStatus,
llvm::StringRef AsString,
const KindsRegistry &Dict) {
if (AsString.empty())
return llvm::Error::success();
llvm::SmallVector<llvm::StringRef, 2> Parts;
AsString.split(Parts, '/', 1);
if (Parts.size() != 2) {
auto *Text = "string '%s' was not in expected form <ContainerName/Target>";
return llvm::createStringError(llvm::inconvertibleErrorCode(),
Text,
AsString.str().c_str());
}
return parseTarget(Ctx, Parts[1], Dict, CurrentStatus[Parts[0]]);
}