Files
Alessandro Di Federico 2128a80cc8 Preserve metadata after Function::deleteBody
Also, introduce and adopt a simple helper class to get this right.
2025-01-28 12:19:16 +01:00

171 lines
4.6 KiB
C++

#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/IR/Function.h"
#include "revng/Pipeline/ContainerEnumerator.h"
#include "revng/Pipeline/ContainerSet.h"
#include "revng/Pipeline/LLVMContainer.h"
#include "revng/Support/IRHelpers.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 extended 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.
class LLVMKind : public KindForContainer<LLVMContainer> {
public:
using StaticContainer = llvm::SmallVector<LLVMKind *, 4>;
public:
template<RankSpecialization BaseRank>
LLVMKind(llvm::StringRef Name, const BaseRank &Rank) :
KindForContainer<LLVMContainer>(Name, Rank) {
getRegisteredInspectors().push_back(this);
}
template<RankSpecialization BaseRank>
LLVMKind(llvm::StringRef Name, Kind &Parent, const BaseRank &Rank) :
KindForContainer<LLVMContainer>(Name, Parent, Rank) {
getRegisteredInspectors().push_back(this);
}
~LLVMKind() 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<LLVMContainer>(&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<Target>
symbolToTarget(const llvm::Function &Symbol) const = 0;
public:
llvm::DenseSet<const llvm::Function *>
targetsIntersection(const TargetsList &Targets,
const LLVMContainer &Container) const {
llvm::DenseSet<const llvm::Function *> 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<llvm::Function *>
targetsIntersection(const TargetsList &Targets,
LLVMContainer &Container) const {
llvm::DenseSet<llvm::Function *> 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 TargetsList &Targets,
LLVMContainer &Container) const final {
const bool AllContained = enumerate(Container).contains(Targets);
for (auto *Function : targetsIntersection(Targets, Container)) {
// Save metadata
MetadataBackup Backup(Function);
// Delete function body
Function->deleteBody();
// Restore metadata
Backup.restoreIn(Function);
}
return AllContained;
}
TargetsList enumerate(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 L;
}
static llvm::DenseSet<const llvm::Function *>
untrackedFunctions(const LLVMContainer &Container) {
llvm::DenseSet<const llvm::Function *> ToReturn;
for (const auto &F : Container.getModule().functions())
if (not hasOwner(F))
ToReturn.insert(&F);
return ToReturn;
}
static llvm::DenseSet<const llvm::Function *>
functions(const TargetsList &Targets, const LLVMContainer &Container) {
if (Targets.size() == 0)
return {};
llvm::DenseSet<const llvm::Function *> 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