+SDOperand PPC32DAGToDAGISel::SelectCALL(SDOperand Op) {
+ SDNode *N = Op.Val;
+ SDOperand Chain = Select(N->getOperand(0));
+
+ unsigned CallOpcode;
+ std::vector<SDOperand> CallOperands;
+
+ if (GlobalAddressSDNode *GASD =
+ dyn_cast<GlobalAddressSDNode>(N->getOperand(1))) {
+ CallOpcode = PPC::CALLpcrel;
+ CallOperands.push_back(CurDAG->getTargetGlobalAddress(GASD->getGlobal(),
+ MVT::i32));
+ } else if (ExternalSymbolSDNode *ESSDN =
+ dyn_cast<ExternalSymbolSDNode>(N->getOperand(1))) {
+ CallOpcode = PPC::CALLpcrel;
+ CallOperands.push_back(N->getOperand(1));
+ } else {
+ // Copy the callee address into the CTR register.
+ SDOperand Callee = Select(N->getOperand(1));
+ Chain = CurDAG->getTargetNode(PPC::MTCTR, MVT::Other, Callee, Chain);
+
+ // Copy the callee address into R12 on darwin.
+ SDOperand R12 = CurDAG->getRegister(PPC::R12, MVT::i32);
+ Chain = CurDAG->getNode(ISD::CopyToReg, MVT::Other, Chain, R12, Callee);
+
+ CallOperands.push_back(getI32Imm(20)); // Information to encode indcall
+ CallOperands.push_back(getI32Imm(0)); // Information to encode indcall
+ CallOperands.push_back(R12);
+ CallOpcode = PPC::CALLindirect;
+ }
+
+ unsigned GPR_idx = 0, FPR_idx = 0;
+ static const unsigned GPR[] = {
+ PPC::R3, PPC::R4, PPC::R5, PPC::R6,
+ PPC::R7, PPC::R8, PPC::R9, PPC::R10,
+ };
+ static const unsigned FPR[] = {
+ PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7,
+ PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13
+ };
+
+ SDOperand InFlag; // Null incoming flag value.
+
+ for (unsigned i = 2, e = N->getNumOperands(); i != e; ++i) {
+ unsigned DestReg = 0;
+ MVT::ValueType RegTy = N->getOperand(i).getValueType();
+ if (RegTy == MVT::i32) {
+ assert(GPR_idx < 8 && "Too many int args");
+ DestReg = GPR[GPR_idx++];
+ } else {
+ assert(MVT::isFloatingPoint(N->getOperand(i).getValueType()) &&
+ "Unpromoted integer arg?");
+ assert(FPR_idx < 13 && "Too many fp args");
+ DestReg = FPR[FPR_idx++];
+ }
+
+ if (N->getOperand(i).getOpcode() != ISD::UNDEF) {
+ SDOperand Val = Select(N->getOperand(i));
+ Chain = CurDAG->getCopyToReg(Chain, DestReg, Val, InFlag);
+ InFlag = Chain.getValue(1);
+ CallOperands.push_back(CurDAG->getRegister(DestReg, RegTy));
+ }
+ }
+
+ // Finally, once everything is in registers to pass to the call, emit the
+ // call itself.
+ if (InFlag.Val)
+ CallOperands.push_back(InFlag); // Strong dep on register copies.
+ else
+ CallOperands.push_back(Chain); // Weak dep on whatever occurs before
+ Chain = CurDAG->getTargetNode(CallOpcode, MVT::Other, MVT::Flag,
+ CallOperands);
+
+ std::vector<SDOperand> CallResults;
+
+ // If the call has results, copy the values out of the ret val registers.
+ switch (N->getValueType(0)) {
+ default: assert(0 && "Unexpected ret value!");
+ case MVT::Other: break;
+ case MVT::i32:
+ if (N->getValueType(1) == MVT::i32) {
+ Chain = CurDAG->getCopyFromReg(Chain, PPC::R4, MVT::i32,
+ Chain.getValue(1)).getValue(1);
+ CallResults.push_back(Chain.getValue(0));
+ Chain = CurDAG->getCopyFromReg(Chain, PPC::R3, MVT::i32,
+ Chain.getValue(2)).getValue(1);
+ CallResults.push_back(Chain.getValue(0));
+ } else {
+ Chain = CurDAG->getCopyFromReg(Chain, PPC::R3, MVT::i32,
+ Chain.getValue(1)).getValue(1);
+ CallResults.push_back(Chain.getValue(0));
+ }
+ break;
+ case MVT::f32:
+ case MVT::f64:
+ Chain = CurDAG->getCopyFromReg(Chain, PPC::F1, N->getValueType(0),
+ Chain.getValue(1)).getValue(1);
+ CallResults.push_back(Chain.getValue(0));
+ break;
+ }
+
+ CallResults.push_back(Chain);
+ for (unsigned i = 0, e = CallResults.size(); i != e; ++i)
+ CodeGenMap[Op.getValue(i)] = CallResults[i];
+ return CallResults[Op.ResNo];
+}
+