When compiling WebAssembly with ThinLTO, functions are partitioned into isolated `.bc` modules and dispatched to individual LTO backend threads. During code generation, the `CoalesceFeaturesAndStripAtomics` pass iterates over the module to gather the union of target features (like `+atomics`) attached to defined functions. In particular when not using threads, it lowers away atomics and TLS variables to their single-threaded equivalents. However, if a partitioned module only contains globally defined TLS variables (e.g. there are no functions, or all functions were fully inlined or stripped by dropDeadSymbols before ThinLTO optimization), the module becomes completely devoid of function definitions. The coalescing pass then falls back to fetching features from the `TargetMachine`. Because in LTO the `TargetMachine` defaults to a generic target without atomics enabled, the TLS is lowered away and the `wasm-feature-atomics` flag is omitted from the resulting ThinLTO object partition, causing `wasm-ld` to immediately reject it. To fix this we take advantage of the fact that the linker always knows whether threads are being used (via the --shared-memory flag). When using shared memory, we enable +atomics and +bulk-memory in the TargetMachine that is used for the backend, and the feature coalescing pass will correctly detect the use of therads. This only makes sense for atomics because of the global linker configuration; for other features we wouldn't be able to do this, but we don't rewrite away any other features anyway.
41 lines
1.3 KiB
LLVM
41 lines
1.3 KiB
LLVM
; RUN: split-file %s %t
|
|
; RUN: opt -module-summary %t/main.ll -o %t.main.o
|
|
; RUN: opt -module-summary %t/empty.ll -o %t.empty.o
|
|
; RUN: wasm-ld --shared-memory %t.main.o %t.empty.o -o %t.wasm
|
|
; RUN: llvm-nm %t.wasm | FileCheck %s
|
|
|
|
; This test ensures that when an unused function with target-features="+atomics,+bulk-memory"
|
|
; is stripped during ThinLTO, the resulting empty module does not fall back to generic TargetMachine
|
|
; features and incorrectly omit the atomics/bulk-memory features from the generated custom sections.
|
|
;
|
|
; Since --shared-memory is passed to wasm-ld, `+atomics` and `+bulk-memory` are propagated
|
|
; to the LTO Config via MAttrs, bypassing the functional absence of attributes.
|
|
|
|
; CHECK-NOT: error:
|
|
; CHECK: _start
|
|
|
|
;--- main.ll
|
|
target triple = "wasm32-unknown-emscripten"
|
|
|
|
define void @_start() #0 {
|
|
entry:
|
|
ret void
|
|
}
|
|
|
|
attributes #0 = { "target-features"="+atomics,+bulk-memory,+mutable-globals,+sign-ext" }
|
|
|
|
;--- empty.ll
|
|
target triple = "wasm32-unknown-emscripten"
|
|
|
|
; Thread-local variable that forces generation of TLS layout
|
|
@my_tls = thread_local global i32 42, align 4
|
|
|
|
; This function will be removed by dropDeadSymbols because it's unused,
|
|
; taking its target-features attribute block along with it.
|
|
define void @unused() #0 {
|
|
entry:
|
|
ret void
|
|
}
|
|
|
|
attributes #0 = { "target-features"="+atomics,+bulk-memory,+mutable-globals,+sign-ext" }
|