[WebAssembly] Implement thread-local storage (local-exec model)
Summary:
Thread local variables are placed inside a `.tdata` segment. Their symbols are
offsets from the start of the segment. The address of a thread local variable
is computed as `__tls_base` + the offset from the start of the segment.
`.tdata` segment is a passive segment and `memory.init` is used once per thread
to initialize the thread local storage.
`__tls_base` is a wasm global. Since each thread has its own wasm instance,
it is effectively thread local. Currently, `__tls_base` must be initialized
at thread startup, and so cannot be used with dynamic libraries.
`__tls_base` is to be initialized with a new linker-synthesized function,
`__wasm_init_tls`, which takes as an argument a block of memory to use as the
storage for thread locals. It then initializes the block of memory and sets
`__tls_base`. As `__wasm_init_tls` will handle the memory initialization,
the memory does not have to be zeroed.
To help allocating memory for thread-local storage, a new compiler intrinsic
is introduced: `__builtin_wasm_tls_size()`. This instrinsic function returns
the size of the thread-local storage for the current function.
The expected usage is to run something like the following upon thread startup:
__wasm_init_tls(malloc(__builtin_wasm_tls_size()));
Reviewers: tlively, aheejin, kripken, sbc100
Subscribers: dschuff, jgravelle-google, hiraditya, sunfish, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D64537
llvm-svn: 366272
2019-07-16 22:00:45 +00:00
|
|
|
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory | FileCheck %s --check-prefixes=CHECK,TLS
|
|
|
|
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory -fast-isel | FileCheck %s --check-prefixes=CHECK,TLS
|
|
|
|
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=-bulk-memory | FileCheck %s --check-prefixes=CHECK,NO-TLS
|
2018-03-20 22:01:32 +00:00
|
|
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
2018-05-10 17:49:11 +00:00
|
|
|
target triple = "wasm32-unknown-unknown"
|
2018-03-20 22:01:32 +00:00
|
|
|
|
[WebAssembly] Implement thread-local storage (local-exec model)
Summary:
Thread local variables are placed inside a `.tdata` segment. Their symbols are
offsets from the start of the segment. The address of a thread local variable
is computed as `__tls_base` + the offset from the start of the segment.
`.tdata` segment is a passive segment and `memory.init` is used once per thread
to initialize the thread local storage.
`__tls_base` is a wasm global. Since each thread has its own wasm instance,
it is effectively thread local. Currently, `__tls_base` must be initialized
at thread startup, and so cannot be used with dynamic libraries.
`__tls_base` is to be initialized with a new linker-synthesized function,
`__wasm_init_tls`, which takes as an argument a block of memory to use as the
storage for thread locals. It then initializes the block of memory and sets
`__tls_base`. As `__wasm_init_tls` will handle the memory initialization,
the memory does not have to be zeroed.
To help allocating memory for thread-local storage, a new compiler intrinsic
is introduced: `__builtin_wasm_tls_size()`. This instrinsic function returns
the size of the thread-local storage for the current function.
The expected usage is to run something like the following upon thread startup:
__wasm_init_tls(malloc(__builtin_wasm_tls_size()));
Reviewers: tlively, aheejin, kripken, sbc100
Subscribers: dschuff, jgravelle-google, hiraditya, sunfish, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D64537
llvm-svn: 366272
2019-07-16 22:00:45 +00:00
|
|
|
; CHECK-LABEL: address_of_tls:
|
|
|
|
; CHECK-NEXT: .functype address_of_tls () -> (i32)
|
2018-03-20 22:01:32 +00:00
|
|
|
define i32 @address_of_tls() {
|
[WebAssembly] Implement thread-local storage (local-exec model)
Summary:
Thread local variables are placed inside a `.tdata` segment. Their symbols are
offsets from the start of the segment. The address of a thread local variable
is computed as `__tls_base` + the offset from the start of the segment.
`.tdata` segment is a passive segment and `memory.init` is used once per thread
to initialize the thread local storage.
`__tls_base` is a wasm global. Since each thread has its own wasm instance,
it is effectively thread local. Currently, `__tls_base` must be initialized
at thread startup, and so cannot be used with dynamic libraries.
`__tls_base` is to be initialized with a new linker-synthesized function,
`__wasm_init_tls`, which takes as an argument a block of memory to use as the
storage for thread locals. It then initializes the block of memory and sets
`__tls_base`. As `__wasm_init_tls` will handle the memory initialization,
the memory does not have to be zeroed.
To help allocating memory for thread-local storage, a new compiler intrinsic
is introduced: `__builtin_wasm_tls_size()`. This instrinsic function returns
the size of the thread-local storage for the current function.
The expected usage is to run something like the following upon thread startup:
__wasm_init_tls(malloc(__builtin_wasm_tls_size()));
Reviewers: tlively, aheejin, kripken, sbc100
Subscribers: dschuff, jgravelle-google, hiraditya, sunfish, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D64537
llvm-svn: 366272
2019-07-16 22:00:45 +00:00
|
|
|
; TLS-DAG: global.get __tls_base
|
|
|
|
; TLS-DAG: i32.const tls
|
|
|
|
; TLS-NEXT: i32.add
|
|
|
|
; TLS-NEXT: return
|
|
|
|
|
|
|
|
; NO-TLS-NEXT: i32.const tls
|
|
|
|
; NO-TLS-NEXT: return
|
2018-03-20 22:01:32 +00:00
|
|
|
ret i32 ptrtoint(i32* @tls to i32)
|
|
|
|
}
|
|
|
|
|
[WebAssembly] Implement thread-local storage (local-exec model)
Summary:
Thread local variables are placed inside a `.tdata` segment. Their symbols are
offsets from the start of the segment. The address of a thread local variable
is computed as `__tls_base` + the offset from the start of the segment.
`.tdata` segment is a passive segment and `memory.init` is used once per thread
to initialize the thread local storage.
`__tls_base` is a wasm global. Since each thread has its own wasm instance,
it is effectively thread local. Currently, `__tls_base` must be initialized
at thread startup, and so cannot be used with dynamic libraries.
`__tls_base` is to be initialized with a new linker-synthesized function,
`__wasm_init_tls`, which takes as an argument a block of memory to use as the
storage for thread locals. It then initializes the block of memory and sets
`__tls_base`. As `__wasm_init_tls` will handle the memory initialization,
the memory does not have to be zeroed.
To help allocating memory for thread-local storage, a new compiler intrinsic
is introduced: `__builtin_wasm_tls_size()`. This instrinsic function returns
the size of the thread-local storage for the current function.
The expected usage is to run something like the following upon thread startup:
__wasm_init_tls(malloc(__builtin_wasm_tls_size()));
Reviewers: tlively, aheejin, kripken, sbc100
Subscribers: dschuff, jgravelle-google, hiraditya, sunfish, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D64537
llvm-svn: 366272
2019-07-16 22:00:45 +00:00
|
|
|
; CHECK-LABEL: ptr_to_tls:
|
|
|
|
; CHECK-NEXT: .functype ptr_to_tls () -> (i32)
|
|
|
|
define i32* @ptr_to_tls() {
|
|
|
|
; TLS-DAG: global.get __tls_base
|
|
|
|
; TLS-DAG: i32.const tls
|
|
|
|
; TLS-NEXT: i32.add
|
|
|
|
; TLS-NEXT: return
|
|
|
|
|
|
|
|
; NO-TLS-NEXT: i32.const tls
|
|
|
|
; NO-TLS-NEXT: return
|
|
|
|
ret i32* @tls
|
|
|
|
}
|
|
|
|
|
|
|
|
; CHECK-LABEL: tls_load:
|
|
|
|
; CHECK-NEXT: .functype tls_load () -> (i32)
|
|
|
|
define i32 @tls_load() {
|
|
|
|
; TLS-DAG: global.get __tls_base
|
|
|
|
; TLS-DAG: i32.const tls
|
|
|
|
; TLS-NEXT: i32.add
|
|
|
|
; TLS-NEXT: i32.load 0
|
|
|
|
; TLS-NEXT: return
|
|
|
|
|
|
|
|
; NO-TLS-NEXT: i32.const 0
|
|
|
|
; NO-TLS-NEXT: i32.load tls
|
|
|
|
; NO-TLS-NEXT: return
|
|
|
|
%tmp = load i32, i32* @tls, align 4
|
|
|
|
ret i32 %tmp
|
|
|
|
}
|
|
|
|
|
|
|
|
; CHECK-LABEL: tls_store:
|
|
|
|
; CHECK-NEXT: .functype tls_store (i32) -> ()
|
|
|
|
define void @tls_store(i32 %x) {
|
|
|
|
; TLS-DAG: global.get __tls_base
|
|
|
|
; TLS-DAG: i32.const tls
|
|
|
|
; TLS-NEXT: i32.add
|
|
|
|
; TLS-NEXT: i32.store 0
|
|
|
|
; TLS-NEXT: return
|
|
|
|
|
|
|
|
; NO-TLS-NEXT: i32.const 0
|
|
|
|
; NO-TLS-NEXT: i32.store tls
|
|
|
|
; NO-TLS-NEXT: return
|
|
|
|
store i32 %x, i32* @tls, align 4
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; CHECK-LABEL: tls_size:
|
|
|
|
; CHECK-NEXT: .functype tls_size () -> (i32)
|
|
|
|
define i32 @tls_size() {
|
|
|
|
; CHECK-NEXT: global.get __tls_size
|
|
|
|
; CHECK-NEXT: return
|
|
|
|
%1 = call i32 @llvm.wasm.tls.size.i32()
|
|
|
|
ret i32 %1
|
|
|
|
}
|
|
|
|
|
|
|
|
; CHECK: .type tls,@object
|
|
|
|
; TLS-NEXT: .section .tbss.tls,"",@
|
|
|
|
; NO-TLS-NEXT: .section .bss.tls,"",@
|
|
|
|
; CHECK-NEXT: .p2align 2
|
|
|
|
; CHECK-NEXT: tls:
|
|
|
|
; CHECK-NEXT: .int32 0
|
|
|
|
@tls = internal thread_local(localexec) global i32 0
|
|
|
|
|
|
|
|
declare i32 @llvm.wasm.tls.size.i32()
|