diff options
| author | Guanzhong Chen <gzchen@google.com> | 2019-07-16 22:00:45 +0000 |
|---|---|---|
| committer | Guanzhong Chen <gzchen@google.com> | 2019-07-16 22:00:45 +0000 |
| commit | 42bba4b852b1a63db4043798bba7d9fcea61cbaf (patch) | |
| tree | 6d17f3ede350dc96c647deda73fdbe78a44c6071 /lld/test | |
| parent | 21f2858dcf3a556f01f6ae151bf7638b70f01c02 (diff) | |
| download | bcm5719-llvm-42bba4b852b1a63db4043798bba7d9fcea61cbaf.tar.gz bcm5719-llvm-42bba4b852b1a63db4043798bba7d9fcea61cbaf.zip | |
[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
Diffstat (limited to 'lld/test')
| -rw-r--r-- | lld/test/wasm/data-segments.ll | 20 | ||||
| -rw-r--r-- | lld/test/wasm/tls.ll | 81 |
2 files changed, 96 insertions, 5 deletions
diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll index a9a403f3c5f..944895a0d39 100644 --- a/lld/test/wasm/data-segments.ll +++ b/lld/test/wasm/data-segments.ll @@ -4,11 +4,11 @@ ; atomics => active segments (TODO: error) ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.o -o %t.atomics.wasm -; RUN: obj2yaml %t.atomics.wasm | FileCheck %s --check-prefix ACTIVE +; RUN: obj2yaml %t.atomics.wasm | FileCheck %s --check-prefixes ACTIVE,ACTIVE-TLS ; atomics, active segments => active segments ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.o -o %t.atomics.active.wasm -; RUN: obj2yaml %t.atomics.active.wasm | FileCheck %s --check-prefix ACTIVE +; RUN: obj2yaml %t.atomics.active.wasm | FileCheck %s --check-prefixes ACTIVE,ACTIVE-TLS ; atomics, passive segments => error ; RUN: not wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --passive-segments %t.atomics.o -o %t.atomics.passive.wasm 2>&1 | FileCheck %s --check-prefix ERROR @@ -27,15 +27,15 @@ ; atomics, bulk memory => active segments (TODO: passive) ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.wasm -; RUN: obj2yaml %t.atomics.bulk-mem.wasm | FileCheck %s --check-prefix ACTIVE +; RUN: obj2yaml %t.atomics.bulk-mem.wasm | FileCheck %s --check-prefixes ACTIVE,ACTIVE-TLS ; atomics, bulk memory, active segments => active segments ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.active.wasm -; RUN: obj2yaml %t.atomics.bulk-mem.active.wasm | FileCheck %s --check-prefix ACTIVE +; RUN: obj2yaml %t.atomics.bulk-mem.active.wasm | FileCheck %s --check-prefixes ACTIVE,ACTIVE-TLS ; atomics, bulk memory, passive segments => passive segments ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --passive-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.passive.wasm -; RUN: obj2yaml %t.atomics.bulk-mem.passive.wasm | FileCheck %s --check-prefix PASSIVE +; RUN: obj2yaml %t.atomics.bulk-mem.passive.wasm | FileCheck %s --check-prefixes PASSIVE,PASSIVE-TLS target triple = "wasm32-unknown-unknown" @@ -54,6 +54,9 @@ target triple = "wasm32-unknown-unknown" ; ACTIVE-NEXT: - Index: 0 ; ACTIVE-NEXT: Locals: [] ; ACTIVE-NEXT: Body: 0B +; ACTIVE-TLS-NEXT: - Index: 1 +; ACTIVE-TLS-NEXT: Locals: [] +; ACTIVE-TLS-NEXT: Body: 0B ; ACTIVE-NEXT: - Type: DATA ; ACTIVE-NEXT: Segments: ; ACTIVE-NEXT: - SectionOffset: 7 @@ -80,6 +83,8 @@ target triple = "wasm32-unknown-unknown" ; ACTIVE-NEXT: FunctionNames: ; ACTIVE-NEXT: - Index: 0 ; ACTIVE-NEXT: Name: __wasm_call_ctors +; ACTIVE-TLS-NEXT: - Index: 1 +; ACTIVE-TLS-NEXT: Name: __wasm_init_tls ; PASSIVE-LABEL: - Type: CODE ; PASSIVE-NEXT: Functions: @@ -89,6 +94,9 @@ target triple = "wasm32-unknown-unknown" ; PASSIVE-NEXT: - Index: 1 ; PASSIVE-NEXT: Locals: [] ; PASSIVE-NEXT: Body: 41800841004114FC080000FC090041940841004190CE00FC080100FC090141A4D6004100410DFC080200FC09020B +; PASSIVE-TLS-NEXT: - Index: 2 +; PASSIVE-TLS-NEXT: Locals: [] +; PASSIVE-TLS-NEXT: Body: 0B ; PASSIVE-NEXT: - Type: DATA ; PASSIVE-NEXT: Segments: ; PASSIVE-NEXT: - SectionOffset: 3 @@ -108,3 +116,5 @@ target triple = "wasm32-unknown-unknown" ; PASSIVE-NEXT: Name: __wasm_call_ctors ; PASSIVE-NEXT: - Index: 1 ; PASSIVE-NEXT: Name: __wasm_init_memory +; PASSIVE-TLS-NEXT: - Index: 2 +; PASSIVE-TLS-NEXT: Name: __wasm_init_tls diff --git a/lld/test/wasm/tls.ll b/lld/test/wasm/tls.ll new file mode 100644 index 00000000000..b570d467568 --- /dev/null +++ b/lld/test/wasm/tls.ll @@ -0,0 +1,81 @@ +; RUN: llc -mattr=+bulk-memory -filetype=obj %s -o %t.o + +target triple = "wasm32-unknown-unknown" + +@tls1 = thread_local(localexec) global i32 1, align 4 +@no_tls = global i32 0, align 4 +@tls2 = thread_local(localexec) global i32 1, align 4 + +define i32* @tls1_addr() { + ret i32* @tls1 +} + +define i32* @tls2_addr() { + ret i32* @tls2 +} + +; RUN: wasm-ld -no-gc-sections --shared-memory --max-memory=131072 --no-entry -o %t.wasm %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +; RUN: wasm-ld -no-gc-sections --shared-memory --max-memory=131072 --no-merge-data-segments --no-entry -o %t.wasm %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +; CHECK: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 8 + + +; CHECK: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: [] +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: [] +; CHECK-NEXT: Body: 20002401200041004108FC0800000B + +; Expected body of __wasm_init_tls: +; local.get 0 +; global.set 1 +; local.get 0 +; i32.const 0 +; i32.const 8 +; memory.init 0, 0 +; end + +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: [] +; CHECK-NEXT: Body: 2381808080004180808080006A0B + +; Expected body of tls1_addr: +; global.get 1 +; i32.const 0 +; i32.add +; end + +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: [] +; CHECK-NEXT: Body: 2381808080004184808080006A0B + +; Expected body of tls1_addr: +; global.get 1 +; i32.const 4 +; i32.add +; end |

