1; RUN: not --crash llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory 2>&1 | FileCheck %s --check-prefix=ERROR
2; RUN: not --crash llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory -fast-isel 2>&1 | FileCheck %s --check-prefix=ERROR
3; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory --mtriple wasm32-unknown-emscripten | FileCheck %s --check-prefixes=CHECK,TLS
4; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -mattr=+bulk-memory --mtriple wasm32-unknown-emscripten -fast-isel | FileCheck %s --check-prefixes=CHECK,TLS
5; 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
6target triple = "wasm32-unknown-unknown"
7
8; ERROR: LLVM ERROR: only -ftls-model=local-exec is supported for now on non-Emscripten OSes: variable tls
9
10; CHECK-LABEL: address_of_tls:
11; CHECK-NEXT: .functype  address_of_tls () -> (i32)
12define i32 @address_of_tls() {
13  ; TLS-DAG: global.get __tls_base
14  ; TLS-DAG: i32.const tls@TLSREL
15  ; TLS-NEXT: i32.add
16  ; TLS-NEXT: return
17
18  ; NO-TLS-NEXT: i32.const tls
19  ; NO-TLS-NEXT: return
20  ret i32 ptrtoint(i32* @tls to i32)
21}
22
23; CHECK-LABEL: address_of_tls_external:
24; CHECK-NEXT: .functype  address_of_tls_external () -> (i32)
25define i32 @address_of_tls_external() {
26  ; TLS-DAG: global.get tls_external@GOT@TLS
27  ; TLS-NEXT: return
28
29  ; NO-TLS-NEXT: i32.const tls_external
30  ; NO-TLS-NEXT: return
31  ret i32 ptrtoint(i32* @tls_external to i32)
32}
33
34; CHECK-LABEL: ptr_to_tls:
35; CHECK-NEXT: .functype ptr_to_tls () -> (i32)
36define i32* @ptr_to_tls() {
37  ; TLS-DAG: global.get __tls_base
38  ; TLS-DAG: i32.const tls@TLSREL
39  ; TLS-NEXT: i32.add
40  ; TLS-NEXT: return
41
42  ; NO-TLS-NEXT: i32.const tls
43  ; NO-TLS-NEXT: return
44  ret i32* @tls
45}
46
47; CHECK-LABEL: ptr_to_tls_external:
48; CHECK-NEXT: .functype ptr_to_tls_external () -> (i32)
49define i32* @ptr_to_tls_external() {
50  ; TLS-DAG: global.get tls_external@GOT@TLS
51  ; TLS-NEXT: return
52
53  ; NO-TLS-NEXT: i32.const tls_external
54  ; NO-TLS-NEXT: return
55  ret i32* @tls_external
56}
57
58; CHECK-LABEL: tls_load:
59; CHECK-NEXT: .functype tls_load () -> (i32)
60define i32 @tls_load() {
61  ; TLS-DAG: global.get __tls_base
62  ; TLS-DAG: i32.const tls@TLSREL
63  ; TLS-NEXT: i32.add
64  ; TLS-NEXT: i32.load 0
65  ; TLS-NEXT: return
66
67  ; NO-TLS-NEXT: i32.const 0
68  ; NO-TLS-NEXT: i32.load tls
69  ; NO-TLS-NEXT: return
70  %tmp = load i32, i32* @tls, align 4
71  ret i32 %tmp
72}
73
74; CHECK-LABEL: tls_load_external:
75; CHECK-NEXT: .functype tls_load_external () -> (i32)
76define i32 @tls_load_external() {
77  ; TLS-DAG: global.get tls_external@GOT@TLS
78  ; TLS-NEXT: i32.load 0
79  ; TLS-NEXT: return
80
81  ; NO-TLS-NEXT: i32.const 0
82  ; NO-TLS-NEXT: i32.load tls_external
83  ; NO-TLS-NEXT: return
84  %tmp = load i32, i32* @tls_external, align 4
85  ret i32 %tmp
86}
87
88; CHECK-LABEL: tls_store:
89; CHECK-NEXT: .functype tls_store (i32) -> ()
90define void @tls_store(i32 %x) {
91  ; TLS-DAG: global.get __tls_base
92  ; TLS-DAG: i32.const tls@TLSREL
93  ; TLS-NEXT: i32.add
94  ; TLS-NEXT: i32.store 0
95  ; TLS-NEXT: return
96
97  ; NO-TLS-NEXT: i32.const 0
98  ; NO-TLS-NEXT: i32.store tls
99  ; NO-TLS-NEXT: return
100  store i32 %x, i32* @tls, align 4
101  ret void
102}
103
104; CHECK-LABEL: tls_store_external:
105; CHECK-NEXT: .functype tls_store_external (i32) -> ()
106define void @tls_store_external(i32 %x) {
107  ; TLS-DAG: global.get tls_external@GOT@TLS
108  ; TLS-NEXT: i32.store 0
109  ; TLS-NEXT: return
110
111  ; NO-TLS-NEXT: i32.const 0
112  ; NO-TLS-NEXT: i32.store tls_external
113  ; NO-TLS-NEXT: return
114  store i32 %x, i32* @tls_external, align 4
115  ret void
116}
117
118; CHECK-LABEL: tls_size:
119; CHECK-NEXT: .functype tls_size () -> (i32)
120define i32 @tls_size() {
121; CHECK-NEXT: global.get __tls_size
122; CHECK-NEXT: return
123  %1 = call i32 @llvm.wasm.tls.size.i32()
124  ret i32 %1
125}
126
127; CHECK-LABEL: tls_align:
128; CHECK-NEXT: .functype tls_align () -> (i32)
129define i32 @tls_align() {
130; CHECK-NEXT: global.get __tls_align
131; CHECK-NEXT: return
132  %1 = call i32 @llvm.wasm.tls.align.i32()
133  ret i32 %1
134}
135
136; CHECK-LABEL: tls_base:
137; CHECK-NEXT: .functype tls_base () -> (i32)
138define i8* @tls_base() {
139; CHECK-NEXT: global.get __tls_base
140; CHECK-NEXT: return
141  %1 = call i8* @llvm.wasm.tls.base()
142  ret i8* %1
143}
144
145; CHECK-LABEL: tls_base_write:
146; CHECK-NEXT: .functype tls_base_write (i32) -> ()
147define void @tls_base_write(i8** %output) {
148; CHECK-NEXT: global.get __tls_base
149; CHECK-NEXT: i32.store 0
150; CHECK-NEXT: return
151  %1 = call i8* @llvm.wasm.tls.base()
152  store i8* %1, i8** %output
153  ret void
154}
155
156; CHECK: .type tls,@object
157; TLS-NEXT: .section .tbss.tls,"T",@
158; NO-TLS-NEXT: .section .bss.tls,"",@
159; CHECK-NEXT: .p2align 2
160; CHECK-NEXT: tls:
161; CHECK-NEXT: .int32 0
162@tls = internal thread_local global i32 0
163
164@tls_external = external thread_local global i32, align 4
165
166declare i32 @llvm.wasm.tls.size.i32()
167declare i32 @llvm.wasm.tls.align.i32()
168declare i8* @llvm.wasm.tls.base()
169