mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
145 lines
4.3 KiB
C++
145 lines
4.3 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <set>
|
|
|
|
#include "revng/Pipeline/GlobalTupleTreeDiff.h"
|
|
#include "revng/Pipeline/Rank.h"
|
|
#include "revng/Pipeline/RegisterKind.h"
|
|
#include "revng/Support/Assert.h"
|
|
|
|
namespace pipeline {
|
|
|
|
class Target;
|
|
class Context;
|
|
class TargetsList;
|
|
class ContainerBase;
|
|
class InvalidationEventBase;
|
|
|
|
class DeadKind;
|
|
|
|
template<RankSpecialization... T>
|
|
inline std::vector<const Rank *>
|
|
locationsToRanks(std::tuple<const T &...> Locations) {
|
|
std::vector<const Rank *> Return;
|
|
std::apply([&](auto &&...Loc) { (Return.push_back(&Loc), ...); }, Locations);
|
|
return Return;
|
|
}
|
|
|
|
/// A Kind is used to accumulate objects that logically belongs to the same
|
|
/// category.
|
|
///
|
|
/// As an example, the Kind of Isolated Functions, the Kind of translated
|
|
/// binaries.
|
|
///
|
|
/// A kind refers to a rank which is used by Targets, furthermore a Kind
|
|
/// can optionally have a Parent Kind. Again this is used mostly by targets.
|
|
///
|
|
/// Kinds expose two additional bits of metadata:
|
|
/// * DefinedLocations: these are Locations (ranks) which define the locations
|
|
/// exposed by the objects of this kind, these assume that all the n keys of the
|
|
/// target map to the first n components of the location; if there are trailing
|
|
/// components all of them are matched
|
|
/// * PreferredKinds: these are other kinds that are suggested when looking for
|
|
/// forward references, i.e. Given a location reference in this Kind, which
|
|
/// Kinds should I look into to find a definition?
|
|
///
|
|
/// If you wish to declare a kind to be used in a llvm container, declare a
|
|
/// LLVMKind instead.
|
|
class Kind : public DynamicHierarchy<Kind> {
|
|
private:
|
|
RegisterKind Register;
|
|
const Rank *TheRank = nullptr;
|
|
std::vector<const Rank *> DefinedLocations;
|
|
std::vector<const Kind *> PreferredKinds;
|
|
|
|
public:
|
|
template<RankSpecialization BaseRank, typename... T>
|
|
requires(RankConvertibleTo<BaseRank, T> and ...)
|
|
Kind(llvm::StringRef Name,
|
|
const BaseRank &TheRank,
|
|
std::tuple<const T &...> Locations,
|
|
std::vector<const Kind *> PreferredKinds) :
|
|
DynamicHierarchy<Kind>(Name),
|
|
Register(*this),
|
|
TheRank(&TheRank),
|
|
DefinedLocations(locationsToRanks(Locations)),
|
|
PreferredKinds(PreferredKinds) {
|
|
this->PreferredKinds.push_back(this);
|
|
}
|
|
|
|
template<RankSpecialization BaseRank, typename... T>
|
|
requires(RankConvertibleTo<BaseRank, T> and ...)
|
|
Kind(llvm::StringRef Name,
|
|
Kind &Parent,
|
|
const BaseRank &TheRank,
|
|
std::tuple<const T &...> Locations,
|
|
std::vector<const Kind *> PreferredKinds) :
|
|
DynamicHierarchy<Kind>(Name, Parent),
|
|
Register(*this),
|
|
TheRank(&TheRank),
|
|
DefinedLocations(locationsToRanks(Locations)),
|
|
PreferredKinds(PreferredKinds) {
|
|
this->PreferredKinds.push_back(this);
|
|
}
|
|
|
|
/// Kinds may provide a override for this method. They must return success if
|
|
/// ToVerify (which always has this kind as a kind), well formed inside
|
|
/// Container (which always contains ToVerify).
|
|
virtual llvm::Error verify(const ContainerBase &Container,
|
|
const Target &ToVerify) const;
|
|
|
|
public:
|
|
size_t depth() const { return TheRank->depth(); }
|
|
|
|
const Rank &rank() const { return *TheRank; }
|
|
|
|
const llvm::ArrayRef<const Kind *> preferredKinds() const {
|
|
return PreferredKinds;
|
|
}
|
|
|
|
const llvm::ArrayRef<const Rank *> definedLocations() const {
|
|
return DefinedLocations;
|
|
}
|
|
|
|
public:
|
|
virtual ~Kind() = default;
|
|
|
|
virtual void appendAllTargets(const Context &Context,
|
|
TargetsList &Out) const = 0;
|
|
TargetsList allTargets(const Context &Context) const;
|
|
|
|
public:
|
|
template<RankSpecialization RankDefinitionType>
|
|
static Kind &deadKind(const RankDefinitionType &Rank);
|
|
};
|
|
|
|
class SingleElementKind : public Kind {
|
|
using Kind::Kind;
|
|
void appendAllTargets(const Context &Context,
|
|
TargetsList &Out) const override;
|
|
};
|
|
|
|
class DeadKind : public Kind {
|
|
|
|
public:
|
|
template<RankSpecialization BaseRank>
|
|
DeadKind(const BaseRank &R) : Kind("Dead", R, {}, {}) {}
|
|
|
|
void appendAllTargets(const Context &Context,
|
|
TargetsList &Out) const override {
|
|
revng_abort();
|
|
}
|
|
};
|
|
|
|
template<RankSpecialization RankDefinitionType>
|
|
inline Kind &Kind::deadKind(const RankDefinitionType &Rank) {
|
|
static DeadKind Kind(Rank);
|
|
return Kind;
|
|
}
|
|
|
|
} // namespace pipeline
|