Interactions with threads and native code

I have just begun investigating LLVM because it seems like it might be an ideal tool for building tools for playing with software. However, my current project is related to parallel programming on shared memory multiprocessor systems, so I need thread support. As far as I can tell, LLVM currently has no intrinsic support for threads, is this correct? I saw the bug that indicates that LLVM's JIT needs some locks to protect its data structures, but are there any other issues that might be preventing LLVM from executing multithreaded applications?

To help me in my investigations, I wrote a small program that calls the Linux clone system call. It turns out that this small test program executes correctly with LLVM, which surprised me. Is this just because I got lucky, or is this expected behaviour?

Does anyone have any thoughts about if or how LLVM should support threads? I was thinking that it might be worthwhile to add a few thread primitives to the llvm.* collection of instrinsics. Something like llvm.spawn, llvm.join, llvm.lock, llvm.unlock, and llvm.cas would be sufficient for my purposes.

Finally, how does LLVM interact with native code? I see in the disassembly that it declares the prototype for the clone function, but how does it locate the implementation? If it ends up calling "dlopen" and "dlsym," how does it know which library to look in? Additionally, is it possible to link against arbitrary native code libraries?

Thank you for your assistance,

Evan Jones

I have just begun investigating LLVM because it seems like it might be an ideal tool for building tools for playing with software. However, my current project is related to parallel programming on shared memory multiprocessor systems, so I need thread support. As far as I can tell, LLVM currently has no intrinsic support for threads, is this correct? I saw the bug that indicates that LLVM's JIT needs some locks to protect its data structures, but are there any other issues that might be preventing LLVM from executing multithreaded applications?

That is correct. If you try to run threaded programs in the JIT, it might run into problems if multiple functions need to JIT functions at the same time. This should be very simple to deal with, we just haven't had anyone take up the task yet. Only the JIT is affected here, not the static code generator or C backend.

I'm pretty sure that this is the only issue with threaded programs.

To help me in my investigations, I wrote a small program that calls the Linux clone system call. It turns out that this small test program executes correctly with LLVM, which surprised me. Is this just because I got lucky, or is this expected behaviour?

That is expected behavior. You should be able to write programs that use clone(), native pthreads libraries, native uithreads, native win32 threads, etc. LLVM also fully supports the volatile attribute in C.

Does anyone have any thoughts about if or how LLVM should support threads? I was thinking that it might be worthwhile to add a few thread primitives to the llvm.* collection of instrinsics. Something like llvm.spawn, llvm.join, llvm.lock, llvm.unlock, and llvm.cas would be sufficient for my purposes.

There has definitely been talk about this. We are slated to get very low-level primitives for compare&swap and atomic increment. I can't say when they will be added (I'm not doing the work myself) but I've been told it should be soon.

The other ones are higher level. There is a balance here between what we want to express directly in llvm, and what we want defer to native libraries. The argument for putting things into LLVM is that it makes it easier for front-end people to produce portable bytecode files (they don't have to provide target-specific runtime libraries). The argument against is that we only want target- and language-independent capabilities to be added to LLVM.

I'm confident that this will eventually be added to LLVM, it's just a matter of finding the right things to add, ones that make sense in the context of LLVM.

Finally, how does LLVM interact with native code? I see in the disassembly that it declares the prototype for the clone function, but how does it locate the implementation? If it ends up calling "dlopen" and "dlsym," how does it know which library to look in? Additionally, is it possible to link against arbitrary native code libraries?

LLVM works exactly like a native compiler. If you call an external function you have to link to the appropriate (possibly native) library with -lFOO options. Note that llvm-gcc takes these options which are particularly handy:

llvm-gcc x.c -o a.out -Wl,-native <- produce a native a.out file with our backend
llvm-gcc x.c -o a.out -Wl,-native-cbe <- produce a native a.out file with the C backend & GCC.

-Chris

That is correct. If you try to run threaded programs in the JIT, it might run into problems if multiple functions need to JIT functions at the same time. This should be very simple to deal with, we just haven't had anyone take up the task yet. Only the JIT is affected here, not the static code generator or C backend.

Well, I'll take a look at the JIT code and see if I am up to it. I need to do a project for the parallel processing course I am taking right now anyway, and doing work that is actually useful to someone would be a much better use for my time.

What about the LLVM interpreter, for situations where there is no JIT? Is it thread-safe?

Does anyone have any thoughts about if or how LLVM should support threads? I was thinking that it might be worthwhile to add a few thread primitives to the llvm.* collection of instrinsics. Something like llvm.spawn, llvm.join, llvm.lock, llvm.unlock, and llvm.cas would be sufficient for my purposes.

There has definitely been talk about this. We are slated to get very low-level primitives for compare&swap and atomic increment. I can't say when they will be added (I'm not doing the work myself) but I've been told it should be soon.

Random related thought: I think it is unfortunate that more processors don't natively support load-linked/store-conditional.

The other ones are higher level. There is a balance here between what we want to express directly in llvm, and what we want defer to native libraries. The argument for putting things into LLVM is that it makes it easier for front-end people to produce portable bytecode files (they don't have to provide target-specific runtime libraries). The argument against is that we only want target- and language-independent capabilities to be added to LLVM.

I definitely think that some sort of portable support for threads would be very useful. At the very least, adding primitives to libSystem and having some portable way to link to them from the bytecode would likely solve most of the problem.

LLVM works exactly like a native compiler. If you call an external function you have to link to the appropriate (possibly native) library with -lFOO options.

Ah, I figured it out: lli calls dlopen on the libraries supplied by a command line parameter. The nasty compatibility hacks that are performed on Linux for libpthreads were preventing llvm-gcc from adding the correct parameter to the script file. When I manually added "-load=/lib/tls/libpthread-0.29.so" it worked.

Thank you for your fast response,

Evan Jones

That is correct. If you try to run threaded programs in the JIT, it might run into problems if multiple functions need to JIT functions at the same time. This should be very simple to deal with, we just haven't had anyone take up the task yet. Only the JIT is affected here, not the static code generator or C backend.

Well, I'll take a look at the JIT code and see if I am up to it. I need to do a project for the parallel processing course I am taking right now anyway, and doing work that is actually useful to someone would be a much better use for my time.

That would be great. As a first implementation, I would suggest adding a lock to the ExecutionEngine class in include/llvm/ExecutionEngine/ExecutionEngine.h, locking it when particular state is accessed. Note that the JIT subclasses this in lib/ExecutionEngine/JIT/JIT.h, so its accesses should be synchronized as well.

The only really tricky thing about this is making the locking portable across platforms. However, I think the include/llvm/Support/ThreadSupport.h file should export what you need.

What about the LLVM interpreter, for situations where there is no JIT? Is it thread-safe?

Yes, I believe it is thread safe. However, is not widely used and is REALLY slow (even for an interpreter).

Does anyone have any thoughts about if or how LLVM should support threads? I was thinking that it might be worthwhile to add a few thread primitives to the llvm.* collection of instrinsics. Something like llvm.spawn, llvm.join, llvm.lock, llvm.unlock, and llvm.cas would be sufficient for my purposes.

There has definitely been talk about this. We are slated to get very low-level primitives for compare&swap and atomic increment. I can't say when they will be added (I'm not doing the work myself) but I've been told it should be soon.

Random related thought: I think it is unfortunate that more processors don't natively support load-linked/store-conditional.

Indeed. Unfortunately they can't be emulated well on processors that do not support them.

The other ones are higher level. There is a balance here between what we want to express directly in llvm, and what we want defer to native libraries. The argument for putting things into LLVM is that it makes it easier for front-end people to produce portable bytecode files (they don't have to provide target-specific runtime libraries). The argument against is that we only want target- and language-independent capabilities to be added to LLVM.

I definitely think that some sort of portable support for threads would be very useful. At the very least, adding primitives to libSystem and having some portable way to link to them from the bytecode would likely solve most of the problem.

It's not clear to me that this is something that needs to be implemented as instructions or intrinsics in the LLVM representation itself. To me, there would be just as much value defining a standard LLVM runtime library for threads that front-ends could choose to link to. This is similar to how the GC support works: only the bare minimum support required for pulling references out of the stack is built into LLVM, the rest (e.g. the specific GC algorithm being used) is related to a runtime library.

LLVM works exactly like a native compiler. If you call an external function you have to link to the appropriate (possibly native) library with -lFOO options.

Ah, I figured it out: lli calls dlopen on the libraries supplied by a command line parameter. The nasty compatibility hacks that are performed on Linux for libpthreads were preventing llvm-gcc from adding the correct parameter to the script file. When I manually added "-load=/lib/tls/libpthread-0.29.so" it worked.

Ok, yes, as you figured out, the JIT is a bit different. :slight_smile:

-Chris

I took a quick look at the code this evening and I think I have a first cut plan: Add a mutex to ExecutionEngine, then lock it in *all* the public methods in ExecutionEngine and JIT. This is not a smart approach, but it would work. The problem is that any other subclasses would also need to do the same thing, at least if they access any of the state in ExecutionEngine.

Any thoughts about this? Am I crazy, or would it work? Are there any other classes that would need similar modification?

Evan Jones

I think that will work fine. The only two subclasses of that are the JIT and Interpreter.

-Chris