diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 734c8dc0297..02278e9e422 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -311,6 +311,12 @@ public: unsigned CallingConv, bool isTailCall, SDOperand Callee, ArgListTy &Args, SelectionDAG &DAG) = 0; + /// LowerReturnTo - This hook lowers a return instruction into the appropriate + /// legal ISD::RET node for the target's current ABI. This method is optional + /// and is intended for targets that need non-standard behavior. + virtual SDOperand LowerReturnTo(SDOperand Chain, SDOperand Op, + SelectionDAG &DAG); + /// LowerVAStart - This lowers the llvm.va_start intrinsic. If not /// implemented, this method prints a message and aborts. This method should /// return the modified chain value. Note that VAListPtr* correspond to the diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 72ee7501082..4a89578eaa0 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -450,8 +450,8 @@ void SelectionDAGLowering::visitRet(ReturnInst &I) { case MVT::f64: break; // No extension needed! } - - DAG.setRoot(DAG.getNode(ISD::RET, MVT::Other, getRoot(), Op1)); + // Allow targets to lower this further to meet ABI requirements + DAG.setRoot(TLI.LowerReturnTo(getRoot(), Op1, DAG)); } void SelectionDAGLowering::visitBr(BranchInst &I) { @@ -898,6 +898,11 @@ MachineBasicBlock *TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI, return 0; } +SDOperand TargetLowering::LowerReturnTo(SDOperand Chain, SDOperand Op, + SelectionDAG &DAG) { + return DAG.getNode(ISD::RET, MVT::Other, Chain, Op); +} + SDOperand TargetLowering::LowerVAStart(SDOperand Chain, SDOperand VAListP, Value *VAListV, SelectionDAG &DAG) { diff --git a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index c55bd30a2dd..75480930311 100644 --- a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -1206,6 +1206,22 @@ SDOperand PPCDAGToDAGISel::Select(SDOperand Op) { // Other cases are autogenerated. break; + case ISD::ANY_EXTEND: + switch(N->getValueType(0)) { + default: assert(0 && "Unhandled type in ANY_EXTEND"); + case MVT::i64: + CurDAG->SelectNodeTo(N, PPC::OR8, MVT::i64, Select(N->getOperand(0)), + Select(N->getOperand(0))); + break; + } + return SDOperand(N, 0); + case ISD::ZERO_EXTEND: + assert(N->getValueType(0) == MVT::i64 && + N->getOperand(0).getValueType() == MVT::i32 && + "ZERO_EXTEND only supported for i32 -> i64"); + CurDAG->SelectNodeTo(N, PPC::RLDICL, MVT::i64, Select(N->getOperand(0)), + getI32Imm(32)); + return SDOperand(N, 0); case ISD::SHL: { unsigned Imm, SH, MB, ME; if (isOpcWithIntImmediate(N->getOperand(0).Val, ISD::AND, Imm) && @@ -1393,11 +1409,6 @@ SDOperand PPCDAGToDAGISel::Select(SDOperand Op) { SDOperand Val = Select(N->getOperand(1)); if (N->getOperand(1).getValueType() == MVT::i32) { Chain = CurDAG->getCopyToReg(Chain, PPC::R3, Val); - } else if (N->getOperand(1).getValueType() == MVT::i64) { - SDOperand Srl = CurDAG->getTargetNode(PPC::RLDICL, MVT::i64, Val, - getI32Imm(32), getI32Imm(32)); - Chain = CurDAG->getCopyToReg(Chain, PPC::R4, Val); - Chain = CurDAG->getCopyToReg(Chain, PPC::R3, Srl); } else { assert(MVT::isFloatingPoint(N->getOperand(1).getValueType())); Chain = CurDAG->getCopyToReg(Chain, PPC::F1, Val); diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index 8cc538df83a..5256e4839d1 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -693,6 +693,19 @@ PPCTargetLowering::LowerCallTo(SDOperand Chain, return std::make_pair(RetVal, Chain); } +SDOperand PPCTargetLowering::LowerReturnTo(SDOperand Chain, SDOperand Op, + SelectionDAG &DAG) { + if (Op.getValueType() == MVT::i64) { + SDOperand Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Op, + DAG.getConstant(1, MVT::i32)); + SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Op, + DAG.getConstant(0, MVT::i32)); + return DAG.getNode(ISD::RET, MVT::Other, Chain, Lo, Hi); + } else { + return DAG.getNode(ISD::RET, MVT::Other, Chain, Op); + } +} + SDOperand PPCTargetLowering::LowerVAStart(SDOperand Chain, SDOperand VAListP, Value *VAListV, SelectionDAG &DAG) { // vastart just stores the address of the VarArgsFrameIndex slot into the diff --git a/lib/Target/PowerPC/PPCISelLowering.h b/lib/Target/PowerPC/PPCISelLowering.h index 0b3690ddf69..f44f192e693 100644 --- a/lib/Target/PowerPC/PPCISelLowering.h +++ b/lib/Target/PowerPC/PPCISelLowering.h @@ -63,6 +63,9 @@ namespace llvm { unsigned CC, bool isTailCall, SDOperand Callee, ArgListTy &Args, SelectionDAG &DAG); + + virtual SDOperand LowerReturnTo(SDOperand Chain, SDOperand Op, + SelectionDAG &DAG); virtual SDOperand LowerVAStart(SDOperand Chain, SDOperand VAListP, Value *VAListV, SelectionDAG &DAG);