Skip to content

Commit ee5f735

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

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
@@ -64,6 +64,7 @@
6464
#include <algorithm>
6565
#include <cassert>
6666
#include <cstddef>
67+
#include <cstdint>
6768
#include <cstdio>
6869
#include <deque>
6970
#include <iterator>
@@ -94,6 +95,34 @@
9495
#include <unistd.h>
9596
#endif // WIN32
9697

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

99128
using namespace clang;
@@ -3306,6 +3335,88 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
33063335

33073336
sInterpreters->emplace_back(I, /*Owned=*/true);
33083337

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

0 commit comments

Comments
 (0)