forked from OSchip/llvm-project
[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
This commit is contained in:
parent
604f802fd3
commit
5204f7611f
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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<InputGlobal>(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<InputGlobal>(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<InputGlobal>(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<SyntheticFunction>(i32ArgSignature, "__wasm_init_tls"));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -247,6 +247,9 @@ void Writer::layoutMemory() {
|
|||
if (WasmSym::tlsSize && seg->name == ".tdata") {
|
||||
auto *tlsSize = cast<DefinedGlobal>(WasmSym::tlsSize);
|
||||
tlsSize->global->global.InitExpr.Value.Int32 = seg->size;
|
||||
|
||||
auto *tlsAlign = cast<DefinedGlobal>(WasmSym::tlsAlign);
|
||||
tlsAlign->global->global.InitExpr.Value.Int32 = 1U << seg->alignment;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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],
|
||||
[],
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue