[llvm] 28857d1 - [WebAssembly] Split and recombine multivalue calls for ISel

Thomas Lively via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 21 11:31:39 PST 2020


Author: Thomas Lively
Date: 2020-01-21T11:31:33-08:00
New Revision: 28857d14a86b1e99a9d2795636a5faf17674f5a2

URL: https://github.com/llvm/llvm-project/commit/28857d14a86b1e99a9d2795636a5faf17674f5a2
DIFF: https://github.com/llvm/llvm-project/commit/28857d14a86b1e99a9d2795636a5faf17674f5a2.diff

LOG: [WebAssembly] Split and recombine multivalue calls for ISel

Summary:
Multivalue calls both take and return an arbitrary number of
arguments, but ISel only supports one or the other in a single
instruction. To get around this, calls are modeled as two pseudo
instructions during ISel. These pseudo instructions, CALL_PARAMS and
CALL_RESULTS, are recombined into a single CALL MachineInstr in a
custom emit hook.

RegStackification and the MC layer will additionally need to be made
aware of multivalue calls before the tests will produce correct
output.

Reviewers: aheejin, dschuff

Subscribers: sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits

Tags: #llvm

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

Added: 
    

Modified: 
    llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index a45104022d60..e99feaaaff7b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -210,8 +210,7 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
     // CALL has both variable operands and variable results, but ISel only
     // supports one or the other. Split calls into two nodes glued together, one
     // for the operands and one for the results. These two nodes will be
-    // recombined in a custom inserter hook.
-    // TODO: Split CALL
+    // recombined in a custom inserter hook into a single MachineInstr.
     SmallVector<SDValue, 16> Ops;
     for (size_t i = 1; i < Node->getNumOperands(); ++i) {
       SDValue Op = Node->getOperand(i);
@@ -220,9 +219,12 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
       Ops.push_back(Op);
     }
     Ops.push_back(Node->getOperand(0));
-    MachineSDNode *Call =
-        CurDAG->getMachineNode(WebAssembly::CALL, DL, Node->getVTList(), Ops);
-    ReplaceNode(Node, Call);
+    MachineSDNode *CallParams =
+        CurDAG->getMachineNode(WebAssembly::CALL_PARAMS, DL, MVT::Glue, Ops);
+    SDValue Link(CallParams, 0);
+    MachineSDNode *CallResults = CurDAG->getMachineNode(
+        WebAssembly::CALL_RESULTS, DL, Node->getVTList(), Link);
+    ReplaceNode(Node, CallResults);
     return;
   }
 

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 7e3e09d90030..e91a9ea03767 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -434,6 +434,29 @@ static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
   return DoneMBB;
 }
 
+static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults,
+                                           DebugLoc DL, MachineBasicBlock *BB,
+                                           const TargetInstrInfo &TII) {
+  MachineInstr &CallParams = *CallResults.getPrevNode();
+  assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS);
+  assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS);
+
+  MachineFunction &MF = *BB->getParent();
+  const MCInstrDesc &MCID = TII.get(WebAssembly::CALL);
+  MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
+
+  for (auto Def : CallResults.defs())
+    MIB.add(Def);
+  for (auto Use : CallParams.uses())
+    MIB.add(Use);
+
+  BB->insert(CallResults.getIterator(), MIB);
+  CallParams.eraseFromParent();
+  CallResults.eraseFromParent();
+
+  return BB;
+}
+
 MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
     MachineInstr &MI, MachineBasicBlock *BB) const {
   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
@@ -466,7 +489,8 @@ MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
   case WebAssembly::FP_TO_UINT_I64_F64:
     return LowerFPToInt(MI, DL, BB, TII, true, true, true,
                         WebAssembly::I64_TRUNC_U_F64);
-    llvm_unreachable("Unexpected instruction to emit with custom inserter");
+  case WebAssembly::CALL_RESULTS:
+    return LowerCallResults(MI, DL, BB, TII);
   }
 }
 

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
index 98a4f43a0748..d3e7493fafa1 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
@@ -54,15 +54,30 @@ multiclass CALL<ValueType vt, WebAssemblyRegClass rt, string prefix,
     Requires<preds>;
 }
 
+// CALL should take both variadic arguments and produce variadic results, but
+// this is not possible to model directly. Instead, we select calls to a
+// CALL_PARAMS taking variadic aguments linked with a CALL_RESULTS that handles
+// producing the call's variadic results. We recombine the two in a custom
+// inserter hook after DAG ISel, so passes over MachineInstrs will only ever
+// observe CALL nodes with all of the expected variadic uses and defs.
+let isPseudo = 1 in
+defm CALL_PARAMS :
+  I<(outs), (ins function32_op:$callee, variable_ops),
+    (outs), (ins function32_op:$callee), [],
+    "call_params\t$callee", "call_params\t$callee", -1>;
+
+let variadicOpsAreDefs = 1, usesCustomInserter = 1, isPseudo = 1 in
+defm CALL_RESULTS :
+  I<(outs), (ins variable_ops), (outs), (ins), [],
+     "call_results", "call_results", -1>;
+
 let Uses = [SP32, SP64], isCall = 1 in {
 
-// TODO: Split CALL into separate nodes for operands and results.
 // TODO: Add an indirect version of the variadic call, delete CALL_*
-let variadicOpsAreDefs = 1 in
 defm CALL :
   I<(outs), (ins function32_op:$callee, variable_ops),
     (outs), (ins function32_op:$callee), [],
-    "call    \t$callee", "call\t$callee", 0x10>;
+    "call\t$callee", "call\t$callee", 0x10>;
 
 defm "" : CALL<i32, I32, "i32.">;
 defm "" : CALL<i64, I64, "i64.">;


        


More information about the llvm-commits mailing list