#ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H
#define LLVM_CLANG_AST_INTERP_PROGRAM_H
#include <map>
#include <vector>
#include "Function.h"
#include "Pointer.h"
#include "PrimType.h"
#include "Record.h"
#include "Source.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
namespace clang {
class RecordDecl;
class Expr;
class FunctionDecl;
class StringLiteral;
class VarDecl;
namespace interp {
class Context;
class Program final {
public:
Program(Context &Ctx) : Ctx(Ctx) {}
~Program() {
for (Global *G : Globals)
if (Block *B = G->block(); B->isInitialized())
B->invokeDtor();
for (auto RecordPair : Records) {
if (Record *R = RecordPair.second)
R->~Record();
}
}
unsigned getOrCreateNativePointer(const void *Ptr);
const void *getNativePointer(unsigned Idx);
unsigned createGlobalString(const StringLiteral *S);
Pointer getPtrGlobal(unsigned Idx) const;
Block *getGlobal(unsigned Idx) {
assert(Idx < Globals.size());
return Globals[Idx]->block();
}
std::optional<unsigned> getGlobal(const ValueDecl *VD);
std::optional<unsigned> getGlobal(const Expr *E);
std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
const Expr *Init = nullptr);
std::optional<unsigned> getOrCreateDummy(const ValueDecl *VD);
std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *Init);
std::optional<unsigned> createGlobal(const Expr *E);
template <typename... Ts>
Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
Def = Def->getCanonicalDecl();
auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
Funcs.insert({Def, std::unique_ptr<Function>(Func)});
return Func;
}
template <typename... Ts>
Function *createFunction(Ts &&... Args) {
auto *Func = new Function(*this, std::forward<Ts>(Args)...);
AnonFuncs.emplace_back(Func);
return Func;
}
Function *getFunction(const FunctionDecl *F);
Record *getOrCreateRecord(const RecordDecl *RD);
Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
Descriptor::MetadataSize MDSize = std::nullopt,
bool IsConst = false, bool IsTemporary = false,
bool IsMutable = false) {
return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);
}
Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
Descriptor::MetadataSize MDSize = std::nullopt,
bool IsConst = false, bool IsTemporary = false,
bool IsMutable = false,
const Expr *Init = nullptr);
class DeclScope {
public:
DeclScope(Program &P, const ValueDecl *VD) : P(P) {
P.startDeclaration(VD);
}
~DeclScope() { P.endDeclaration(); }
private:
Program &P;
};
std::optional<unsigned> getCurrentDecl() const {
if (CurrentDeclaration == NoDeclaration)
return std::optional<unsigned>{};
return LastDeclaration;
}
private:
friend class DeclScope;
std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
bool IsStatic, bool IsExtern,
const Expr *Init = nullptr);
Context &Ctx;
llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
std::vector<std::unique_ptr<Function>> AnonFuncs;
llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
std::vector<const void *> NativePointers;
llvm::DenseMap<const void *, unsigned> NativePointerIndices;
using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
class Global {
public:
template <typename... Tys>
Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
return Alloc.Allocate(Meta + Data, alignof(void *));
}
std::byte *data() { return B.data(); }
Block *block() { return &B; }
const Block *block() const { return &B; }
private:
Block B;
};
PoolAllocTy Allocator;
std::vector<Global *> Globals;
llvm::DenseMap<const void *, unsigned> GlobalIndices;
llvm::DenseMap<const RecordDecl *, Record *> Records;
llvm::DenseMap<const ValueDecl *, unsigned> DummyVariables;
template <typename... Ts>
Descriptor *allocateDescriptor(Ts &&... Args) {
return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
}
static constexpr unsigned NoDeclaration = (unsigned)-1;
unsigned LastDeclaration = 0;
unsigned CurrentDeclaration = NoDeclaration;
void startDeclaration(const ValueDecl *Decl) {
LastDeclaration += 1;
CurrentDeclaration = LastDeclaration;
}
void endDeclaration() {
CurrentDeclaration = NoDeclaration;
}
public:
void dump() const;
void dump(llvm::raw_ostream &OS) const;
};
}
}
#endif