Description
#![feature(thread_local)]
use std::cell::Cell;
#[thread_local]
static THREAD_LOCAL: Cell<bool> = const { Cell::new(false) };
pub fn pub_mentions_thread_local() {
let _ = THREAD_LOCAL;
}
#[no_mangle]
fn no_mangle_uses_thread_local() {
let r = &THREAD_LOCAL;
if !r.get() {
r.set(true);
}
}
compiles to:
no_mangle_uses_thread_local:
push rax
data16
lea rdi, [rip + example::THREAD_LOCAL::h5a1be4459c52c6f4@TLSGD]
data16
data16
rex64
call __tls_get_addr@PLT
cmp byte ptr [rax], 0
jne .LBB0_2
data16
lea rdi, [rip + example::THREAD_LOCAL::h5a1be4459c52c6f4@TLSGD]
data16
data16
rex64
call __tls_get_addr@PLT
mov byte ptr [rax], 1
.LBB0_2:
pop rax
ret
example::THREAD_LOCAL::h5a1be4459c52c6f4:
.zero 1
(https://godbolt.org/z/K69s4fzzz)
i.e. two accesses under the global-dynamic
TLS model. I have two questions here:
-
Why is the TLS resolved twice? It's sound to resolve it only once; in fact, the source code takes
&THREAD_LOCAL
just once. This might be an LLVM problem. -
Why is
global-dynamic
used instead oflocal-dynamic
? Removingpub
frompub_mentions_thread_local
, deletingpub_mentions_thread_local
altogether, or adding#[no_mangle]
to it fixes this, even though that function literally has an empty MIR. This makes me suspect this is not an LLVM bug.
I'm not positive that #[no_mangle]
is to blame here, but that's the closest I have to a non-generic title.
std::thread_local!
is unaffected.
@rustbot label +A-codegen +A-thread-locals +C-optimization +F-thread_local +T-compiler