Index: cfe/trunk/include/clang/Basic/BuiltinsWebAssembly.def =================================================================== --- cfe/trunk/include/clang/Basic/BuiltinsWebAssembly.def +++ cfe/trunk/include/clang/Basic/BuiltinsWebAssembly.def @@ -31,6 +31,7 @@ // Thread-local storage TARGET_BUILTIN(__builtin_wasm_tls_size, "z", "nc", "bulk-memory") +TARGET_BUILTIN(__builtin_wasm_tls_align, "z", "nc", "bulk-memory") TARGET_BUILTIN(__builtin_wasm_tls_base, "v*", "nU", "bulk-memory") // Floating point min/max Index: cfe/trunk/lib/CodeGen/CGBuiltin.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGBuiltin.cpp +++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp @@ -13924,6 +13924,11 @@ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_size, ResultType); return Builder.CreateCall(Callee); } + case WebAssembly::BI__builtin_wasm_tls_align: { + llvm::Type *ResultType = ConvertType(E->getType()); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_align, ResultType); + return Builder.CreateCall(Callee); + } case WebAssembly::BI__builtin_wasm_tls_base: { Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_base); return Builder.CreateCall(Callee); Index: cfe/trunk/test/CodeGen/builtins-wasm.c =================================================================== --- cfe/trunk/test/CodeGen/builtins-wasm.c +++ cfe/trunk/test/CodeGen/builtins-wasm.c @@ -44,6 +44,12 @@ // WEBASSEMBLY64: call i64 @llvm.wasm.tls.size.i64() } +__SIZE_TYPE__ tls_align() { + return __builtin_wasm_tls_align(); + // WEBASSEMBLY32: call i32 @llvm.wasm.tls.align.i32() + // WEBASSEMBLY64: call i64 @llvm.wasm.tls.align.i64() +} + void *tls_base() { return __builtin_wasm_tls_base(); // WEBASSEMBLY: call i8* @llvm.wasm.tls.base() Index: lld/trunk/test/wasm/tls-align.ll =================================================================== --- lld/trunk/test/wasm/tls-align.ll +++ lld/trunk/test/wasm/tls-align.ll @@ -0,0 +1,51 @@ +; RUN: llc -mattr=+bulk-memory -filetype=obj %s -o %t.o + +target triple = "wasm32-unknown-unknown" + +@no_tls = global i32 0, align 4 +@tls1 = thread_local(localexec) global i32 1, align 4 +@tls2 = thread_local(localexec) global i32 1, align 16 + +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 + +; 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: 66608 + +; __tls_base +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 + +; __tls_size +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 20 + +; __tls_align +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 16 Index: lld/trunk/test/wasm/tls.ll =================================================================== --- lld/trunk/test/wasm/tls.ll +++ lld/trunk/test/wasm/tls.ll @@ -14,6 +14,13 @@ ret i32* @tls2 } +define i32 @tls_align() { + %1 = call i32 @llvm.wasm.tls.align.i32() + ret i32 %1 +} + +declare i32 @llvm.wasm.tls.align.i32() + ; RUN: wasm-ld -no-gc-sections --shared-memory --max-memory=131072 --no-entry -o %t.wasm %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s @@ -28,12 +35,16 @@ ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66576 + +; __tls_base ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 0 + +; __tls_size ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false @@ -41,6 +52,14 @@ ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 8 +; __tls_align +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 4 + ; CHECK: - Type: CODE ; CHECK-NEXT: Functions: @@ -77,3 +96,11 @@ ; i32.const 4 ; i32.add ; end + +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: [] +; CHECK-NEXT: Body: 2383808080000B + +; Expected body of tls1_addr: +; global.get 3 +; end Index: lld/trunk/wasm/Driver.cpp =================================================================== --- lld/trunk/wasm/Driver.cpp +++ lld/trunk/wasm/Driver.cpp @@ -450,6 +450,16 @@ return sym; } +static GlobalSymbol *createGlobalVariable(StringRef name, bool isMutable) { + llvm::wasm::WasmGlobal wasmGlobal; + wasmGlobal.Type = {WASM_TYPE_I32, isMutable}; + wasmGlobal.InitExpr.Value.Int32 = 0; + wasmGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; + wasmGlobal.SymbolName = name; + return symtab->addSyntheticGlobal(name, WASM_SYMBOL_VISIBILITY_HIDDEN, + make(wasmGlobal, nullptr)); +} + // Create ABI-defined synthetic symbols static void createSyntheticSymbols() { static WasmSignature nullSignature = {{}, {}}; @@ -517,24 +527,9 @@ } if (config->sharedMemory && !config->shared) { - llvm::wasm::WasmGlobal tlsBaseGlobal; - tlsBaseGlobal.Type = {WASM_TYPE_I32, true}; - tlsBaseGlobal.InitExpr.Value.Int32 = 0; - tlsBaseGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; - tlsBaseGlobal.SymbolName = "__tls_base"; - WasmSym::tlsBase = - symtab->addSyntheticGlobal("__tls_base", WASM_SYMBOL_VISIBILITY_HIDDEN, - make(tlsBaseGlobal, nullptr)); - - llvm::wasm::WasmGlobal tlsSizeGlobal; - tlsSizeGlobal.Type = {WASM_TYPE_I32, false}; - tlsSizeGlobal.InitExpr.Value.Int32 = 0; - tlsSizeGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; - tlsSizeGlobal.SymbolName = "__tls_size"; - WasmSym::tlsSize = - symtab->addSyntheticGlobal("__tls_size", WASM_SYMBOL_VISIBILITY_HIDDEN, - make(tlsSizeGlobal, nullptr)); - + WasmSym::tlsBase = createGlobalVariable("__tls_base", true); + WasmSym::tlsSize = createGlobalVariable("__tls_size", false); + WasmSym::tlsAlign = createGlobalVariable("__tls_align", false); WasmSym::initTLS = symtab->addSyntheticFunction( "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, make(i32ArgSignature, "__wasm_init_tls")); Index: lld/trunk/wasm/Symbols.h =================================================================== --- lld/trunk/wasm/Symbols.h +++ lld/trunk/wasm/Symbols.h @@ -435,6 +435,10 @@ // Symbol whose value is the size of the TLS block. static GlobalSymbol *tlsSize; + // __tls_size + // Symbol whose value is the alignment of the TLS block. + static GlobalSymbol *tlsAlign; + // __data_end // Symbol marking the end of the data and bss. static DefinedData *dataEnd; Index: lld/trunk/wasm/Symbols.cpp =================================================================== --- lld/trunk/wasm/Symbols.cpp +++ lld/trunk/wasm/Symbols.cpp @@ -35,6 +35,7 @@ GlobalSymbol *WasmSym::stackPointer; GlobalSymbol *WasmSym::tlsBase; GlobalSymbol *WasmSym::tlsSize; +GlobalSymbol *WasmSym::tlsAlign; UndefinedGlobal *WasmSym::tableBase; UndefinedGlobal *WasmSym::memoryBase; Index: lld/trunk/wasm/Writer.cpp =================================================================== --- lld/trunk/wasm/Writer.cpp +++ lld/trunk/wasm/Writer.cpp @@ -247,6 +247,9 @@ if (WasmSym::tlsSize && seg->name == ".tdata") { auto *tlsSize = cast(WasmSym::tlsSize); tlsSize->global->global.InitExpr.Value.Int32 = seg->size; + + auto *tlsAlign = cast(WasmSym::tlsAlign); + tlsAlign->global->global.InitExpr.Value.Int32 = 1U << seg->alignment; } } Index: llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td =================================================================== --- llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td +++ llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td @@ -133,6 +133,11 @@ [], [IntrNoMem, IntrSpeculatable]>; +def int_wasm_tls_align : + Intrinsic<[llvm_anyint_ty], + [], + [IntrNoMem, IntrSpeculatable]>; + def int_wasm_tls_base : Intrinsic<[llvm_ptr_ty], [], Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -224,6 +224,16 @@ ReplaceNode(Node, TLSSize); return; } + case Intrinsic::wasm_tls_align: { + MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); + assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); + + MachineSDNode *TLSAlign = CurDAG->getMachineNode( + WebAssembly::GLOBAL_GET_I32, DL, PtrVT, + CurDAG->getTargetExternalSymbol("__tls_align", MVT::i32)); + ReplaceNode(Node, TLSAlign); + return; + } } break; } Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -79,7 +79,7 @@ // Clang-provided symbols. if (strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0 || strcmp(Name, "__memory_base") == 0 || strcmp(Name, "__table_base") == 0 || - strcmp(Name, "__tls_size") == 0) { + strcmp(Name, "__tls_size") == 0 || strcmp(Name, "__tls_align") == 0) { bool Mutable = strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0; WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); Index: llvm/trunk/test/CodeGen/WebAssembly/tls-general-dynamic.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/tls-general-dynamic.ll +++ llvm/trunk/test/CodeGen/WebAssembly/tls-general-dynamic.ll @@ -75,6 +75,15 @@ ret i32 %1 } +; CHECK-LABEL: tls_align: +; CHECK-NEXT: .functype tls_align () -> (i32) +define i32 @tls_align() { +; CHECK-NEXT: global.get __tls_align +; CHECK-NEXT: return + %1 = call i32 @llvm.wasm.tls.align.i32() + ret i32 %1 +} + ; CHECK-LABEL: tls_base: ; CHECK-NEXT: .functype tls_base () -> (i32) define i8* @tls_base() { @@ -104,4 +113,5 @@ @tls = internal thread_local global i32 0 declare i32 @llvm.wasm.tls.size.i32() +declare i32 @llvm.wasm.tls.align.i32() declare i8* @llvm.wasm.tls.base()