Index: llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -889,6 +889,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) Index: llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -454,6 +454,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); Index: llvm/test/CodeGen/WebAssembly/fast-isel-call-indirect64.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/WebAssembly/fast-isel-call-indirect64.ll @@ -0,0 +1,21 @@ +; 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: i64.load $push[[L0:[0-9]+]]=, 8($pop{{[0-9]+}}) +; CHECK-NEXT: i32.wrap_i64 $push[[L1:[0-9]+]]=, $pop[[L0]] +; CHECK-NEXT: call_indirect $push[[L2:[0-9]+]]=, $pop[[L1]] +; CHECK-NEXT: local.set {{[0-9]+}}, $pop[[L2]] + +define hidden i32 @b(i32 (...)* %f) { +entry: + %f.addr = alloca i32 (...)*, align 8 + store i32 (...)* %f, i32 (...)** %f.addr, align 8 + %0 = load i32 (...)*, i32 (...)** %f.addr, align 8 + %callee.knr.cast = bitcast i32 (...)* %0 to i32 ()* + %call = call i32 %callee.knr.cast() + ret i32 %call +}