Files
Giacomo Vercesi e3074ec29a revng artifact: omit kind
When working with `revng artifact`, omit the kind in both the output of
`--list` and the parameters taken specifying which targets to produce.
2025-05-07 10:48:48 +02:00

450 lines
12 KiB
C++

#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <algorithm>
#include <cstring>
#include <initializer_list>
#include <iterator>
#include <optional>
#include <set>
#include <utility>
#include <vector>
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
#include "revng/ADT/ZipMapIterator.h"
#include "revng/Pipeline/Kind.h"
#include "revng/Support/Assert.h"
#include "revng/Support/Debug.h"
namespace pipeline {
class TargetsList;
class ContainerBase;
class Context;
/// A target is a triple of Kind, PathComponents, and Exactness used to
/// enumerate and transform the contents of a container.
///
/// The kind is used to tell apart objects that are conceptually different or
/// have a relationship of containment or extension.
/// The PathComponent list is used to tell apart objects belonging to the same
/// Kind
class Target {
public:
using PathComponents = llvm::SmallVector<std::string, 1>;
private:
PathComponents Components;
const Kind *K = nullptr;
public:
Target(PathComponents Components, const Kind &K) :
Components(std::move(Components)), K(&K) {
revng_assert(this->Components.size() == getKind().depth());
}
Target(std::string PathComponent, const Kind &K) :
Components({ std::move(PathComponent) }), K(&K) {
revng_assert(this->Components.size() == getKind().depth());
}
Target(std::initializer_list<std::string> Names, const Kind &K) : K(&K) {
for (auto Name : Names)
Components.emplace_back(Name);
revng_assert(this->Components.size() == getKind().depth());
}
Target(llvm::ArrayRef<llvm::StringRef> Names, const Kind &K) : K(&K) {
for (auto Name : Names) {
Components.emplace_back(Name.str());
}
revng_assert(this->Components.size() == getKind().depth());
}
Target(const Kind &K) : K(&K) {
revng_assert(this->Components.size() == getKind().depth());
}
public:
static llvm::Expected<Target> deserialize(Context &Context,
llvm::StringRef String);
public:
bool operator<(const Target &Other) const {
auto Self = std::tie(K, Components);
auto OtherSelf = std::tie(Other.K, Other.Components);
return Self < OtherSelf;
}
int operator<=>(const Target &Other) const;
bool operator==(const Target &Other) const { return (*this <=> Other) == 0; }
public:
const Kind &getKind() const { return *K; }
const PathComponents &getPathComponents() const { return Components; }
public:
void setKind(const Kind &NewKind) { K = &NewKind; }
public:
llvm::Error verify(const ContainerBase &Container) const {
return K->verify(Container, *this);
}
public:
std::string toString() const;
std::string path() const;
void dump() const debug_function { dump(dbg); }
template<typename OStream>
void dump(OStream &OS, size_t Indentation = 0) const debug_function {
indent(OS, Indentation);
OS << toString() << '\n';
}
};
class KindsRegistry;
llvm::Error parseTarget(const Context &Context,
llvm::StringRef AsString,
const KindsRegistry &Dict,
TargetsList &Out);
/// a sorted list of targets.
class TargetsList {
public:
using List = llvm::SmallVector<Target, 4>;
using iterator = List::iterator;
using const_iterator = List::const_iterator;
using value_type = List::value_type;
using size_type = List::size_type;
using reference = List::reference;
using pointer = List::pointer;
private:
List Contained;
public:
TargetsList() = default;
TargetsList(List C) : Contained(std::move(C)) {}
static TargetsList allTargets(const Context &Context, const Kind &K) {
TargetsList ToReturn;
K.appendAllTargets(Context, ToReturn);
return ToReturn;
}
bool operator==(const TargetsList &Other) const = default;
bool operator!=(const TargetsList &Other) const = default;
public:
const Target &operator[](size_t Index) const { return Contained[Index]; }
Target &operator[](size_t Index) { return Contained[Index]; }
public:
llvm::Error verify(const ContainerBase &Container) const {
for (const Target &T : *this)
if (auto Error = T.verify(Container))
return Error;
return llvm::Error::success();
}
iterator begin() { return Contained.begin(); }
iterator end() { return Contained.end(); }
const_iterator begin() const { return Contained.begin(); }
const_iterator end() const { return Contained.end(); }
size_t size() const { return Contained.size(); }
bool empty() const { return Contained.empty(); }
Target &front() { return Contained.front(); }
const Target &front() const { return Contained.front(); }
bool contains(const Target &Target) const;
bool contains(const TargetsList &Targets) const {
return llvm::all_of(Targets, [this](const Target &Target) {
return contains(Target);
});
}
TargetsList filter(const Kind &K) const {
List C;
for (const auto &Target : Contained)
if (&Target.getKind() == &K)
C.push_back(Target);
return TargetsList(std::move(C));
}
public:
template<typename... Args>
void emplace_back(Args &&...A) {
Contained.emplace_back(std::forward<Args>(A)...);
llvm::sort(Contained);
Contained.erase(unique(Contained.begin(), Contained.end()),
Contained.end());
}
void merge(const TargetsList &Other);
void push_back(const Target &Target) {
Contained.push_back(Target);
llvm::sort(Contained);
Contained.erase(unique(Contained.begin(), Contained.end()),
Contained.end());
}
template<typename... Args>
auto erase_if(Args &&...A) {
llvm::erase_if(Contained, std::forward<Args>(A)...);
}
template<typename... Args>
auto erase(Args &&...A) {
return Contained.erase(std::forward<Args>(A)...);
}
void erase(const Target &Target) {
Contained.erase(std::remove(Contained.begin(), Contained.end(), Target),
Contained.end());
}
TargetsList intersect(const TargetsList &Other) const {
TargetsList ToReturn;
std::set_intersection(begin(),
end(),
Other.begin(),
Other.end(),
std::back_inserter(ToReturn.Contained));
llvm::sort(ToReturn.Contained);
return ToReturn;
}
private:
struct Comp {
bool operator()(const Target &T, const Kind &K) const {
return &T.getKind() < &K;
}
bool operator()(const Kind &K, const Target &T) const {
return &K < &T.getKind();
}
};
public:
llvm::iterator_range<iterator> filterByKind(const Kind &K) {
auto &&[b, e] = std::equal_range(begin(), end(), K, Comp());
return llvm::make_range(b, e);
}
llvm::iterator_range<const_iterator> filterByKind(const Kind &K) const {
auto &&[b, e] = std::equal_range(begin(), end(), K, Comp());
return llvm::make_range(b, e);
}
llvm::SmallVector<const Kind *, 4> getContainedKinds() const {
llvm::SmallVector<const Kind *, 4> ToReturn;
auto Current = begin();
while (Current != end()) {
ToReturn.push_back(&Current->getKind());
Current = std::upper_bound(Current, end(), Current->getKind(), Comp());
}
return ToReturn;
}
public:
void dump() const debug_function { dump(dbg); }
template<typename OStream>
void dump(OStream &OS, size_t Indentation = 0) const {
for (const auto &Entry : Contained)
Entry.dump(OS, Indentation);
}
};
/// A map from container name to target list that is usually used to represents
/// the state of a step.
class ContainerToTargetsMap {
friend llvm::yaml::MappingTraits<ContainerToTargetsMap>;
friend llvm::yaml::MappingTraits<const ContainerToTargetsMap>;
public:
using Map = llvm::StringMap<TargetsList>;
using iterator = Map::iterator;
using const_iterator = Map::const_iterator;
using value_type = Map::value_type;
using key_iterator = decltype(declval<Map>().keys());
private:
Map Status;
public:
bool operator==(const ContainerToTargetsMap &) const = default;
bool sameTargets(const ContainerToTargetsMap &Other) const {
for (auto &&[ThisPair, OtherPair] : zipmap_range(Status, Other.Status)) {
if (ThisPair == nullptr and not OtherPair->second.empty()) {
return false;
} else if (OtherPair == nullptr and not ThisPair->second.empty()) {
return false;
} else if (ThisPair != nullptr and OtherPair != nullptr
and ThisPair->second != OtherPair->second) {
return false;
}
}
return true;
}
iterator begin() { return Status.begin(); }
iterator end() { return Status.end(); }
const_iterator begin() const { return Status.begin(); }
const_iterator end() const { return Status.end(); }
key_iterator keys() const { return Status.keys(); }
auto size() const { return Status.size(); }
bool empty() const { return targetsCount() == 0; }
bool contains(llvm::StringRef ContainerName) const {
return Status.find(ContainerName) != Status.end();
}
bool contains(const ContainerToTargetsMap &Other) const {
for (const value_type &Pair : Other.Status) {
if (Pair.second.empty())
continue;
if (not contains(Pair.first()))
return false;
if (not find(Pair.first())->second.contains(Pair.second))
return false;
}
return true;
}
iterator find(llvm::StringRef ContainerName) {
return Status.find(ContainerName);
}
const_iterator find(llvm::StringRef ContainerName) const {
return Status.find(ContainerName);
}
TargetsList &at(llvm::StringRef Name) {
revng_assert(Status.find(Name) != Status.end());
return Status.find(Name)->getValue();
}
const TargetsList &at(llvm::StringRef ContainerName) const {
revng_assert(Status.find(ContainerName) != Status.end());
return Status.find(ContainerName)->second;
}
TargetsList &operator[](llvm::StringRef ContainerName) {
return Status[ContainerName];
}
public:
void merge(const ContainerToTargetsMap &Other);
void erase(const ContainerToTargetsMap &Other);
auto erase(llvm::StringRef Name) { return Status.erase(Name); }
void add(llvm::StringRef Name,
std::initializer_list<std::string> Names,
const Kind &K) {
Status[Name].emplace_back(Names, K);
}
void add(llvm::StringRef Name, Target Target) {
Status[Name].emplace_back(std::move(Target));
}
void add(llvm::StringRef Name, const TargetsList &Targets) {
for (const auto &Target : Targets)
Status[Name].emplace_back(Target);
}
public:
template<typename OStream>
void
dump(OStream &OS, size_t Indentation = 0, bool Parenthesis = true) const {
if (Parenthesis) {
indent(OS, Indentation);
OS << "{\n";
}
auto ExtraIndentation = Indentation + (Parenthesis ? 1 : 0);
for (const auto &Container : Status) {
indent(OS, ExtraIndentation);
OS << Container.first().str() << ":\n";
Container.second.dump(OS, ExtraIndentation + 1);
}
if (Parenthesis) {
indent(OS, Indentation);
OS << "}\n";
}
}
void dump() const debug_function { dump(dbg); }
private:
size_t targetsCount() const {
size_t Size = 0;
for (const auto &Container : Status)
Size += Container.second.size();
return Size;
}
};
using TargetInStepSet = llvm::StringMap<ContainerToTargetsMap>;
llvm::Error parseTarget(const Context &Context,
ContainerToTargetsMap &CurrentStatus,
llvm::StringRef AsString,
const KindsRegistry &Dict);
inline void merge(TargetInStepSet &Map, const TargetInStepSet &Other) {
for (const auto &Entry : Other) {
if (auto Iter = Map.find(Entry.first()); Iter != Map.end()) {
Iter->second.merge(Entry.second);
} else {
Map.try_emplace(Entry.first(), Entry.second);
}
}
}
template<typename T>
void prettyPrintStatus(const ContainerToTargetsMap &Targets,
T &OS,
size_t Indentation = 0) {
for (const auto &Pair : Targets) {
const auto &Name = Pair.first();
const auto &List = Pair.second;
if (List.empty())
continue;
indent(OS, Indentation);
OS << Name << ":\n";
for (const auto &Target : List)
Target.dump(OS, Indentation + 1);
}
}
} // namespace pipeline