[LLVMdev] Bug Report -- Possible optimizer bug with thread_local variables

Tom Bergan tbergan at cs.washington.edu
Wed Nov 7 23:43:11 PST 2012


Hello,

I apologize if this has already been fixed or reported.  I believe there is
a bug in the way the optimizer deals with thread_local variables.  The
attached program, test.c, has a thread-local variable "int Foo" and a
global variable "int *Ptr".  The program takes the following steps:

1) The main thread spawns a new thread and waits
2) The new thread writes Foo = 50 and Ptr = &Foo, then signals the main
thread and waits
3) The main thread prints *Ptr, releases the new thread, and exits

The crux of this example is that the main thread obtains a pointer to the
new thread's TLS via "Ptr".  When I compile with gcc, the program prints
"50" as expected.  When I compile with LLVM, the program prints "0".  This
is confirmed in the following three versions of LLVM:
* the 2.9 release
* whatever version of LLVM is driving http://llvm.org/demo/index.cgi
* svn revision 167568 on trunk (this was the most-recent revision as of a
few hours ago)

I've attached the optimized bytecode in test.ll.  This was produced by
http://llvm.org/demo/index.cgi with "LTO" checked.  You can see the bug in
main(), where LLVM has optimized the load "*Ptr" into the following
instructions:

  %.b = load i1* @Foo.b, align 1   ; main() loads its own @Foo.b, not the
@Foo.b written by run()
  %5 = select i1 %.b, i32 50, i32 0

My guess is that the optimizer does not realize that thread_local addresses
are not constant in the same way that global addresses are constant, since
each thread_local variable actually names N variables, one for each of N
running threads.  Thus, it's not safe to optimize across two accesses of a
thread_local variable unless it can be proven that both accesses will be
performed by the same thread.

In terms of LLVM's design, I've noticed that thread_local variables are
represented in the same way as ordinary variables (via
llvm::GlobalVariable) except that the "isThreadLocal" flag is true.  This
strikes me as a potential for confusion, because you have this one corner
case -- thread_locals -- in which an "llvm::Constant" is not really a
"constant" in the same way as other constants.  This might be related to
http://llvm.org/bugs/show_bug.cgi?id=13720, and perhaps a few other bugs.

-Tom

p.s. If anyone is hit by this bug, my current workaround is to declare Ptr
volatile:
    int * volatile Ptr;

Note that if the volatile is moved under the pointer, as in the following:
    volatile int * Ptr;

then the bug reappears, as the load "*Ptr" in main() will be incorrectly
optimized to:
    %5 = load volatile i32* @Foo, align 4
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20121107/ec954dff/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.c
Type: text/x-csrc
Size: 868 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20121107/ec954dff/attachment.c>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.ll
Type: application/octet-stream
Size: 3226 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20121107/ec954dff/attachment.obj>


More information about the llvm-dev mailing list