https://github.com/conrade-ctc updated https://github.com/llvm/llvm-project/pull/208413
>From 2b538f07423d9999e55c88bfa2a6d465a579e4dd Mon Sep 17 00:00:00 2001 From: Emery Conrad <[email protected]> Date: Thu, 9 Jul 2026 05:15:58 -0500 Subject: [PATCH] Reland "[ORC] Track __emutls_t definitions in IRMaterializationUnit" (#207161) Reverted in #207775: the new test exposed that clang-repl on Darwin cannot resolve __emutls_get_address at all -- it lives in the compiler-rt builtins static archive, which nothing links into the process (on Linux it resolves from libgcc_s.so). Reland with a Darwin fix: force-link __emutls_get_address into clang and define it as an absolute symbol in the process-symbols JITDylib, in-process only. Co-developed-with-the-help-of: Claude Code (Claude Opus 4.8, human in the loop) --- clang/lib/Interpreter/IncrementalExecutor.cpp | 28 +++++++++++++++++++ clang/test/Interpreter/emulated-tls.cpp | 25 +++++++++++++++++ llvm/lib/ExecutionEngine/Orc/Layer.cpp | 1 + 3 files changed, 54 insertions(+) create mode 100644 clang/test/Interpreter/emulated-tls.cpp diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp index 65cb29a2f441a..63929a241da08 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -27,6 +27,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h" #include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h" #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" @@ -60,6 +61,12 @@ #include <unistd.h> #endif +#ifdef __APPLE__ +// Provided by the compiler-rt builtins archive, which implements the +// emulated-TLS runtime on Darwin. +extern "C" void *__emutls_get_address(void *); +#endif + namespace clang { IncrementalExecutorBuilder::~IncrementalExecutorBuilder() = default; @@ -388,6 +395,27 @@ IncrementalExecutorBuilder::create(llvm::orc::ThreadSafeContext &TSC, if (!JB) return JB.takeError(); JITBuilder = std::move(*JB); +#ifdef __APPLE__ + // TODO: Switch to native TLS on Darwin once clang-repl can adopt the ORC + // runtime (which provides __emutls_get_address and supports the full TLS + // lifecycle). That will also remove the in-process-only constraint below. + // + // On Darwin, thread_locals are lowered to emulated TLS, but the runtime + // (__emutls_get_address) lives in the compiler-rt builtins archive and + // nothing else in this process references it, so it isn't linked in and + // process-symbol lookup cannot find it. Taking its address here forces + // the archive member into the binary; defining it as an absolute symbol + // makes it visible to JIT'd code. In-process execution only: the address + // is meaningless in an out-of-process executor. + JITBuilder->setNotifyCreatedCallback([](llvm::orc::LLJIT &J) { + auto &JD = J.getProcessSymbolsJITDylib() ? *J.getProcessSymbolsJITDylib() + : J.getMainJITDylib(); + return JD.define(llvm::orc::absoluteSymbols( + {{J.mangleAndIntern("__emutls_get_address"), + {llvm::orc::ExecutorAddr::fromPtr(&__emutls_get_address), + llvm::JITSymbolFlags::Exported}}})); + }); +#endif } llvm::Error Err = llvm::Error::success(); diff --git a/clang/test/Interpreter/emulated-tls.cpp b/clang/test/Interpreter/emulated-tls.cpp new file mode 100644 index 0000000000000..73afe172ef6d9 --- /dev/null +++ b/clang/test/Interpreter/emulated-tls.cpp @@ -0,0 +1,25 @@ +// REQUIRES: host-supports-jit +// UNSUPPORTED: system-windows +// +// An inline function that odr-uses a non-zero-initialized thread_local is +// emitted as a weak (linkonce_odr) definition into every PartialTranslationUnit +// that references it. With emulated TLS that set includes an __emutls_t.<var> +// symbol. When a later PTU re-defines the same weak set, ORC's +// IRMaterializationUnit::discard() must find each duplicated symbol in its +// SymbolToDefinition map. The emulated-TLS path used to register __emutls_t.<var> +// in SymbolFlags but not SymbolToDefinition, so discarding it dereferenced +// end() -- an assertion failure in +Asserts builds and heap corruption +// otherwise. Two PTUs each pulling in the same inline worker reproduces it. +// +// RUN: cat %s | clang-repl | FileCheck %s + +extern "C" int printf(const char *, ...); +template <int Tag> struct HeavyThing { static thread_local int tls; }; +template <int Tag> thread_local int HeavyThing<Tag>::tls = Tag + 1; +inline int worker() { return HeavyThing<1>::tls; } +int callA() { return worker(); } +int callB() { return worker(); } +auto r = printf("tls = %d, %d\n", callA(), callB()); +// CHECK: tls = 2, 2 + +%quit diff --git a/llvm/lib/ExecutionEngine/Orc/Layer.cpp b/llvm/lib/ExecutionEngine/Orc/Layer.cpp index eb144275da589..5e95b8c73b482 100644 --- a/llvm/lib/ExecutionEngine/Orc/Layer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Layer.cpp @@ -70,6 +70,7 @@ IRMaterializationUnit::IRMaterializationUnit( auto EmuTLST = Mangle(("__emutls_t." + GV.getName()).str()); SymbolFlags[EmuTLST] = Flags; + SymbolToDefinition[EmuTLST] = &GV; } continue; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
