diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index f63a09248b8..9f8b999b56b 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -818,11 +818,12 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) { break; case ISD::FORMAL_ARGUMENTS: + case ISD::CALL: // The only option for this is to custom lower it. Result = TLI.LowerOperation(Result.getValue(0), DAG); - assert(Result.Val && "Target didn't custom lower ISD::FORMAL_ARGUMENTS!"); + assert(Result.Val && "Target didn't custom lower this node!"); - // Since FORMAL_ARGUMENTS nodes produce multiple values, make sure to + // Since CALL/FORMAL_ARGUMENTS nodes produce multiple values, make sure to // remember that we legalized all of them, so it doesn't get relegalized. for (unsigned i = 0, e = Result.Val->getNumValues(); i != e; ++i) { Tmp1 = LegalizeOp(Result.getValue(i)); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index cf1d41f705f..41c1193b027 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2841,6 +2841,7 @@ const char *SDNode::getOperationName(const SelectionDAG *G) const { case ISD::INLINEASM: return "inlineasm"; case ISD::HANDLENODE: return "handlenode"; case ISD::FORMAL_ARGUMENTS: return "formal_arguments"; + case ISD::CALL: return "call"; // Unary operators case ISD::FABS: return "fabs"; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index b6472323708..105eb9ba126 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -2344,7 +2344,8 @@ void SelectionDAGLowering::visitVACopy(CallInst &I) { /// TargetLowering::LowerArguments - This is the default LowerArguments /// implementation, which just inserts a FORMAL_ARGUMENTS node. FIXME: When all -/// targets are migrated to using FORMAL_ARGUMENTS, this hook should be removed. +/// targets are migrated to using FORMAL_ARGUMENTS, this hook should be +/// integrated into SDISel. std::vector TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { // Add CC# and isVararg as operands to the FORMAL_ARGUMENTS node. @@ -2477,8 +2478,145 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { return Ops; } + +/// TargetLowering::LowerCallTo - This is the default LowerCallTo +/// implementation, which just inserts an ISD::CALL node, which is later custom +/// lowered by the target to something concrete. FIXME: When all targets are +/// migrated to using ISD::CALL, this hook should be integrated into SDISel. +std::pair +TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy, bool isVarArg, + unsigned CallingConv, bool isTailCall, + SDOperand Callee, + ArgListTy &Args, SelectionDAG &DAG) { + std::vector Ops; + Ops.push_back(Chain); // Op#0 - Chain + Ops.push_back(DAG.getConstant(CallingConv, getPointerTy())); // Op#1 - CC + Ops.push_back(DAG.getConstant(isVarArg, getPointerTy())); // Op#2 - VarArg + Ops.push_back(DAG.getConstant(isTailCall, getPointerTy())); // Op#3 - Tail + Ops.push_back(Callee); + + // Handle all of the outgoing arguments. + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + MVT::ValueType VT = getValueType(Args[i].second); + SDOperand Op = Args[i].first; + switch (getTypeAction(VT)) { + default: assert(0 && "Unknown type action!"); + case Legal: + Ops.push_back(Op); + break; + case Promote: + if (MVT::isInteger(VT)) { + unsigned ExtOp = Args[i].second->isSigned() ? + ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; + Op = DAG.getNode(ExtOp, getTypeToTransformTo(VT), Op); + } else { + assert(MVT::isFloatingPoint(VT) && "Not int or FP?"); + Op = DAG.getNode(ISD::FP_EXTEND, getTypeToTransformTo(VT), Op); + } + Ops.push_back(Op); + break; + case Expand: + if (VT != MVT::Vector) { + // If this is a large integer, it needs to be broken down into small + // integers. Figure out what the source elt type is and how many small + // integers it is. + MVT::ValueType NVT = getTypeToTransformTo(VT); + unsigned NumVals = MVT::getSizeInBits(VT)/MVT::getSizeInBits(NVT); + if (NumVals == 2) { + SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, NVT, Op, + DAG.getConstant(0, getPointerTy())); + SDOperand Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, NVT, Op, + DAG.getConstant(1, getPointerTy())); + if (!isLittleEndian()) + std::swap(Lo, Hi); + + Ops.push_back(Lo); + Ops.push_back(Hi); + } else { + // Value scalarized into many values. Unimp for now. + assert(0 && "Cannot expand i64 -> i16 yet!"); + } + } else { + assert(0 && "Doesn't handle vectors yet!"); + } + break; + } + } + + // Figure out the result value types. + std::vector RetTys; + + if (RetTy != Type::VoidTy) { + MVT::ValueType VT = getValueType(RetTy); + switch (getTypeAction(VT)) { + default: assert(0 && "Unknown type action!"); + case Legal: + RetTys.push_back(VT); + break; + case Promote: + RetTys.push_back(getTypeToTransformTo(VT)); + break; + case Expand: + if (VT != MVT::Vector) { + // If this is a large integer, it needs to be reassembled from small + // integers. Figure out what the source elt type is and how many small + // integers it is. + MVT::ValueType NVT = getTypeToTransformTo(VT); + unsigned NumVals = MVT::getSizeInBits(VT)/MVT::getSizeInBits(NVT); + for (unsigned i = 0; i != NumVals; ++i) + RetTys.push_back(NVT); + } else { + assert(0 && "Doesn't handle vectors yet!"); + } + } + } + + RetTys.push_back(MVT::Other); // Always has a chain. + + // Finally, create the CALL node. + SDOperand Res = DAG.getNode(ISD::CALL, RetTys, Ops); + + // This returns a pair of operands. The first element is the + // return value for the function (if RetTy is not VoidTy). The second + // element is the outgoing token chain. + SDOperand ResVal; + if (RetTys.size() != 1) { + MVT::ValueType VT = getValueType(RetTy); + if (RetTys.size() == 2) { + ResVal = Res; + + // If this value was promoted, truncate it down. + if (ResVal.getValueType() != VT) { + if (MVT::isInteger(VT)) { + unsigned AssertOp = RetTy->isSigned() ? + ISD::AssertSext : ISD::AssertZext; + ResVal = DAG.getNode(AssertOp, ResVal.getValueType(), ResVal, + DAG.getValueType(VT)); + ResVal = DAG.getNode(ISD::TRUNCATE, VT, ResVal); + } else { + assert(MVT::isFloatingPoint(VT)); + ResVal = DAG.getNode(ISD::FP_ROUND, VT, ResVal); + } + } + } else if (RetTys.size() == 3) { + ResVal = DAG.getNode(ISD::BUILD_PAIR, VT, + Res.getValue(0), Res.getValue(1)); + + } else { + assert(0 && "Case not handled yet!"); + } + } + + return std::make_pair(ResVal, Res.getValue(Res.Val->getNumValues()-1)); +} + + + // It is always conservatively correct for llvm.returnaddress and // llvm.frameaddress to return 0. +// +// FIXME: Change this to insert a FRAMEADDR/RETURNADDR node, and have that be +// expanded to 0 if the target wants. std::pair TargetLowering::LowerFrameReturnAddress(bool isFrameAddr, SDOperand Chain, unsigned Depth, SelectionDAG &DAG) {