[WebAssembly] Fix call_indirect on funcrefs
authorPaulo Matos <pmatos@igalia.com>
Wed, 6 Oct 2021 08:08:04 +0000 (10:08 +0200)
committerPaulo Matos <pmatos@igalia.com>
Wed, 6 Oct 2021 08:11:53 +0000 (10:11 +0200)
The currently implementation of funcrefs is broken since it is putting
the funcref itself on the stack before the call_indirect. Instead what
should be on the stack is the constant 0, which is the index at which
we store the funcref in __funcref_call_table.

Reviewed By: tlively

Differential Revision: https://reviews.llvm.org/D111152

llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
llvm/test/CodeGen/WebAssembly/funcref-call.ll

index 7dd1f48..6284a3c 100644 (file)
@@ -567,7 +567,21 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
   if (IsIndirect) {
     auto FnPtr = CallParams.getOperand(0);
     CallParams.RemoveOperand(0);
-    CallParams.addOperand(FnPtr);
+
+    // For funcrefs, call_indirect is done through __funcref_call_table and the
+    // funcref is always installed in slot 0 of the table, therefore instead of having
+    // the function pointer added at the end of the params list, a zero (the index in
+    // __funcref_call_table is added).
+    if (IsFuncrefCall) {
+      Register RegZero =
+          MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
+      MachineInstrBuilder MIBC0 =
+          BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
+
+      BB->insert(CallResults.getIterator(), MIBC0);
+      MachineInstrBuilder(MF, CallParams).addReg(RegZero);
+    } else
+      CallParams.addOperand(FnPtr);
   }
 
   for (auto Def : CallResults.defs())
index bd8d6c3..abe6b7b 100644 (file)
@@ -15,7 +15,7 @@ define void @call_funcref(%funcref %ref) {
 ; CHECK-NEXT: i32.const 0
 ; CHECK-NEXT: local.get 0
 ; CHECK-NEXT: table.set __funcref_call_table
-; CHECK-NEXT: local.get 0
+; CHECK-NEXT: i32.const 0
 ; CHECK-NEXT: call_indirect __funcref_call_table, () -> ()
 ; CHECK-NEXT: i32.const 0
 ; CHECK-NEXT: ref.null func