Skip to content

Commit f4fca87

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

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
#include <algorithm>
6767
#include <cassert>
6868
#include <cstddef>
69+
#include <cstdint>
6970
#include <cstdio>
7071
#include <deque>
7172
#include <iterator>
@@ -96,6 +97,34 @@
9697
#include <unistd.h>
9798
#endif // WIN32
9899

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

101130
using namespace clang;
@@ -3308,6 +3337,88 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
33083337

33093338
sInterpreters->emplace_back(I, /*Owned=*/true);
33103339

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

0 commit comments

Comments
 (0)