Skip to content

Commit 0e37487

Browse files
committed
[WebAssembly] Fix selection of global calls
When selecting calls, currently we unconditionally remove `Wrapper`s of the call target. But we are supposed to do that only when the target is a function, an external symbol (= library function), or an alias of a function. Otherwise we end up directly calling globals that are not functions. Fixes llvm#60003. Reviewed By: tlively, HerrCai0907 Differential Revision: https://reviews.llvm.org/D147397
1 parent 47fc018 commit 0e37487

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,22 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
249249
SmallVector<SDValue, 16> Ops;
250250
for (size_t i = 1; i < Node->getNumOperands(); ++i) {
251251
SDValue Op = Node->getOperand(i);
252-
if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper)
253-
Op = Op->getOperand(0);
252+
// Remove the wrapper when the call target is a function, an external
253+
// symbol (which will be lowered to a library function), or an alias of
254+
// a function. If the target is not a function/external symbol, we
255+
// shouldn't remove the wrapper, because we cannot call it directly and
256+
// instead we want it to be loaded with a CONST instruction and called
257+
// with a call_indirect later.
258+
if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper) {
259+
SDValue NewOp = Op->getOperand(0);
260+
if (auto *GlobalOp = dyn_cast<GlobalAddressSDNode>(NewOp.getNode())) {
261+
if (isa<Function>(
262+
GlobalOp->getGlobal()->stripPointerCastsAndAliases()))
263+
Op = NewOp;
264+
} else if (isa<ExternalSymbolSDNode>(NewOp.getNode())) {
265+
Op = NewOp;
266+
}
267+
}
254268
Ops.push_back(Op);
255269
}
256270

llvm/test/CodeGen/WebAssembly/call.ll

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -mattr=+sign-ext,+simd128 | FileCheck --check-prefixes=CHECK,NO-TAIL %s
2-
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 -mattr=+sign-ext,+simd128 | FileCheck --check-prefixes=CHECK,NO-TAIL %s
1+
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -mattr=+sign-ext,+simd128 | FileCheck --check-prefixes=CHECK,SLOW,NO-TAIL %s
2+
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 -mattr=+sign-ext,+simd128 | FileCheck --check-prefixes=CHECK,FAST,NO-TAIL %s
33
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -mattr=+sign-ext,+simd128,+tail-call | FileCheck --check-prefixes=CHECK,SLOW-TAIL %s
44
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 -mattr=+sign-ext,+simd128,+tail-call | FileCheck --check-prefixes=CHECK,FAST-TAIL %s
55

@@ -251,6 +251,46 @@ entry:
251251
ret void
252252
}
253253

254+
; Calling non-functional globals should be lowered to call_indirects.
255+
; CHECK-LABEL: call_indirect_int:
256+
; CHECK: i32.const $push[[L0:[0-9]+]]=, global_i8
257+
; CHECK-NEXT: call_indirect $pop[[L0]]
258+
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, global_i32
259+
; CHECK-NEXT: call_indirect $pop[[L1]]
260+
@global_i8 = global i8 0
261+
@global_i32 = global i32 0
262+
define void @call_indirect_int() {
263+
call void @global_i8()
264+
call void @global_i32()
265+
ret void
266+
}
267+
268+
; Calling aliases of non-functional globals should be lowered to call_indirects.
269+
; CHECK-LABEL: call_indirect_int_alias:
270+
; CHECK: i32.const $push[[L0:[0-9]+]]=, global_i8_alias
271+
; CHECK-NEXT: call_indirect $pop[[L0]]
272+
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, global_i32_alias
273+
; CHECK-NEXT: call_indirect $pop[[L1]]
274+
@global_i8_alias = alias i8, ptr @global_i8
275+
@global_i32_alias = alias i32, ptr @global_i32
276+
define void @call_indirect_int_alias() {
277+
call void @global_i8_alias()
278+
call void @global_i32_alias()
279+
ret void
280+
}
281+
282+
; Ideally calling aliases of functions should be lowered to direct calls. We
283+
; support this in the normal (=slow) isel.
284+
; CHECK-LABEL: call_func_alias:
285+
; SLOW: call func_alias
286+
; FAST: i32.const $push[[L0:[0-9]+]]=, func_alias
287+
; FAST-NEXT: call_indirect $pop[[L0]]
288+
@func_alias = alias void (), ptr @call_void_nullary
289+
define void @call_func_alias() {
290+
call void @func_alias()
291+
ret void
292+
}
293+
254294
; TODO: test the following:
255295
; - More argument combinations.
256296
; - Tail call.

0 commit comments

Comments
 (0)