diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -881,6 +881,19 @@ // it as NO_STRIP so as to ensure that the indirect function table makes it // to linked output. Sym->setNoStrip(); + + // See if we must truncate the function pointer. + // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers + // as 64-bit for uniformity with other pointer types. + // See also: WebAssemblyISelLowering.cpp: LowerCallResults + if (Subtarget->hasAddr64()) { + auto Wrap = BuildMI(*FuncInfo.MBB, std::prev(FuncInfo.InsertPt), DbgLoc, + TII.get(WebAssembly::I32_WRAP_I64)); + unsigned Reg32 = createResultReg(&WebAssembly::I32RegClass); + Wrap.addReg(Reg32, RegState::Define); + Wrap.addReg(CalleeReg); + CalleeReg = Reg32; + } } for (unsigned ArgReg : Args) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -455,6 +455,7 @@ // See if we must truncate the function pointer. // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers // as 64-bit for uniformity with other pointer types. + // See also: WebAssemblyFastISel::selectCall if (IsIndirect && MF.getSubtarget().hasAddr64()) { Register Reg32 = MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass); diff --git a/llvm/test/CodeGen/WebAssembly/fast-isel-call-indirect64.ll b/llvm/test/CodeGen/WebAssembly/fast-isel-call-indirect64.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/fast-isel-call-indirect64.ll @@ -0,0 +1,15 @@ +; RUN: llc < %s -fast-isel --mtriple=wasm64 -asm-verbose=false -wasm-keep-registers | FileCheck %s + +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "wasm64" + +; Ensure fast isel also lowers function pointers to 32-bit. + +; CHECK: local.get $push[[L0:[0-9]+]]=, 0 +; CHECK-NEXT: i32.wrap_i64 $push[[L1:[0-9]+]]=, $pop[[L0]] +; CHECK-NEXT: call_indirect $pop[[L1]] + +define hidden void @f(void ()* %g) { + call void %g() + ret void +}