Skip to content

Commit eaf2fcd

Browse files
committed
[WebAssembly] Make RefTypeMem2Local recognize target-features
Currently we check `Subtarget->hasReferenceTypes()` to decide whether to run `RefTypeMem2Local` pass: https://github.com/llvm/llvm-project/blob/6133878227efc30355c02c2f089e06ce58231a3d/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp#L491-L495 This works fine when `-mattr=+reference-types` is given in the command line (of `llc` or of `wasm-ld` in case of LTO). This also works fine if the backend is called by Clang, because Clang's feature set will be passed to the backend when creating a `TargetMachine`: https://github.com/llvm/llvm-project/blob/ac791888bbbe58651e597cf7a4b2276424b77a92/clang/lib/CodeGen/BackendUtil.cpp#L549-L550 https://github.com/llvm/llvm-project/blob/ac791888bbbe58651e597cf7a4b2276424b77a92/clang/lib/CodeGen/BackendUtil.cpp#L561-L562 But if the backend compilation is called by `llc`, a `TargetMachine` is created here: https://github.com/llvm/llvm-project/blob/bf1ad1d267b1f911cb9846403d2c3d3250a40870/llvm/tools/llc/llc.cpp#L554-L555 And if the backend is called by `wasm-ld`'s LTO, a `TargetMachine` is created here: https://github.com/llvm/llvm-project/blob/ac791888bbbe58651e597cf7a4b2276424b77a92/llvm/lib/LTO/LTOBackend.cpp#L513 At this point, in the both places, the created `TargetMachine` only has access to target features given by the command line with `-mattr=` and doesn't have access to bitcode functions' `target-features` attribute. We later gather the target features used by functions and store that info in the `TargetMachine` in `CoalesceFeaturesAndStripAtomics`, https://github.com/llvm/llvm-project/blob/ac791888bbbe58651e597cf7a4b2276424b77a92/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp#L202-L206 but this runs in the pass pipeline driven by the pass manager, so this has not run by the time we check `Subtarget->hasReferenceTypes()` in `WebAssemblyPassConfig::addISelPrepare`. So currently `RefTypeMem2Local` would not run on those functions with `"target-features"="+reference-types"` attributes if the backend is called by `llc` or `wasm-ld`. So this makes `RefTypeMem2Local` pass run unconditionally, and checks `target-featurs` function attribute to decide whether to run the pass on each function. This allows the pass to run with `wasm-ld` + LTO and `llc`, even if `-mattr=+reference-types` is not explicitly given in the command line again, as long as `+reference-types` is in the function's `target-features` attribute. This also covers the case we give the target features by the command line like `llc -mattr=+reference-types` and not in the bitcode function's attribute, because attributes given in the command line will be stored in the function's attributes anyway: https://github.com/llvm/llvm-project/blob/bd28889732e14ac6baca686c3ec99a82fc9cd89d/llvm/lib/CodeGen/CommandFlags.cpp#L673-L674 https://github.com/llvm/llvm-project/blob/bd28889732e14ac6baca686c3ec99a82fc9cd89d/llvm/lib/CodeGen/CommandFlags.cpp#L732-L733 With this PR, - `lto0.test_externref_emjs` - `thinlto0.test_externref_emjs`, - `lto0.test_externref_emjs_dynlink`, - `thinlto0.test_externref_emjs_dynlnk` pass. These currently fail but don't get checked in the CI. I think they used to pass but started to fail after llvm#83196, because we used to run mem2reg even with `-O0` before that. (`ltoN` (N > 0) tests are not affected because they run mem2reg anyway so they don't need `RefTypeMem2Local`)
1 parent 8c0f52e commit eaf2fcd

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

llvm/lib/Target/WebAssembly/WebAssemblyRefTypeMem2Local.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ bool WebAssemblyRefTypeMem2Local::runOnFunction(Function &F) {
8686
"********** Function: "
8787
<< F.getName() << '\n');
8888

89-
visit(F);
89+
if (F.getFnAttribute("target-features")
90+
.getValueAsString()
91+
.contains("+reference-types"))
92+
visit(F);
9093
return Changed;
9194
}

llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -483,16 +483,9 @@ void WebAssemblyPassConfig::addIRPasses() {
483483
}
484484

485485
void WebAssemblyPassConfig::addISelPrepare() {
486-
WebAssemblyTargetMachine *WasmTM =
487-
static_cast<WebAssemblyTargetMachine *>(TM);
488-
const WebAssemblySubtarget *Subtarget =
489-
WasmTM->getSubtargetImpl(std::string(WasmTM->getTargetCPU()),
490-
std::string(WasmTM->getTargetFeatureString()));
491-
if (Subtarget->hasReferenceTypes()) {
492-
// We need to move reference type allocas to WASM_ADDRESS_SPACE_VAR so that
493-
// loads and stores are promoted to local.gets/local.sets.
494-
addPass(createWebAssemblyRefTypeMem2Local());
495-
}
486+
// We need to move reference type allocas to WASM_ADDRESS_SPACE_VAR so that
487+
// loads and stores are promoted to local.gets/local.sets.
488+
addPass(createWebAssemblyRefTypeMem2Local());
496489
// Lower atomics and TLS if necessary
497490
addPass(new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine()));
498491

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
; RUN: llc < %s -stop-after=wasm-ref-type-mem2local | FileCheck %s
2+
3+
; This file is the same as ref-type-mem2local.ll, except we pass
4+
; '+reference-types' target feature using a function attribute instead of
5+
; '-mattr=+reference-types' command line argument.
6+
7+
target triple = "wasm32-unknown-unknown"
8+
9+
%externref = type ptr addrspace(10)
10+
%funcref = type ptr addrspace(20)
11+
12+
declare %externref @get_externref()
13+
declare %funcref @get_funcref()
14+
declare i32 @get_i32()
15+
declare void @take_externref(%externref)
16+
declare void @take_funcref(%funcref)
17+
declare void @take_i32(i32)
18+
19+
; Reference type allocas should be moved to addrspace(1)
20+
; CHECK-LABEL: @test_ref_type_mem2local
21+
define void @test_ref_type_mem2local() #0 {
22+
entry:
23+
%alloc.externref = alloca %externref, align 1
24+
%eref = call %externref @get_externref()
25+
store %externref %eref, ptr %alloc.externref, align 1
26+
%eref.loaded = load %externref, ptr %alloc.externref, align 1
27+
call void @take_externref(%externref %eref.loaded)
28+
; CHECK: %alloc.externref.var = alloca ptr addrspace(10), align 1, addrspace(1)
29+
; CHECK-NEXT: %eref = call ptr addrspace(10) @get_externref()
30+
; CHECK-NEXT: store ptr addrspace(10) %eref, ptr addrspace(1) %alloc.externref.var, align 1
31+
; CHECK-NEXT: %eref.loaded = load ptr addrspace(10), ptr addrspace(1) %alloc.externref.var, align 1
32+
; CHECK-NEXT: call void @take_externref(ptr addrspace(10) %eref.loaded)
33+
34+
%alloc.funcref = alloca %funcref, align 1
35+
%fref = call %funcref @get_funcref()
36+
store %funcref %fref, ptr %alloc.funcref, align 1
37+
%fref.loaded = load %funcref, ptr %alloc.funcref, align 1
38+
call void @take_funcref(%funcref %fref.loaded)
39+
; CHECK-NEXT: %alloc.funcref.var = alloca ptr addrspace(20), align 1, addrspace(1)
40+
; CHECK-NEXT: %fref = call ptr addrspace(20) @get_funcref()
41+
; CHECK-NEXT: store ptr addrspace(20) %fref, ptr addrspace(1) %alloc.funcref.var, align 1
42+
; CHECK-NEXT: %fref.loaded = load ptr addrspace(20), ptr addrspace(1) %alloc.funcref.var, align 1
43+
; CHECK-NEXT: call void @take_funcref(ptr addrspace(20) %fref.loaded)
44+
45+
ret void
46+
}
47+
48+
; POD type allocas should stay the same
49+
; CHECK-LABEL: @test_pod_type
50+
define void @test_pod_type() #0 {
51+
entry:
52+
%alloc.i32 = alloca i32
53+
%i32 = call i32 @get_i32()
54+
store i32 %i32, ptr %alloc.i32
55+
%i32.loaded = load i32, ptr %alloc.i32
56+
call void @take_i32(i32 %i32.loaded)
57+
; CHECK: %alloc.i32 = alloca i32, align 4{{$}}
58+
; CHECK-NOT: addrspace(1)
59+
60+
ret void
61+
}
62+
63+
attributes #0 = { "target-features"="+reference-types" }

0 commit comments

Comments
 (0)