mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
127 lines
3.7 KiB
C++
127 lines
3.7 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <map>
|
|
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/IR/Attributes.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "revng/ADT/Concepts.h"
|
|
#include "revng/Support/Assert.h"
|
|
#include "revng/Support/FunctionTags.h"
|
|
#include "revng/Support/IRHelpers.h"
|
|
|
|
template<typename T>
|
|
concept PointerToLLVMTypeOrDerived = DerivesFrom<std::remove_pointer_t<T>,
|
|
llvm::Type>;
|
|
|
|
template<typename KeyT>
|
|
class OpaqueFunctionsPool {
|
|
private:
|
|
llvm::Module *M;
|
|
const bool PurgeOnDestruction;
|
|
std::map<KeyT, llvm::Function *> Pool;
|
|
llvm::AttributeList AttributeSets;
|
|
FunctionTags::TagsSet Tags;
|
|
|
|
public:
|
|
OpaqueFunctionsPool(llvm::Module *M, bool PurgeOnDestruction) :
|
|
M(M), PurgeOnDestruction(PurgeOnDestruction) {}
|
|
|
|
~OpaqueFunctionsPool() {
|
|
if (PurgeOnDestruction) {
|
|
for (auto &[Key, F] : Pool) {
|
|
revng_assert(F->use_begin() == F->use_end());
|
|
eraseFromParent(F);
|
|
}
|
|
}
|
|
}
|
|
|
|
public:
|
|
void addFnAttribute(llvm::Attribute::AttrKind Kind) {
|
|
using namespace llvm;
|
|
AttributeSets = AttributeSets.addAttribute(M->getContext(),
|
|
AttributeList::FunctionIndex,
|
|
Kind);
|
|
}
|
|
|
|
void setTags(const FunctionTags::TagsSet &Tags) { this->Tags = Tags; }
|
|
|
|
public:
|
|
auto begin() const { return Pool.begin(); }
|
|
auto end() const { return Pool.end(); }
|
|
|
|
public:
|
|
void record(KeyT Key, llvm::Function *F) {
|
|
auto It = Pool.find(Key);
|
|
if (It == Pool.end())
|
|
Pool[Key] = F;
|
|
else
|
|
revng_assert(It->second == F);
|
|
}
|
|
|
|
public:
|
|
llvm::Function *
|
|
get(KeyT Key, llvm::FunctionType *FT, const llvm::Twine &Name = {}) {
|
|
using namespace llvm;
|
|
|
|
Function *F = nullptr;
|
|
auto It = Pool.find(Key);
|
|
if (It != Pool.end()) {
|
|
F = It->second;
|
|
} else {
|
|
F = Function::Create(FT, GlobalValue::ExternalLinkage, Name, M);
|
|
F->setAttributes(AttributeSets);
|
|
Tags.set(F);
|
|
Pool.insert(It, { Key, F });
|
|
}
|
|
|
|
// Ensure the function we're returning is as expected
|
|
revng_assert(F->getType()->getPointerElementType() == FT);
|
|
|
|
return F;
|
|
}
|
|
|
|
llvm::Function *get(KeyT Key,
|
|
llvm::Type *ReturnType = nullptr,
|
|
llvm::ArrayRef<llvm::Type *> Arguments = {},
|
|
const llvm::Twine &Name = {}) {
|
|
using namespace llvm;
|
|
if (ReturnType == nullptr)
|
|
ReturnType = Type::getVoidTy(M->getContext());
|
|
|
|
return get(Key, FunctionType::get(ReturnType, Arguments, false), Name);
|
|
}
|
|
|
|
/// Initialize the pool with all the functions in M that match the tag TheTag,
|
|
/// using the return type as key.
|
|
void initializeFromReturnType(const FunctionTags::Tag &TheTag) requires
|
|
PointerToLLVMTypeOrDerived<KeyT> {
|
|
using TypeLike = std::remove_pointer_t<KeyT>;
|
|
for (llvm::Function &F : TheTag.functions(M)) {
|
|
auto *RetType = F.getFunctionType()->getReturnType();
|
|
if (auto *KeyType = dyn_cast<TypeLike>(RetType))
|
|
record(KeyType, &F);
|
|
}
|
|
}
|
|
|
|
/// Initialize the pool with all the functions in M that match the tag TheTag,
|
|
/// using the type of the ArgNo-th argument as key.
|
|
void initializeFromNthArgType(const FunctionTags::Tag &TheTag,
|
|
unsigned ArgNo) requires
|
|
PointerToLLVMTypeOrDerived<KeyT> {
|
|
using TypeLike = std::remove_pointer_t<KeyT>;
|
|
for (llvm::Function &F : TheTag.functions(M)) {
|
|
auto ArgType = F.getFunctionType()->getParamType(ArgNo);
|
|
if (auto *KeyType = dyn_cast<TypeLike>(ArgType))
|
|
record(KeyType, &F);
|
|
}
|
|
}
|
|
};
|