LLJIT vs. thread-local storage

Hi Geoff,

Ok — I think I’m caught up now. You’re using LLVM 8, and thread locals are working for you on ORCv1, but not ORCv2.

Is there any chance that ORC v2 will support thread-local variables in the foreseeable future?

I think so. I was able to reproduce an issue that looks related to yours on my Darwin machine:

In resolving { (“___emutls_v.x”: 0x000000012a406000 [Data]), (“___emutls_t.x”: 0x000000012a406020 [Data]), (“_main”: 0x000000012a405000 [Callable]) }
Assertion failed: (I != SymbolFlags.end() && “Resolving symbol outside this responsibility set”), function notifyResolved, file llvm/lib/ExecutionEngine/Orc/Core.cpp, line 448.

If I look at what was supposed to be resolved (the “responsibility set”) I see that the JIT expected a definition for _x, but instead it got an unexpected definition for __emutls_t.x. You’re seeing the reverse: the JIT linker is trying to resolve __emutls_t.x (presumably you’ve compiled some code with an extern therad_local reference), but the JIT only knows about _x.

The reason for the change in behavior has to do with concurrency support, which was introduced in ORCv2. To make concurrency safe you need to declare the symbols that any program representation will produce up front (So we can know which program representation to compile, kick off its compilation, and synchronize around it). Usually, knowing what symbols a program representation will produce is easy: You just mangle all the defined symbol names and you’re done. In this case though emulated TLS will rename some symbols during compilation. I think the solution is to teach the JIT to mangle IR thread-local names (with an _emutls_t. prefix) when emulated TLS is enabled. I will take a shot at this tomorrow.

— Lang.