diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp index fa5776cddcd29..b03b35028c69c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -123,7 +123,7 @@ static SDValue getTagSymNode(int Tag, SelectionDAG *DAG) { static APInt encodeFunctionSignature(SelectionDAG *DAG, SDLoc &DL, SmallVector &Returns, SmallVector &Params) { - auto toWasmValType = [&](MVT VT) { + auto toWasmValType = [](MVT VT) { if (VT == MVT::i32) { return wasm::ValType::I32; } @@ -244,10 +244,18 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { MCSymbol *Table = WebAssembly::getOrCreateFunctionTableSymbol( MF.getContext(), Subtarget); SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT); - SDValue FuncRef = SDValue( - CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL, - MVT::funcref, TableSym, Node->getOperand(1)), - 0); + SDValue FuncPtr = Node->getOperand(1); + if (Subtarget->hasAddr64() && FuncPtr.getValueType() == MVT::i64) { + // table.get expects an i32 but on 64 bit platforms the function pointer + // is an i64. In that case, i32.wrap_i64 to convert. + FuncPtr = SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64, DL, + MVT::i32, FuncPtr), + 0); + } + SDValue FuncRef = + SDValue(CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL, + MVT::funcref, TableSym, FuncPtr), + 0); // Encode the signature information into the type index placeholder. // This gets decoded and converted into the actual type signature in diff --git a/llvm/test/CodeGen/WebAssembly/ref-test-func.ll b/llvm/test/CodeGen/WebAssembly/ref-test-func.ll index e3760a07c6445..e4014ba73119b 100644 --- a/llvm/test/CodeGen/WebAssembly/ref-test-func.ll +++ b/llvm/test/CodeGen/WebAssembly/ref-test-func.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 -; RUN: llc < %s --mtriple=wasm32-unknown-unknown -mcpu=mvp -mattr=+reference-types | FileCheck --check-prefixes CHECK,CHK32 %s -; RUN: llc < %s --mtriple=wasm64-unknown-unknown -mcpu=mvp -mattr=+reference-types | FileCheck --check-prefixes CHECK,CHK64 %s +; RUN: llc < %s --mtriple=wasm32-unknown-unknown -mcpu=mvp -mattr=+reference-types -verify-machineinstrs | FileCheck --check-prefixes CHECK,CHK32 %s +; RUN: llc < %s --mtriple=wasm64-unknown-unknown -mcpu=mvp -mattr=+reference-types -verify-machineinstrs | FileCheck --check-prefixes CHECK,CHK64 %s define void @test_fpsig_void_void(ptr noundef %func) local_unnamed_addr #0 { ; CHECK-LABEL: test_fpsig_void_void: @@ -8,6 +8,7 @@ define void @test_fpsig_void_void(ptr noundef %func) local_unnamed_addr #0 { ; CHK64: .functype test_fpsig_void_void (i64) -> () ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 0 +; CHK64-NEXT: i32.wrap_i64 ; CHECK-NEXT: table.get __indirect_function_table ; CHECK-NEXT: ref.test () -> () ; CHECK-NEXT: call use @@ -24,6 +25,7 @@ define void @test_fpsig_return_i32(ptr noundef %func) local_unnamed_addr #0 { ; CHK64: .functype test_fpsig_return_i32 (i64) -> () ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 0 +; CHK64-NEXT: i32.wrap_i64 ; CHECK-NEXT: table.get __indirect_function_table ; CHECK-NEXT: ref.test () -> (i32) ; CHECK-NEXT: call use @@ -40,6 +42,7 @@ define void @test_fpsig_return_i64(ptr noundef %func) local_unnamed_addr #0 { ; CHK64: .functype test_fpsig_return_i64 (i64) -> () ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 0 +; CHK64-NEXT: i32.wrap_i64 ; CHECK-NEXT: table.get __indirect_function_table ; CHECK-NEXT: ref.test () -> (i64) ; CHECK-NEXT: call use @@ -56,6 +59,7 @@ define void @test_fpsig_return_f32(ptr noundef %func) local_unnamed_addr #0 { ; CHK64: .functype test_fpsig_return_f32 (i64) -> () ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 0 +; CHK64-NEXT: i32.wrap_i64 ; CHECK-NEXT: table.get __indirect_function_table ; CHECK-NEXT: ref.test () -> (f32) ; CHECK-NEXT: call use @@ -72,6 +76,7 @@ define void @test_fpsig_return_f64(ptr noundef %func) local_unnamed_addr #0 { ; CHK64: .functype test_fpsig_return_f64 (i64) -> () ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 0 +; CHK64-NEXT: i32.wrap_i64 ; CHECK-NEXT: table.get __indirect_function_table ; CHECK-NEXT: ref.test () -> (f64) ; CHECK-NEXT: call use @@ -89,6 +94,7 @@ define void @test_fpsig_param_i32(ptr noundef %func) local_unnamed_addr #0 { ; CHK64: .functype test_fpsig_param_i32 (i64) -> () ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 0 +; CHK64-NEXT: i32.wrap_i64 ; CHECK-NEXT: table.get __indirect_function_table ; CHECK-NEXT: ref.test (f64) -> () ; CHECK-NEXT: call use @@ -106,6 +112,7 @@ define void @test_fpsig_multiple_params_and_returns(ptr noundef %func) local_unn ; CHK64: .functype test_fpsig_multiple_params_and_returns (i64) -> () ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 0 +; CHK64-NEXT: i32.wrap_i64 ; CHECK-NEXT: table.get __indirect_function_table ; CHECK-NEXT: ref.test (i64, f32, i64) -> (i32, i64, f32, f64) ; CHECK-NEXT: call use @@ -117,4 +124,23 @@ entry: } +define void @test_fpsig_ptrs(ptr noundef %func) local_unnamed_addr #0 { +; CHECK-LABEL: test_fpsig_ptrs: +; CHK32: .functype test_fpsig_ptrs (i32) -> () +; CHK64: .functype test_fpsig_ptrs (i64) -> () +; CHECK-NEXT: # %bb.0: # %entry +; CHECK-NEXT: local.get 0 +; CHK64-NEXT: i32.wrap_i64 +; CHECK-NEXT: table.get __indirect_function_table +; CHK32-NEXT: ref.test (i32, i32) -> (i32) +; CHK64-NEXT: ref.test (i64, i64) -> (i64) +; CHECK-NEXT: call use +; CHECK-NEXT: # fallthrough-return +entry: + %res = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, ptr null, token poison, ptr null, ptr null) + tail call void @use(i32 noundef %res) #3 + ret void +} + + declare void @use(i32 noundef) local_unnamed_addr #1