[llvm] 74f9841 - [lld][WebAssembly] Allow use of statically allocated TLS region.
Sam Clegg via llvm-commits
llvm-commits at lists.llvm.org
Mon May 23 17:27:44 PDT 2022
Author: Sam Clegg
Date: 2022-05-23T17:27:17-07:00
New Revision: 74f98419770041deb983b4f736ebdc06de4ee2ac
URL: https://github.com/llvm/llvm-project/commit/74f98419770041deb983b4f736ebdc06de4ee2ac
DIFF: https://github.com/llvm/llvm-project/commit/74f98419770041deb983b4f736ebdc06de4ee2ac.diff
LOG: [lld][WebAssembly] Allow use of statically allocated TLS region.
It turns out we were already allocating static address space for TLS
data along with the non-TLS static data, but this space was going
unused/ignored.
With this change, we include the TLS segment in `__wasm_init_memory`
(which does the work of loading the passive segments into memory when a
module is first loaded). We also set the `__tls_base` global to point
to the start of this segment.
This means that the runtime can use this static copy of the TLS data for
the first/primary thread if it chooses, rather than doing a runtime
allocation prior to calling `__wasm_init_tls`.
Practically speaking, this will allow emscripten to avoid dynamic
allocation of TLS region on the main thread.
Differential Revision: https://reviews.llvm.org/D126107
Added:
Modified:
lld/test/wasm/data-segments.ll
lld/test/wasm/tls_init_symbols.s
lld/wasm/Writer.cpp
llvm/include/llvm/BinaryFormat/Wasm.h
Removed:
################################################################################
diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll
index 25b45982fe8bc..bfba82ee29cf2 100644
--- a/lld/test/wasm/data-segments.ll
+++ b/lld/test/wasm/data-segments.ll
@@ -128,7 +128,7 @@
; PASSIVE-PIC-NEXT: Locals:
; PASSIVE32-PIC-NEXT: - Type: I32
; PASSIVE64-PIC-NEXT: - Type: I64
-; PASSIVE-PIC-NEXT: Count: 1
+; PASSIVE-PIC-NEXT: Count: 2
; PASSIVE-PIC-NEXT: Body: {{.*}}
; PASSIVE-PIC-NEXT: - Index: 3
; PASSIVE-PIC-NEXT: Locals: []
@@ -178,6 +178,19 @@
; DIS-NEXT: # 2: down to label0
; DIS-NEXT: end
+; NOPIC-DIS-NEXT: [[PTR]].const 1024
+; NOPIC-DIS-NEXT: [[PTR]].const 1024
+; NOPIC-DIS-NEXT: global.set 1
+; PIC-DIS-NEXT: [[PTR]].const 0
+; PIC-DIS-NEXT: global.get 1
+; PIC-DIS-NEXT: [[PTR]].add
+; PIC-DIS-NEXT: local.tee 1
+; PIC-DIS-NEXT: global.set {{\d*}}
+; PIC-DIS-NEXT: local.get 1
+; DIS-NEXT: i32.const 0
+; DIS-NEXT: i32.const 4
+; DIS-NEXT: memory.init 0, 0
+
; NOPIC-DIS-NEXT: [[PTR]].const 1028
; PIC-DIS-NEXT: [[PTR]].const 4
; PIC-DIS-NEXT: global.get 1
diff --git a/lld/test/wasm/tls_init_symbols.s b/lld/test/wasm/tls_init_symbols.s
index 1470e0658e008..601766d681d85 100644
--- a/lld/test/wasm/tls_init_symbols.s
+++ b/lld/test/wasm/tls_init_symbols.s
@@ -42,8 +42,10 @@ tls_sym:
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: Name: __wasm_init_tls
# CHECK-NEXT: - Index: 2
-# CHECK-NEXT: Name: __wasm_apply_global_tls_relocs
+# CHECK-NEXT: Name: __wasm_init_memory
# CHECK-NEXT: - Index: 3
+# CHECK-NEXT: Name: __wasm_apply_global_tls_relocs
+# CHECK-NEXT: - Index: 4
# CHECK-NEXT: Name: _start
# DIS: <__wasm_init_tls>:
@@ -53,7 +55,7 @@ tls_sym:
# DIS-NEXT: i32.const 0
# DIS-NEXT: i32.const 4
# DIS-NEXT: memory.init 0, 0
-# DIS-NEXT: call 2
+# DIS-NEXT: call 3
# DIS-NEXT: end
# DIS: <__wasm_apply_global_tls_relocs>:
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index fa5b8d5db0e80..9e3e32c183f19 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -218,6 +218,7 @@ void Writer::writeSections() {
}
static void setGlobalPtr(DefinedGlobal *g, uint64_t memoryPtr) {
+ LLVM_DEBUG(dbgs() << "setGlobalPtr " << g->getName() << " -> " << memoryPtr << "\n");
g->global->setPointerValue(memoryPtr);
}
@@ -276,13 +277,15 @@ void Writer::layoutMemory() {
memoryPtr, seg->size, seg->alignment));
if (!config->relocatable && seg->isTLS()) {
- if (config->sharedMemory) {
+ if (WasmSym::tlsSize) {
auto *tlsSize = cast<DefinedGlobal>(WasmSym::tlsSize);
setGlobalPtr(tlsSize, seg->size);
-
+ }
+ if (WasmSym::tlsAlign) {
auto *tlsAlign = cast<DefinedGlobal>(WasmSym::tlsAlign);
setGlobalPtr(tlsAlign, int64_t{1} << seg->alignment);
- } else if (WasmSym::tlsBase) {
+ }
+ if (!config->sharedMemory && WasmSym::tlsBase) {
auto *tlsBase = cast<DefinedGlobal>(WasmSym::tlsBase);
setGlobalPtr(tlsBase, memoryPtr);
}
@@ -970,9 +973,6 @@ static void createFunction(DefinedFunction *func, StringRef bodyContent) {
}
bool Writer::needsPassiveInitialization(const OutputSegment *segment) {
- // TLS segments are initialized separately
- if (segment->isTLS())
- return false;
// If bulk memory features is supported then we can perform bss initialization
// (via memory.fill) during `__wasm_init_memory`.
if (config->importMemory && !segment->requiredInBinary())
@@ -1002,6 +1002,11 @@ void Writer::createSyntheticInitFunctions() {
"__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN,
make<SyntheticFunction>(nullSignature, "__wasm_init_memory"));
WasmSym::initMemory->markLive();
+ if (config->sharedMemory) {
+ // This global is assigned during __wasm_init_memory in the shared memory
+ // case.
+ WasmSym::tlsBase->markLive();
+ }
}
if (config->sharedMemory && out.globalSec->needsTLSRelocations()) {
@@ -1126,7 +1131,7 @@ void Writer::createInitMemoryFunction() {
// With PIC code we cache the flag address in local 0
if (config->isPic) {
writeUleb128(os, 1, "num local decls");
- writeUleb128(os, 1, "local count");
+ writeUleb128(os, 2, "local count");
writeU8(os, is64 ? WASM_TYPE_I64 : WASM_TYPE_I32, "address type");
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
@@ -1177,10 +1182,31 @@ void Writer::createInitMemoryFunction() {
if (config->isPic) {
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
- "memory_base");
+ "__memory_base");
writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD,
"i32.add");
}
+
+ // When we initialize the TLS segment we also set the `__tls_base`
+ // global. This allows the runtime to use this static copy of the
+ // TLS data for the first/main thread.
+ if (config->sharedMemory && s->isTLS()) {
+ if (config->isPic) {
+ // Cache the result of the addionion in local 0
+ writeU8(os, WASM_OPCODE_LOCAL_TEE, "local.tee");
+ writeUleb128(os, 1, "local 1");
+ } else {
+ writePtrConst(os, s->startVA, is64, "destination address");
+ }
+ writeU8(os, WASM_OPCODE_GLOBAL_SET, "GLOBAL_SET");
+ writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(),
+ "__tls_base");
+ if (config->isPic) {
+ writeU8(os, WASM_OPCODE_LOCAL_GET, "local.tee");
+ writeUleb128(os, 1, "local 1");
+ }
+ }
+
if (s->isBss) {
writeI32Const(os, 0, "fill value");
writeI32Const(os, s->size, "memory region size");
@@ -1243,6 +1269,10 @@ void Writer::createInitMemoryFunction() {
for (const OutputSegment *s : segments) {
if (needsPassiveInitialization(s) && !s->isBss) {
+ // The TLS region should not be dropped since its is needed
+ // during the intiailizing of each thread (__wasm_init_tls).
+ if (config->sharedMemory && s->isTLS())
+ continue;
// data.drop instruction
writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
writeUleb128(os, WASM_OPCODE_DATA_DROP, "data.drop");
@@ -1440,7 +1470,6 @@ void Writer::createInitTLSFunction() {
writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set");
writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "global index");
- WasmSym::tlsBase->markLive();
// FIXME(wvo): this local needs to be I64 in wasm64, or we need an extend op.
writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get");
@@ -1623,8 +1652,10 @@ void Writer::run() {
}
}
- if (WasmSym::initTLS && WasmSym::initTLS->isLive())
+ if (WasmSym::initTLS && WasmSym::initTLS->isLive()) {
+ log("-- createInitTLSFunction");
createInitTLSFunction();
+ }
if (errorCount())
return;
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 23773b1af9d70..2419a06fbe96c 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -283,6 +283,7 @@ enum : unsigned {
WASM_OPCODE_CALL = 0x10,
WASM_OPCODE_LOCAL_GET = 0x20,
WASM_OPCODE_LOCAL_SET = 0x21,
+ WASM_OPCODE_LOCAL_TEE = 0x22,
WASM_OPCODE_GLOBAL_GET = 0x23,
WASM_OPCODE_GLOBAL_SET = 0x24,
WASM_OPCODE_I32_STORE = 0x36,
More information about the llvm-commits
mailing list