// 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);
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;
}
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();
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);
}
}
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.">;