Skip to content

Commit 4db2096

Browse files
committed
Declare clang-repl value printing symbols, mangle and define to the JIT
Supports LLVM 18-21
1 parent 546fcb5 commit 4db2096

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,34 @@
9191
#include <unistd.h>
9292
#endif // WIN32
9393

94+
// Runtime symbols required if the library using JIT (Cpp::Evaluate) does not
95+
// link to llvm
96+
#if !defined(CPPINTEROP_USE_CLING) && !defined(EMSCRIPTEN)
97+
struct __clang_Interpreter_NewTag {
98+
} __ci_newtag;
99+
#if CLANG_VERSION_MAJOR > 21
100+
extern "C" void* __clang_Interpreter_SetValueWithAlloc(void* This, void* OutVal,
101+
void* OpaqueType)
102+
#else
103+
void* __clang_Interpreter_SetValueWithAlloc(void* This, void* OutVal,
104+
void* OpaqueType);
105+
#endif
106+
107+
#if CLANG_VERSION_MAJOR > 18
108+
extern "C" void __clang_Interpreter_SetValueNoAlloc(void* This,
109+
void* OutVal,
110+
void* OpaqueType, ...);
111+
#else
112+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*);
113+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*);
114+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, float);
115+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double);
116+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double);
117+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*,
118+
unsigned long long);
119+
#endif
120+
#endif // CPPINTEROP_USE_CLING
121+
94122
namespace Cpp {
95123

96124
using namespace clang;
@@ -3303,6 +3331,88 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
33033331

33043332
sInterpreters->emplace_back(I, /*Owned=*/true);
33053333

3334+
// Define runtime symbols in the JIT dylib for clang-repl
3335+
#if !defined(CPPINTEROP_USE_CLING) && !defined(EMSCRIPTEN)
3336+
DefineAbsoluteSymbol(*I, "__ci_newtag",
3337+
reinterpret_cast<uint64_t>(&__ci_newtag));
3338+
// llvm > 22 has this defined as a C symbol that does not require mangling
3339+
#if CLANG_VERSION_MAJOR >= 22
3340+
DefineAbsoluteSymbol(
3341+
*I, "__clang_Interpreter_SetValueWithAlloc",
3342+
reinterpret_cast<uint64_t>(&__clang_Interpreter_SetValueWithAlloc));
3343+
#else
3344+
// obtain mangled name
3345+
auto* D = static_cast<clang::Decl*>(
3346+
Cpp::GetNamed("__clang_Interpreter_SetValueWithAlloc"));
3347+
if (auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
3348+
auto GD = GlobalDecl(FD);
3349+
std::string mangledName;
3350+
compat::maybeMangleDeclName(GD, mangledName);
3351+
DefineAbsoluteSymbol(
3352+
*I, mangledName.c_str(),
3353+
reinterpret_cast<uint64_t>(&__clang_Interpreter_SetValueWithAlloc));
3354+
}
3355+
#endif
3356+
// llvm < 19 has multiple overloads of __clang_Interpreter_SetValueNoAlloc
3357+
#if CLANG_VERSION_MAJOR < 19
3358+
// obtain all 6 candidates, and obtain the correct Decl for each overload
3359+
// using BestOverloadFunctionMatch. We then map the decl to the correct
3360+
// function pointer (force the compiler to find the right declarion by casting
3361+
// to the corresponding function pointer signature) and then register it.
3362+
const std::vector<TCppFunction_t> Methods = Cpp::GetFunctionsUsingName(
3363+
Cpp::GetGlobalScope(), "__clang_Interpreter_SetValueNoAlloc");
3364+
std::string mangledName;
3365+
ASTContext& Ctxt = I->getSema().getASTContext();
3366+
auto* TAI = Ctxt.VoidPtrTy.getAsOpaquePtr();
3367+
3368+
// possible parameter lists for __clang_Interpreter_SetValueNoAlloc overloads
3369+
// in LLVM 18
3370+
const std::vector<std::vector<Cpp::TemplateArgInfo>> a_params = {
3371+
{TAI, TAI, TAI},
3372+
{TAI, TAI, TAI, TAI},
3373+
{TAI, TAI, TAI, Ctxt.FloatTy.getAsOpaquePtr()},
3374+
{TAI, TAI, TAI, Ctxt.DoubleTy.getAsOpaquePtr()},
3375+
{TAI, TAI, TAI, Ctxt.LongDoubleTy.getAsOpaquePtr()},
3376+
{TAI, TAI, TAI, Ctxt.UnsignedLongLongTy.getAsOpaquePtr()}};
3377+
3378+
using FP0 = void (*)(void*, void*, void*);
3379+
using FP1 = void (*)(void*, void*, void*, void*);
3380+
using FP2 = void (*)(void*, void*, void*, float);
3381+
using FP3 = void (*)(void*, void*, void*, double);
3382+
using FP4 = void (*)(void*, void*, void*, long double);
3383+
using FP5 = void (*)(void*, void*, void*, unsigned long long);
3384+
3385+
const std::vector<void*> func_pointers = {
3386+
reinterpret_cast<void*>(
3387+
static_cast<FP0>(&__clang_Interpreter_SetValueNoAlloc)),
3388+
reinterpret_cast<void*>(
3389+
static_cast<FP1>(&__clang_Interpreter_SetValueNoAlloc)),
3390+
reinterpret_cast<void*>(
3391+
static_cast<FP2>(&__clang_Interpreter_SetValueNoAlloc)),
3392+
reinterpret_cast<void*>(
3393+
static_cast<FP3>(&__clang_Interpreter_SetValueNoAlloc)),
3394+
reinterpret_cast<void*>(
3395+
static_cast<FP4>(&__clang_Interpreter_SetValueNoAlloc)),
3396+
reinterpret_cast<void*>(
3397+
static_cast<FP5>(&__clang_Interpreter_SetValueNoAlloc))};
3398+
3399+
// these symbols are not externed, so we need to mangle their names
3400+
for (size_t i = 0; i < a_params.size(); ++i) {
3401+
auto* decl = static_cast<clang::Decl*>(
3402+
Cpp::BestOverloadFunctionMatch(Methods, {}, a_params[i]));
3403+
if (auto* fd = llvm::dyn_cast<clang::FunctionDecl>(decl)) {
3404+
auto gd = clang::GlobalDecl(fd);
3405+
compat::maybeMangleDeclName(gd, mangledName);
3406+
DefineAbsoluteSymbol(*I, mangledName.c_str(),
3407+
reinterpret_cast<uint64_t>(func_pointers[i]));
3408+
}
3409+
}
3410+
#else
3411+
DefineAbsoluteSymbol(
3412+
*I, "__clang_Interpreter_SetValueNoAlloc",
3413+
reinterpret_cast<uint64_t>(&__clang_Interpreter_SetValueNoAlloc));
3414+
#endif
3415+
#endif
33063416
return I;
33073417
}
33083418

0 commit comments

Comments
 (0)