#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #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 inline std::vector locationsToRanks(std::tuple Locations) { std::vector Return; std::apply([&](auto &&...Loc) { (Return.push_back(&Loc), ...); }, Locations); return Return; } /// A Kind is used to accumunate 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 { private: RegisterKind Register; const Rank *TheRank; std::vector DefinedLocations; std::vector PreferredKinds; public: template requires(RankConvertibleTo and ...) Kind(llvm::StringRef Name, const BaseRank &TheRank, std::tuple Locations, std::vector PreferredKinds) : DynamicHierarchy(Name), Register(*this), TheRank(&TheRank), DefinedLocations(locationsToRanks(Locations)), PreferredKinds(PreferredKinds) { this->PreferredKinds.push_back(this); } template requires(RankConvertibleTo and ...) Kind(llvm::StringRef Name, Kind &Parent, const BaseRank &TheRank, std::tuple Locations, std::vector PreferredKinds) : DynamicHierarchy(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 preferredKinds() const { return PreferredKinds; } const llvm::ArrayRef definedLocations() const { return DefinedLocations; } public: virtual ~Kind() = default; virtual void getInvalidations(const Context &Ctx, pipeline::TargetsList &ToRemove, const GlobalTupleTreeDiff &Diff) const {} virtual void appendAllTargets(const Context &Ctx, TargetsList &Out) const = 0; TargetsList allTargets(const Context &Ctx) const; public: template static Kind &deadKind(const RankDefinitionType &Rank); }; class SingleElementKind : public Kind { using Kind::Kind; void appendAllTargets(const Context &Ctx, TargetsList &Out) const override; }; class DeadKind : public Kind { public: template DeadKind(const BaseRank &R) : Kind("Dead", R, {}, {}) {} void appendAllTargets(const Context &Ctx, TargetsList &Out) const override { revng_abort(); } }; template inline Kind &Kind::deadKind(const RankDefinitionType &Rank) { static DeadKind Kind(Rank); return Kind; } } // namespace pipeline