Skip to content

Commit fdffc1d

Browse files
committed
Overload resolution for __clang_Interpreter_SetValueNoAlloc symbols to be defined with LLVM <19
1 parent 9c6be69 commit fdffc1d

File tree

1 file changed

+68
-8
lines changed

1 file changed

+68
-8
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,29 @@
9090
#include <unistd.h>
9191
#endif // WIN32
9292

93-
#if CLANG_VERSION_MAJOR > 22
93+
// Runtime symbols required if the library using JIT (Cpp::Evaluate) does not link to llvm
94+
#ifndef CPPINTEROP_USE_CLING
95+
#if CLANG_VERSION_MAJOR >= 22
9496
extern "C" void* __clang_Interpreter_SetValueWithAlloc(void* This, void* OutVal,
9597
void* OpaqueType)
9698
#else
9799
void* __clang_Interpreter_SetValueWithAlloc(void* This, void* OutVal,
98100
void* OpaqueType);
99101
#endif
100102

101-
extern "C" void __clang_Interpreter_SetValueNoAlloc(void* This,
102-
void* OutVal,
103-
void* OpaqueType, ...);
103+
#if CLANG_VERSION_MAJOR >= 19
104+
extern "C" void __clang_Interpreter_SetValueNoAlloc(void* This,
105+
void* OutVal,
106+
void* OpaqueType, ...);
107+
#elif CLANG_VERSION_MAJOR == 18
108+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*);
109+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*);
110+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, float);
111+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double);
112+
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double);
113+
void __clang_Interpreter_SetValueNoAlloc(void*,void*,void*,unsigned long long);
114+
#endif
115+
#endif // CPPINTEROP_USE_CLING
104116

105117
namespace Cpp {
106118

@@ -3488,10 +3500,12 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
34883500

34893501
// Define runtime symbols in the JIT dylib for clang-repl
34903502
#ifndef CPPINTEROP_USE_CLING
3491-
#if CLANG_VERSION_MAJOR > 22
3503+
// llvm > 22 has this defined as a C symbol that does not require mangling
3504+
#if CLANG_VERSION_MAJOR >= 22
34923505
DefineAbsoluteSymbol(*I, "__clang_Interpreter_SetValueWithAlloc",
3493-
(uint64_t)&__clang_Interpreter_SetValueNoAlloc);
3506+
(uint64_t)&__clang_Interpreter_SetValueWithAlloc);
34943507
#else
3508+
// obtain mangled name
34953509
auto* D = static_cast<clang::Decl*>(
34963510
Cpp::GetNamed("__clang_Interpreter_SetValueWithAlloc"));
34973511
if (auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
@@ -3502,8 +3516,54 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
35023516
(uint64_t)&__clang_Interpreter_SetValueWithAlloc);
35033517
}
35043518
#endif
3505-
DefineAbsoluteSymbol(*I, "__clang_Interpreter_SetValueNoAlloc",
3506-
(uint64_t)&__clang_Interpreter_SetValueNoAlloc);
3519+
// llvm < 19 has multiple overloads of __clang_Interpreter_SetValueNoAlloc
3520+
#if CLANG_VERSION_MAJOR < 19
3521+
// obtain all 6 candidates, and obtain the correct Decl for each overload using BestOverloadFunctionMatch. We then map the decl to the correct function pointer (force the compiler to find the right declarion by casting to the corresponding function pointer signature) and then register it.
3522+
const std::vector<TCppFunction_t> Methods = Cpp::GetFunctionsUsingName(Cpp::GetGlobalScope(), "__clang_Interpreter_SetValueNoAlloc");
3523+
std::string mangledName;
3524+
ASTContext& Ctxt = I->getSema().getASTContext();
3525+
auto* TAI = Ctxt.VoidPtrTy.getAsOpaquePtr();
3526+
3527+
// possible parameter lists for __clang_Interpreter_SetValueNoAlloc overloads in LLVM 18
3528+
const std::vector<std::vector<Cpp::TemplateArgInfo>> a_params = {
3529+
{TAI, TAI, TAI},
3530+
{TAI, TAI, TAI, TAI},
3531+
{TAI, TAI, TAI, Ctxt.FloatTy.getAsOpaquePtr()},
3532+
{TAI, TAI, TAI, Ctxt.DoubleTy.getAsOpaquePtr()},
3533+
{TAI, TAI, TAI, Ctxt.LongDoubleTy.getAsOpaquePtr()},
3534+
{TAI, TAI, TAI, Ctxt.UnsignedLongLongTy.getAsOpaquePtr()}
3535+
};
3536+
3537+
using FP0 = void (*)(void*, void*, void*);
3538+
using FP1 = void (*)(void*, void*, void*, void*);
3539+
using FP2 = void (*)(void*, void*, void*, float);
3540+
using FP3 = void (*)(void*, void*, void*, double);
3541+
using FP4 = void (*)(void*, void*, void*, long double);
3542+
using FP5 = void (*)(void*, void*, void*, unsigned long long);
3543+
3544+
const std::vector<void*> func_pointers = {
3545+
reinterpret_cast<void*>(static_cast<FP0>(&__clang_Interpreter_SetValueNoAlloc)),
3546+
reinterpret_cast<void*>(static_cast<FP1>(&__clang_Interpreter_SetValueNoAlloc)),
3547+
reinterpret_cast<void*>(static_cast<FP2>(&__clang_Interpreter_SetValueNoAlloc)),
3548+
reinterpret_cast<void*>(static_cast<FP3>(&__clang_Interpreter_SetValueNoAlloc)),
3549+
reinterpret_cast<void*>(static_cast<FP4>(&__clang_Interpreter_SetValueNoAlloc)),
3550+
reinterpret_cast<void*>(static_cast<FP5>(&__clang_Interpreter_SetValueNoAlloc))
3551+
};
3552+
3553+
// these symbols are not externed, so we need to mangle their names
3554+
for (size_t i = 0; i < a_params.size(); ++i) {
3555+
auto* decl = static_cast<clang::Decl*>(Cpp::BestOverloadFunctionMatch(Methods, {}, a_params[i]));
3556+
if (auto* fd = llvm::dyn_cast<clang::FunctionDecl>(decl)) {
3557+
auto gd = clang::GlobalDecl(fd);
3558+
compat::maybeMangleDeclName(gd, mangledName);
3559+
DefineAbsoluteSymbol(*I, mangledName.c_str(),
3560+
reinterpret_cast<uint64_t>(func_pointers[i]));
3561+
}
3562+
}
3563+
#else
3564+
DefineAbsoluteSymbol(*I, "__clang_Interpreter_SetValueNoAlloc",
3565+
(uint64_t)&__clang_Interpreter_SetValueNoAlloc);
3566+
#endif
35073567
#endif
35083568
return I;
35093569
}

0 commit comments

Comments
 (0)