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
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@366272
91177308-0d34-0410-b5e6-
96231b3b80d8
TARGET_BUILTIN(__builtin_wasm_memory_init, "vIUiIUiv*UiUi", "", "bulk-memory")
TARGET_BUILTIN(__builtin_wasm_data_drop, "vIUi", "", "bulk-memory")
+// Thread-local storage
+TARGET_BUILTIN(__builtin_wasm_tls_size, "z", "nc", "bulk-memory")
+
// Floating point min/max
BUILTIN(__builtin_wasm_min_f32, "fff", "nc")
BUILTIN(__builtin_wasm_max_f32, "fff", "nc")
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_data_drop);
return Builder.CreateCall(Callee, {Arg});
}
+ case WebAssembly::BI__builtin_wasm_tls_size: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_size, ResultType);
+ return Builder.CreateCall(Callee);
+ }
case WebAssembly::BI__builtin_wasm_throw: {
Value *Tag = EmitScalarExpr(E->getArg(0));
Value *Obj = EmitScalarExpr(E->getArg(1));
// WEBASSEMBLY64: call void @llvm.wasm.data.drop(i32 3)
}
+__SIZE_TYPE__ tls_size() {
+ return __builtin_wasm_tls_size();
+ // WEBASSEMBLY32: call i32 @llvm.wasm.tls.size.i32()
+ // WEBASSEMBLY64: call i64 @llvm.wasm.tls.size.i64()
+}
+
void throw(void *obj) {
return __builtin_wasm_throw(0, obj);
// WEBASSEMBLY32: call void @llvm.wasm.throw(i32 0, i8* %{{.*}})