#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/IR/Function.h" #include "llvm/Support/Casting.h" #include "llvm/Transforms/Utils/Cloning.h" #include "revng/Pipeline/ContainerEnumerator.h" #include "revng/Pipeline/ContainerSet.h" #include "revng/Pipeline/Context.h" #include "revng/Pipeline/Kind.h" #include "revng/Pipeline/Step.h" #include "revng/Pipeline/Target.h" namespace pipeline { /// Kind that must be extended to be able to specify how a to deduce the target /// associated to a particular llvm global object. /// /// When extented two function must be provided, symbolToTarget must return the /// target associated to a function if there is any. /// /// compactTargets must collapse the targets into the * target if they are all /// presents, do no thing otherwise. template class LLVMGlobalKindBase : public KindForContainer { public: using StaticContainer = llvm::SmallVector; public: LLVMGlobalKindBase(llvm::StringRef Name, Rank *Rank) : KindForContainer(Name, Rank) {} LLVMGlobalKindBase(llvm::StringRef Name, Kind &Parent) : KindForContainer(Name, Parent) {} LLVMGlobalKindBase(llvm::StringRef Name, Kind &Parent, Rank *Rank) : KindForContainer(Name, Parent, Rank) {} ~LLVMGlobalKindBase() override {} public: static bool hasOwner(const llvm::Function &Symbol) { for (const auto &I : getRegisteredInspectors()) if (I->symbolToTarget(Symbol)) return true; return false; } llvm::Error verify(const ContainerBase &Container, const Target &T) const override { if (const auto *Casted = llvm::dyn_cast(&Container)) return verifyTarget(*Casted, T); return llvm::Error::success(); } virtual llvm::Error verifyTarget(const LLVMContainer &Container, const Target &T) const { return llvm::Error::success(); } public: virtual std::optional symbolToTarget(const llvm::Function &Symbol) const = 0; virtual TargetsList compactTargets(const Context &Ctx, TargetsList::List &Targets) const = 0; public: llvm::DenseSet targetsIntersection(const TargetsList &Targets, const LLVMContainer &Container) const { llvm::DenseSet ToReturn; for (auto &GL : Container.getModule().functions()) { auto MaybeTarget = symbolToTarget(GL); if (not MaybeTarget.has_value()) continue; if (not Targets.contains(*MaybeTarget)) continue; ToReturn.insert(&GL); } return ToReturn; } llvm::DenseSet targetsIntersection(const TargetsList &Targets, LLVMContainer &Container) const { llvm::DenseSet ToReturn; for (auto &GL : Container.getModule().functions()) { auto MaybeTarget = symbolToTarget(GL); if (not MaybeTarget.has_value()) continue; if (not Targets.contains(*MaybeTarget)) continue; ToReturn.insert(&GL); } return ToReturn; } public: bool remove(const Context &Ctx, const TargetsList &Targets, LLVMContainer &Container) const final { const bool AllContained = enumerate(Ctx, Container).contains(Targets); for (auto &GL : targetsIntersection(Targets, Container)) GL->deleteBody(); return AllContained; } TargetsList enumerate(const Context &Ctx, const LLVMContainer &Container) const final { TargetsList::List L; for (auto &GL : Container.getModule().functions()) { auto MaybeTarget = symbolToTarget(GL); if (not MaybeTarget.has_value()) continue; L.push_back(std::move(*MaybeTarget)); } return compactTargets(Ctx, L); } static llvm::DenseSet untrackedFunctions(const LLVMContainer &Container) { llvm::DenseSet ToReturn; for (const auto &F : Container.getModule().functions()) if (not hasOwner(F)) ToReturn.insert(&F); return ToReturn; } static llvm::DenseSet functions(const TargetsList &Targets, const LLVMContainer &Container) { if (Targets.size() == 0) return {}; llvm::DenseSet ToReturn; for (const auto &Kind : getRegisteredInspectors()) { auto Set = Kind->targetsIntersection(Targets, Container); for (const auto &E : Set) ToReturn.insert(E); } return ToReturn; } private: static StaticContainer &getRegisteredInspectors() { static StaticContainer Container; return Container; } }; } // namespace pipeline