diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp index a45104022d6062..e99feaaaff7b25 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 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 7e3e09d90030be..e91a9ea0376750 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 98a4f43a0748f3..d3e7493fafa1aa 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -54,15 +54,30 @@ multiclass CALL; } +// 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; defm "" : CALL;