From 5204f7611f4ad6549921f9fa757823e77f39ce32 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Fri, 19 Jul 2019 23:34:16 +0000 Subject: [PATCH] [WebAssembly] Compute and export TLS block alignment Summary: Add immutable WASM global `__tls_align` which stores the alignment requirements of the TLS segment. Add `__builtin_wasm_tls_align()` intrinsic to get this alignment in Clang. The expected usage has now changed to: __wasm_init_tls(memalign(__builtin_wasm_tls_align(), __builtin_wasm_tls_size())); Reviewers: tlively, aheejin, sbc100, sunfish, alexcrichton Reviewed By: tlively Subscribers: dschuff, jgravelle-google, hiraditya, cfe-commits, llvm-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D65028 llvm-svn: 366624 --- clang/include/clang/Basic/BuiltinsWebAssembly.def | 1 + clang/lib/CodeGen/CGBuiltin.cpp | 5 +++ clang/test/CodeGen/builtins-wasm.c | 6 +++ lld/test/wasm/tls-align.ll | 51 ++++++++++++++++++++++ lld/test/wasm/tls.ll | 27 ++++++++++++ lld/wasm/Driver.cpp | 31 ++++++------- lld/wasm/Symbols.cpp | 1 + lld/wasm/Symbols.h | 4 ++ lld/wasm/Writer.cpp | 3 ++ llvm/include/llvm/IR/IntrinsicsWebAssembly.td | 5 +++ .../Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp | 10 +++++ .../Target/WebAssembly/WebAssemblyMCInstLower.cpp | 2 +- .../CodeGen/WebAssembly/tls-general-dynamic.ll | 10 +++++ 13 files changed, 137 insertions(+), 19 deletions(-) create mode 100644 lld/test/wasm/tls-align.ll diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def index 0c0ca9e..acd713d 100644 --- a/clang/include/clang/Basic/BuiltinsWebAssembly.def +++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -31,6 +31,7 @@ TARGET_BUILTIN(__builtin_wasm_data_drop, "vIUi", "", "bulk-memory") // 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 diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 8c7411fc..dee1e20 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -13924,6 +13924,11 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, 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); diff --git a/clang/test/CodeGen/builtins-wasm.c b/clang/test/CodeGen/builtins-wasm.c index 8f8e7a9..f3129b7 100644 --- a/clang/test/CodeGen/builtins-wasm.c +++ b/clang/test/CodeGen/builtins-wasm.c @@ -44,6 +44,12 @@ __SIZE_TYPE__ tls_size() { // 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() diff --git a/lld/test/wasm/tls-align.ll b/lld/test/wasm/tls-align.ll new file mode 100644 index 0000000..0dd557a --- /dev/null +++ b/lld/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 diff --git a/lld/test/wasm/tls.ll b/lld/test/wasm/tls.ll index e410e08..5327eb9 100644 --- a/lld/test/wasm/tls.ll +++ b/lld/test/wasm/tls.ll @@ -14,6 +14,13 @@ define i32* @tls2_addr() { 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 @@ define i32* @tls2_addr() { ; 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 @@ define i32* @tls2_addr() { ; 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 @@ define i32* @tls2_addr() { ; 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 diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 003dd0d..c3f24be 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -450,6 +450,16 @@ createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) { 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 @@ static void createSyntheticSymbols() { } 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")); diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp index 7d8d532..05cf2ef 100644 --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -35,6 +35,7 @@ DefinedData *WasmSym::heapBase; GlobalSymbol *WasmSym::stackPointer; GlobalSymbol *WasmSym::tlsBase; GlobalSymbol *WasmSym::tlsSize; +GlobalSymbol *WasmSym::tlsAlign; UndefinedGlobal *WasmSym::tableBase; UndefinedGlobal *WasmSym::memoryBase; diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h index f4816aae..83d3926 100644 --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -435,6 +435,10 @@ struct WasmSym { // 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; diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 68e001c..2dbff1b 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -247,6 +247,9 @@ void Writer::layoutMemory() { 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; } } diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td index 0dc68a5..4750c31 100644 --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -133,6 +133,11 @@ def int_wasm_tls_size : [], [IntrNoMem, IntrSpeculatable]>; +def int_wasm_tls_align : + Intrinsic<[llvm_anyint_ty], + [], + [IntrNoMem, IntrSpeculatable]>; + def int_wasm_tls_base : Intrinsic<[llvm_ptr_ty], [], diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp index aaf3259..4de002c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -224,6 +224,16 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { 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; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp index 288b991..d9089de 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -79,7 +79,7 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol( // 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); diff --git a/llvm/test/CodeGen/WebAssembly/tls-general-dynamic.ll b/llvm/test/CodeGen/WebAssembly/tls-general-dynamic.ll index f121d62..41dbd47 100644 --- a/llvm/test/CodeGen/WebAssembly/tls-general-dynamic.ll +++ b/llvm/test/CodeGen/WebAssembly/tls-general-dynamic.ll @@ -75,6 +75,15 @@ define i32 @tls_size() { 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 @@ define void @tls_base_write(i8** %output) { @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() -- 2.7.4