diff --git a/include/llvm/CodeGen/RuntimeLibcalls.h b/include/llvm/CodeGen/RuntimeLibcalls.h index 92a0b788866..0138b0c4842 100644 --- a/include/llvm/CodeGen/RuntimeLibcalls.h +++ b/include/llvm/CodeGen/RuntimeLibcalls.h @@ -99,6 +99,7 @@ namespace RTLIB { FPTOSINT_F64_I128, FPTOSINT_F80_I64, FPTOSINT_F80_I128, + FPTOSINT_PPCF128_I32, FPTOSINT_PPCF128_I64, FPTOSINT_PPCF128_I128, FPTOUINT_F32_I32, @@ -110,6 +111,7 @@ namespace RTLIB { FPTOUINT_F80_I32, FPTOUINT_F80_I64, FPTOUINT_F80_I128, + FPTOUINT_PPCF128_I32, FPTOUINT_PPCF128_I64, FPTOUINT_PPCF128_I128, SINTTOFP_I32_F32, diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index 2e274558138..f56863cd6ee 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -193,16 +193,16 @@ namespace ISD { CALL, // EXTRACT_ELEMENT - This is used to get the lower or upper (determined by - // a Constant, which is required to be operand #1) half of the integer value - // specified as operand #0. This is only for use before legalization, for - // values that will be broken into multiple registers. + // a Constant, which is required to be operand #1) half of the integer or + // float value specified as operand #0. This is only for use before + // legalization, for values that will be broken into multiple registers. EXTRACT_ELEMENT, // BUILD_PAIR - This is the opposite of EXTRACT_ELEMENT in some ways. Given // two values of the same integer value type, this produces a value twice as // big. Like EXTRACT_ELEMENT, this can only be used before legalization. BUILD_PAIR, - + // MERGE_VALUES - This node takes multiple discrete operands and returns // them all as its individual results. This nodes has exactly the same // number of inputs and outputs, and is only valid before legalization. diff --git a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp index d99a9bd6dfd..be1d45502da 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -118,7 +118,7 @@ SDOperand DAGTypeLegalizer::SoftenFloatRes_FADD(SDNode *N) { RTLIB::ADD_F64, RTLIB::ADD_F80, RTLIB::ADD_PPCF128), - NVT, Ops, 2, false/*sign irrelevant*/); + NVT, Ops, 2, false); } SDOperand DAGTypeLegalizer::SoftenFloatRes_FCOPYSIGN(SDNode *N) { @@ -169,7 +169,7 @@ SDOperand DAGTypeLegalizer::SoftenFloatRes_FMUL(SDNode *N) { RTLIB::MUL_F64, RTLIB::MUL_F80, RTLIB::MUL_PPCF128), - NVT, Ops, 2, false/*sign irrelevant*/); + NVT, Ops, 2, false); } SDOperand DAGTypeLegalizer::SoftenFloatRes_FSUB(SDNode *N) { @@ -181,7 +181,7 @@ SDOperand DAGTypeLegalizer::SoftenFloatRes_FSUB(SDNode *N) { RTLIB::SUB_F64, RTLIB::SUB_F80, RTLIB::SUB_PPCF128), - NVT, Ops, 2, false/*sign irrelevant*/); + NVT, Ops, 2, false); } SDOperand DAGTypeLegalizer::SoftenFloatRes_LOAD(SDNode *N) { @@ -547,7 +547,14 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) { case ISD::EXTRACT_ELEMENT: ExpandRes_EXTRACT_ELEMENT(N, Lo, Hi); break; case ISD::EXTRACT_VECTOR_ELT: ExpandRes_EXTRACT_VECTOR_ELT(N, Lo, Hi); break; - case ISD::LOAD: ExpandFloatRes_LOAD(N, Lo, Hi); break; + case ISD::ConstantFP: ExpandFloatRes_ConstantFP(N, Lo, Hi); break; + case ISD::FADD: ExpandFloatRes_FADD(N, Lo, Hi); break; + case ISD::FDIV: ExpandFloatRes_FDIV(N, Lo, Hi); break; + case ISD::FMUL: ExpandFloatRes_FMUL(N, Lo, Hi); break; + case ISD::FSUB: ExpandFloatRes_FSUB(N, Lo, Hi); break; + case ISD::LOAD: ExpandFloatRes_LOAD(N, Lo, Hi); break; + case ISD::SINT_TO_FP: + case ISD::UINT_TO_FP: ExpandFloatRes_XINT_TO_FP(N, Lo, Hi); break; } // If Lo/Hi is null, the sub-method took care of registering results etc. @@ -555,6 +562,74 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) { SetExpandedFloat(SDOperand(N, ResNo), Lo, Hi); } +void DAGTypeLegalizer::ExpandFloatRes_ConstantFP(SDNode *N, SDOperand &Lo, + SDOperand &Hi) { + MVT NVT = TLI.getTypeToTransformTo(N->getValueType(0)); + assert(NVT.getSizeInBits() == integerPartWidth && + "Do not know how to expand this float constant!"); + APInt C = cast(N)->getValueAPF().convertToAPInt(); + Lo = DAG.getConstantFP(APFloat(APInt(integerPartWidth, 1, + &C.getRawData()[1])), NVT); + Hi = DAG.getConstantFP(APFloat(APInt(integerPartWidth, 1, + &C.getRawData()[0])), NVT); +} + +void DAGTypeLegalizer::ExpandFloatRes_FADD(SDNode *N, SDOperand &Lo, + SDOperand &Hi) { + SDOperand Ops[2] = { N->getOperand(0), N->getOperand(1) }; + SDOperand Call = MakeLibCall(GetFPLibCall(N->getValueType(0), + RTLIB::ADD_F32, + RTLIB::ADD_F64, + RTLIB::ADD_F80, + RTLIB::ADD_PPCF128), + N->getValueType(0), Ops, 2, + false); + assert(Call.Val->getOpcode() == ISD::BUILD_PAIR && "Call lowered wrongly!"); + Lo = Call.getOperand(0); Hi = Call.getOperand(1); +} + +void DAGTypeLegalizer::ExpandFloatRes_FDIV(SDNode *N, SDOperand &Lo, + SDOperand &Hi) { + SDOperand Ops[2] = { N->getOperand(0), N->getOperand(1) }; + SDOperand Call = MakeLibCall(GetFPLibCall(N->getValueType(0), + RTLIB::DIV_F32, + RTLIB::DIV_F64, + RTLIB::DIV_F80, + RTLIB::DIV_PPCF128), + N->getValueType(0), Ops, 2, + false); + assert(Call.Val->getOpcode() == ISD::BUILD_PAIR && "Call lowered wrongly!"); + Lo = Call.getOperand(0); Hi = Call.getOperand(1); +} + +void DAGTypeLegalizer::ExpandFloatRes_FMUL(SDNode *N, SDOperand &Lo, + SDOperand &Hi) { + SDOperand Ops[2] = { N->getOperand(0), N->getOperand(1) }; + SDOperand Call = MakeLibCall(GetFPLibCall(N->getValueType(0), + RTLIB::MUL_F32, + RTLIB::MUL_F64, + RTLIB::MUL_F80, + RTLIB::MUL_PPCF128), + N->getValueType(0), Ops, 2, + false); + assert(Call.Val->getOpcode() == ISD::BUILD_PAIR && "Call lowered wrongly!"); + Lo = Call.getOperand(0); Hi = Call.getOperand(1); +} + +void DAGTypeLegalizer::ExpandFloatRes_FSUB(SDNode *N, SDOperand &Lo, + SDOperand &Hi) { + SDOperand Ops[2] = { N->getOperand(0), N->getOperand(1) }; + SDOperand Call = MakeLibCall(GetFPLibCall(N->getValueType(0), + RTLIB::SUB_F32, + RTLIB::SUB_F64, + RTLIB::SUB_F80, + RTLIB::SUB_PPCF128), + N->getValueType(0), Ops, 2, + false); + assert(Call.Val->getOpcode() == ISD::BUILD_PAIR && "Call lowered wrongly!"); + Lo = Call.getOperand(0); Hi = Call.getOperand(1); +} + void DAGTypeLegalizer::ExpandFloatRes_LOAD(SDNode *N, SDOperand &Lo, SDOperand &Hi) { if (ISD::isNormalLoad(N)) { @@ -587,6 +662,71 @@ void DAGTypeLegalizer::ExpandFloatRes_LOAD(SDNode *N, SDOperand &Lo, ReplaceValueWith(SDOperand(LD, 1), Chain); } +void DAGTypeLegalizer::ExpandFloatRes_XINT_TO_FP(SDNode *N, SDOperand &Lo, + SDOperand &Hi) { + assert(N->getValueType(0) == MVT::ppcf128 && "Unsupported XINT_TO_FP!"); + MVT VT = N->getValueType(0); + MVT NVT = TLI.getTypeToTransformTo(VT); + SDOperand Src = N->getOperand(0); + MVT SrcVT = Src.getValueType(); + + // First do an SINT_TO_FP, whether the original was signed or unsigned. + if (SrcVT.bitsLE(MVT::i32)) { + // The integer can be represented exactly in an f64. + Src = DAG.getNode(ISD::SIGN_EXTEND, MVT::i32, Src); + Lo = DAG.getConstantFP(APFloat(APInt(NVT.getSizeInBits(), 0)), NVT); + Hi = DAG.getNode(ISD::SINT_TO_FP, NVT, Src); + } else { + RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; + if (SrcVT.bitsLE(MVT::i64)) { + Src = DAG.getNode(ISD::SIGN_EXTEND, MVT::i64, Src); + LC = RTLIB::SINTTOFP_I64_PPCF128; + } else if (SrcVT.bitsLE(MVT::i128)) { + Src = DAG.getNode(ISD::SIGN_EXTEND, MVT::i128, Src); + LC = RTLIB::SINTTOFP_I128_PPCF128; + } + assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported XINT_TO_FP!"); + + Hi = MakeLibCall(LC, VT, &Src, 1, true); + assert(Hi.Val->getOpcode() == ISD::BUILD_PAIR && "Call lowered wrongly!"); + Lo = Hi.getOperand(0); Hi = Hi.getOperand(1); + } + + if (N->getOpcode() == ISD::SINT_TO_FP) + return; + + // Unsigned - fix up the SINT_TO_FP value just calculated. + Hi = DAG.getNode(ISD::BUILD_PAIR, VT, Lo, Hi); + SrcVT = Src.getValueType(); + + // x>=0 ? (ppcf128)(iN)x : (ppcf128)(iN)x + 2^N; N=32,64,128. + static const uint64_t TwoE32[] = { 0x41f0000000000000LL, 0 }; + static const uint64_t TwoE64[] = { 0x43f0000000000000LL, 0 }; + static const uint64_t TwoE128[] = { 0x47f0000000000000LL, 0 }; + const uint64_t *Parts = 0; + + switch (SrcVT.getSimpleVT()) { + default: + assert(false && "Unsupported UINT_TO_FP!"); + case MVT::i32: + Parts = TwoE32; + case MVT::i64: + Parts = TwoE64; + case MVT::i128: + Parts = TwoE128; + } + + Lo = DAG.getNode(ISD::FADD, VT, Hi, + DAG.getConstantFP(APFloat(APInt(128, 2, Parts)), + MVT::ppcf128)); + Lo = DAG.getNode(ISD::SELECT_CC, VT, Src, DAG.getConstant(0, SrcVT), Lo, Hi, + DAG.getCondCode(ISD::SETLT)); + Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, NVT, Lo, + DAG.getConstant(1, TLI.getPointerTy())); + Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, NVT, Lo, + DAG.getConstant(0, TLI.getPointerTy())); +} + //===----------------------------------------------------------------------===// // Float Operand Expansion @@ -622,6 +762,10 @@ bool DAGTypeLegalizer::ExpandFloatOperand(SDNode *N, unsigned OpNo) { case ISD::SELECT_CC: Res = ExpandFloatOp_BR_CC(N); break; case ISD::SETCC: Res = ExpandFloatOp_BR_CC(N); break; + case ISD::FP_ROUND: Res = ExpandFloatOp_FP_ROUND(N); break; + case ISD::FP_TO_SINT: Res = ExpandFloatOp_FP_TO_SINT(N); break; + case ISD::FP_TO_UINT: Res = ExpandFloatOp_FP_TO_UINT(N); break; + case ISD::STORE: Res = ExpandFloatOp_STORE(cast(N), OpNo); break; @@ -728,6 +872,58 @@ SDOperand DAGTypeLegalizer::ExpandFloatOp_SETCC(SDNode *N) { DAG.getCondCode(CCCode)); } +SDOperand DAGTypeLegalizer::ExpandFloatOp_FP_TO_UINT(SDNode *N) { + assert(N->getOperand(0).getValueType() == MVT::ppcf128 && + "Unsupported FP_TO_UINT!"); + + RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; + switch (N->getValueType(0).getSimpleVT()) { + default: + assert(false && "Unsupported FP_TO_UINT!"); + case MVT::i32: + LC = RTLIB::FPTOUINT_PPCF128_I32; + break; + case MVT::i64: + LC = RTLIB::FPTOUINT_PPCF128_I64; + break; + case MVT::i128: + LC = RTLIB::FPTOUINT_PPCF128_I128; + break; + } + + return MakeLibCall(LC, N->getValueType(0), &N->getOperand(0), 1, false); +} + +SDOperand DAGTypeLegalizer::ExpandFloatOp_FP_TO_SINT(SDNode *N) { + assert(N->getOperand(0).getValueType() == MVT::ppcf128 && + "Unsupported FP_TO_SINT!"); + + RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; + switch (N->getValueType(0).getSimpleVT()) { + default: + assert(false && "Unsupported FP_TO_SINT!"); + case MVT::i32: + LC = RTLIB::FPTOSINT_PPCF128_I32; + case MVT::i64: + LC = RTLIB::FPTOSINT_PPCF128_I64; + break; + case MVT::i128: + LC = RTLIB::FPTOSINT_PPCF128_I64; + break; + } + + return MakeLibCall(LC, N->getValueType(0), &N->getOperand(0), 1, false); +} + +SDOperand DAGTypeLegalizer::ExpandFloatOp_FP_ROUND(SDNode *N) { + assert(N->getOperand(0).getValueType() == MVT::ppcf128 && + "Logic only correct for ppcf128!"); + SDOperand Lo, Hi; + GetExpandedFloat(N->getOperand(0), Lo, Hi); + // Round it the rest of the way (e.g. to f32) if needed. + return DAG.getNode(ISD::FP_ROUND, N->getValueType(0), Hi, N->getOperand(1)); +} + SDOperand DAGTypeLegalizer::ExpandFloatOp_STORE(SDNode *N, unsigned OpNo) { if (ISD::isNormalStore(N)) return ExpandOp_NormalStore(N, OpNo); diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index ea7ac8f26bd..add3dcdf1bc 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -354,11 +354,20 @@ private: // Float Result Expansion. void ExpandFloatResult(SDNode *N, unsigned ResNo); - void ExpandFloatRes_LOAD(SDNode *N, SDOperand &Lo, SDOperand &Hi); + void ExpandFloatRes_ConstantFP(SDNode *N, SDOperand &Lo, SDOperand &Hi); + void ExpandFloatRes_FADD (SDNode *N, SDOperand &Lo, SDOperand &Hi); + void ExpandFloatRes_FDIV (SDNode *N, SDOperand &Lo, SDOperand &Hi); + void ExpandFloatRes_FMUL (SDNode *N, SDOperand &Lo, SDOperand &Hi); + void ExpandFloatRes_FSUB (SDNode *N, SDOperand &Lo, SDOperand &Hi); + void ExpandFloatRes_LOAD (SDNode *N, SDOperand &Lo, SDOperand &Hi); + void ExpandFloatRes_XINT_TO_FP(SDNode *N, SDOperand &Lo, SDOperand &Hi); // Float Operand Expansion. bool ExpandFloatOperand(SDNode *N, unsigned OperandNo); SDOperand ExpandFloatOp_BR_CC(SDNode *N); + SDOperand ExpandFloatOp_FP_ROUND(SDNode *N); + SDOperand ExpandFloatOp_FP_TO_SINT(SDNode *N); + SDOperand ExpandFloatOp_FP_TO_UINT(SDNode *N); SDOperand ExpandFloatOp_SELECT_CC(SDNode *N); SDOperand ExpandFloatOp_SETCC(SDNode *N); SDOperand ExpandFloatOp_STORE(SDNode *N, unsigned OpNo); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 78281aa6326..fdff418a615 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2244,10 +2244,9 @@ SDOperand SelectionDAG::getNode(unsigned Opcode, MVT VT, break; case ISD::EXTRACT_ELEMENT: assert(N2C && (unsigned)N2C->getValue() < 2 && "Bad EXTRACT_ELEMENT!"); - assert(!N1.getValueType().isVector() && - N1.getValueType().isInteger() && - !VT.isVector() && VT.isInteger() && - "EXTRACT_ELEMENT only applies to integers!"); + assert(!N1.getValueType().isVector() && !VT.isVector() && + (N1.getValueType().isInteger() == VT.isInteger()) && + "Wrong types for EXTRACT_ELEMENT!"); // EXTRACT_ELEMENT of BUILD_PAIR is often formed while legalize is expanding // 64-bit integers into 32-bit parts. Instead of building the extract of diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index c99319338e3..ae9b917f1bd 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -97,6 +97,7 @@ static void InitLibcallNames(const char **Names) { Names[RTLIB::FPTOSINT_F64_I128] = "__fixdfti"; Names[RTLIB::FPTOSINT_F80_I64] = "__fixxfdi"; Names[RTLIB::FPTOSINT_F80_I128] = "__fixxfti"; + Names[RTLIB::FPTOSINT_PPCF128_I32] = "__fixtfsi"; Names[RTLIB::FPTOSINT_PPCF128_I64] = "__fixtfdi"; Names[RTLIB::FPTOSINT_PPCF128_I128] = "__fixtfti"; Names[RTLIB::FPTOUINT_F32_I32] = "__fixunssfsi"; @@ -108,6 +109,7 @@ static void InitLibcallNames(const char **Names) { Names[RTLIB::FPTOUINT_F80_I32] = "__fixunsxfsi"; Names[RTLIB::FPTOUINT_F80_I64] = "__fixunsxfdi"; Names[RTLIB::FPTOUINT_F80_I128] = "__fixunsxfti"; + Names[RTLIB::FPTOUINT_PPCF128_I32] = "__fixunstfsi"; Names[RTLIB::FPTOUINT_PPCF128_I64] = "__fixunstfdi"; Names[RTLIB::FPTOUINT_PPCF128_I128] = "__fixunstfti"; Names[RTLIB::SINTTOFP_I32_F32] = "__floatsisf";