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