From 37bcda3de96a9c41dc1aa05615ca3df869119026 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Fri, 18 Apr 2008 20:56:03 +0000 Subject: [PATCH] Implement a bit more softfloat support in LegalizeTypes. Correct the load logic so that it actually works, and also teach it to handle floating point extending loads. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@49923 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/SelectionDAG/LegalizeTypes.h | 5 + .../SelectionDAG/LegalizeTypesFloatToInt.cpp | 189 +++++++++++++++++- 2 files changed, 188 insertions(+), 6 deletions(-) diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index 6ddbdb0ade5..a983c95cb68 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -316,8 +316,13 @@ private: void FloatToIntResult(SDNode *N, unsigned OpNo); SDOperand FloatToIntRes_BIT_CONVERT(SDNode *N); SDOperand FloatToIntRes_BUILD_PAIR(SDNode *N); + SDOperand FloatToIntRes_ConstantFP(ConstantFPSDNode *N); + SDOperand FloatToIntRes_FADD(SDNode *N); SDOperand FloatToIntRes_FCOPYSIGN(SDNode *N); + SDOperand FloatToIntRes_FMUL(SDNode *N); + SDOperand FloatToIntRes_FSUB(SDNode *N); SDOperand FloatToIntRes_LOAD(SDNode *N); + SDOperand FloatToIntRes_XINT_TO_FP(SDNode *N); // Operand Float to Integer Conversion. bool FloatToIntOperand(SDNode *N, unsigned OpNo); diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypesFloatToInt.cpp b/lib/CodeGen/SelectionDAG/LegalizeTypesFloatToInt.cpp index 50410ef734a..f23b63eb1d5 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypesFloatToInt.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeTypesFloatToInt.cpp @@ -11,12 +11,29 @@ // is the act of turning a computation in an invalid floating point type into // a computation in an integer type of the same size. For example, turning // f32 arithmetic into operations using i32. Also known as "soft float". +// The result is equivalent to bitcasting the float value to the integer type. // //===----------------------------------------------------------------------===// +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/DerivedTypes.h" #include "LegalizeTypes.h" using namespace llvm; +/// GetFPLibCall - Return the right libcall for the given floating point type. +static RTLIB::Libcall GetFPLibCall(MVT::ValueType VT, + RTLIB::Libcall Call_F32, + RTLIB::Libcall Call_F64, + RTLIB::Libcall Call_F80, + RTLIB::Libcall Call_PPCF128) { + return + VT == MVT::f32 ? Call_F32 : + VT == MVT::f64 ? Call_F64 : + VT == MVT::f80 ? Call_F80 : + VT == MVT::ppcf128 ? Call_PPCF128 : + RTLIB::UNKNOWN_LIBCALL; +} + //===----------------------------------------------------------------------===// // Result Float to Integer Conversion. //===----------------------------------------------------------------------===// @@ -52,8 +69,17 @@ void DAGTypeLegalizer::FloatToIntResult(SDNode *N, unsigned ResNo) { case ISD::BIT_CONVERT: R = FloatToIntRes_BIT_CONVERT(N); break; case ISD::BUILD_PAIR: R = FloatToIntRes_BUILD_PAIR(N); break; + case ISD::ConstantFP: + R = FloatToIntRes_ConstantFP(cast(N)); + break; case ISD::FCOPYSIGN: R = FloatToIntRes_FCOPYSIGN(N); break; case ISD::LOAD: R = FloatToIntRes_LOAD(N); break; + case ISD::SINT_TO_FP: + case ISD::UINT_TO_FP: R = FloatToIntRes_XINT_TO_FP(N); break; + + case ISD::FADD: R = FloatToIntRes_FADD(N); break; + case ISD::FMUL: R = FloatToIntRes_FMUL(N); break; + case ISD::FSUB: R = FloatToIntRes_FSUB(N); break; } // If R is null, the sub-method took care of registering the result. @@ -73,6 +99,23 @@ SDOperand DAGTypeLegalizer::FloatToIntRes_BUILD_PAIR(SDNode *N) { BitConvertToInteger(N->getOperand(1))); } +SDOperand DAGTypeLegalizer::FloatToIntRes_ConstantFP(ConstantFPSDNode *N) { + return DAG.getConstant(N->getValueAPF().convertToAPInt(), + TLI.getTypeToTransformTo(N->getValueType(0))); +} + +SDOperand DAGTypeLegalizer::FloatToIntRes_FADD(SDNode *N) { + MVT::ValueType NVT = TLI.getTypeToTransformTo(N->getValueType(0)); + SDOperand Ops[2] = { GetIntegerOp(N->getOperand(0)), + GetIntegerOp(N->getOperand(1)) }; + return MakeLibCall(GetFPLibCall(N->getValueType(0), + RTLIB::ADD_F32, + RTLIB::ADD_F64, + RTLIB::ADD_F80, + RTLIB::ADD_PPCF128), + NVT, Ops, 2, false/*sign irrelevant*/); +} + SDOperand DAGTypeLegalizer::FloatToIntRes_FCOPYSIGN(SDNode *N) { SDOperand LHS = GetIntegerOp(N->getOperand(0)); SDOperand RHS = BitConvertToInteger(N->getOperand(1)); @@ -112,14 +155,148 @@ SDOperand DAGTypeLegalizer::FloatToIntRes_FCOPYSIGN(SDNode *N) { return DAG.getNode(ISD::OR, LVT, LHS, SignBit); } -SDOperand DAGTypeLegalizer::FloatToIntRes_LOAD(SDNode *N) { +SDOperand DAGTypeLegalizer::FloatToIntRes_FMUL(SDNode *N) { MVT::ValueType NVT = TLI.getTypeToTransformTo(N->getValueType(0)); - LoadSDNode *L = cast(N); + SDOperand Ops[2] = { GetIntegerOp(N->getOperand(0)), + GetIntegerOp(N->getOperand(1)) }; + return MakeLibCall(GetFPLibCall(N->getValueType(0), + RTLIB::MUL_F32, + RTLIB::MUL_F64, + RTLIB::MUL_F80, + RTLIB::MUL_PPCF128), + NVT, Ops, 2, false/*sign irrelevant*/); +} - return DAG.getLoad(L->getAddressingMode(), L->getExtensionType(), - NVT, L->getChain(), L->getBasePtr(), L->getOffset(), - L->getSrcValue(), L->getSrcValueOffset(), - L->getMemoryVT(), L->isVolatile(), L->getAlignment()); +SDOperand DAGTypeLegalizer::FloatToIntRes_FSUB(SDNode *N) { + MVT::ValueType NVT = TLI.getTypeToTransformTo(N->getValueType(0)); + SDOperand Ops[2] = { GetIntegerOp(N->getOperand(0)), + GetIntegerOp(N->getOperand(1)) }; + return MakeLibCall(GetFPLibCall(N->getValueType(0), + RTLIB::SUB_F32, + RTLIB::SUB_F64, + RTLIB::SUB_F80, + RTLIB::SUB_PPCF128), + NVT, Ops, 2, false/*sign irrelevant*/); +} + +SDOperand DAGTypeLegalizer::FloatToIntRes_LOAD(SDNode *N) { + LoadSDNode *L = cast(N); + MVT::ValueType VT = N->getValueType(0); + MVT::ValueType NVT = TLI.getTypeToTransformTo(VT); + + if (L->getExtensionType() == ISD::NON_EXTLOAD) + return DAG.getLoad(L->getAddressingMode(), L->getExtensionType(), + NVT, L->getChain(), L->getBasePtr(), L->getOffset(), + L->getSrcValue(), L->getSrcValueOffset(), NVT, + L->isVolatile(), L->getAlignment()); + + // Do a non-extending load followed by FP_EXTEND. + SDOperand NL = DAG.getLoad(L->getAddressingMode(), ISD::NON_EXTLOAD, + L->getMemoryVT(), L->getChain(), + L->getBasePtr(), L->getOffset(), + L->getSrcValue(), L->getSrcValueOffset(), + L->getMemoryVT(), + L->isVolatile(), L->getAlignment()); + return BitConvertToInteger(DAG.getNode(ISD::FP_EXTEND, VT, NL)); +} + +SDOperand DAGTypeLegalizer::FloatToIntRes_XINT_TO_FP(SDNode *N) { + bool isSigned = N->getOpcode() == ISD::SINT_TO_FP; + MVT::ValueType DestVT = N->getValueType(0); + SDOperand Op = N->getOperand(0); + + if (Op.getValueType() == MVT::i32) { + // simple 32-bit [signed|unsigned] integer to float/double expansion + + // Get the stack frame index of a 8 byte buffer. + SDOperand StackSlot = DAG.CreateStackTemporary(MVT::f64); + + // word offset constant for Hi/Lo address computation + SDOperand Offset = DAG.getConstant(MVT::getSizeInBits(MVT::i32) / 8, + TLI.getPointerTy()); + // set up Hi and Lo (into buffer) address based on endian + SDOperand Hi = StackSlot; + SDOperand Lo = DAG.getNode(ISD::ADD, TLI.getPointerTy(), StackSlot, Offset); + if (TLI.isLittleEndian()) + std::swap(Hi, Lo); + + // if signed map to unsigned space + SDOperand OpMapped; + if (isSigned) { + // constant used to invert sign bit (signed to unsigned mapping) + SDOperand SignBit = DAG.getConstant(0x80000000u, MVT::i32); + OpMapped = DAG.getNode(ISD::XOR, MVT::i32, Op, SignBit); + } else { + OpMapped = Op; + } + // store the lo of the constructed double - based on integer input + SDOperand Store1 = DAG.getStore(DAG.getEntryNode(), + OpMapped, Lo, NULL, 0); + // initial hi portion of constructed double + SDOperand InitialHi = DAG.getConstant(0x43300000u, MVT::i32); + // store the hi of the constructed double - biased exponent + SDOperand Store2=DAG.getStore(Store1, InitialHi, Hi, NULL, 0); + // load the constructed double + SDOperand Load = DAG.getLoad(MVT::f64, Store2, StackSlot, NULL, 0); + // FP constant to bias correct the final result + SDOperand Bias = DAG.getConstantFP(isSigned ? + BitsToDouble(0x4330000080000000ULL) + : BitsToDouble(0x4330000000000000ULL), + MVT::f64); + // subtract the bias + SDOperand Sub = DAG.getNode(ISD::FSUB, MVT::f64, Load, Bias); + // final result + SDOperand Result; + // handle final rounding + if (DestVT == MVT::f64) { + // do nothing + Result = Sub; + } else if (MVT::getSizeInBits(DestVT) < MVT::getSizeInBits(MVT::f64)) { + Result = DAG.getNode(ISD::FP_ROUND, DestVT, Sub, + DAG.getIntPtrConstant(0)); + } else if (MVT::getSizeInBits(DestVT) > MVT::getSizeInBits(MVT::f64)) { + Result = DAG.getNode(ISD::FP_EXTEND, DestVT, Sub); + } + return BitConvertToInteger(Result); + } + assert(!isSigned && "Legalize cannot Expand SINT_TO_FP for i64 yet"); + SDOperand Tmp1 = DAG.getNode(ISD::SINT_TO_FP, DestVT, Op); + + SDOperand SignSet = DAG.getSetCC(TLI.getSetCCResultType(Op), Op, + DAG.getConstant(0, Op.getValueType()), + ISD::SETLT); + SDOperand Zero = DAG.getIntPtrConstant(0), Four = DAG.getIntPtrConstant(4); + SDOperand CstOffset = DAG.getNode(ISD::SELECT, Zero.getValueType(), + SignSet, Four, Zero); + + // If the sign bit of the integer is set, the large number will be treated + // as a negative number. To counteract this, the dynamic code adds an + // offset depending on the data type. + uint64_t FF; + switch (Op.getValueType()) { + default: assert(0 && "Unsupported integer type!"); + case MVT::i8 : FF = 0x43800000ULL; break; // 2^8 (as a float) + case MVT::i16: FF = 0x47800000ULL; break; // 2^16 (as a float) + case MVT::i32: FF = 0x4F800000ULL; break; // 2^32 (as a float) + case MVT::i64: FF = 0x5F800000ULL; break; // 2^64 (as a float) + } + if (TLI.isLittleEndian()) FF <<= 32; + static Constant *FudgeFactor = ConstantInt::get(Type::Int64Ty, FF); + + SDOperand CPIdx = DAG.getConstantPool(FudgeFactor, TLI.getPointerTy()); + CPIdx = DAG.getNode(ISD::ADD, TLI.getPointerTy(), CPIdx, CstOffset); + SDOperand FudgeInReg; + if (DestVT == MVT::f32) + FudgeInReg = DAG.getLoad(MVT::f32, DAG.getEntryNode(), CPIdx, + PseudoSourceValue::getConstantPool(), 0); + else { + FudgeInReg = DAG.getExtLoad(ISD::EXTLOAD, DestVT, + DAG.getEntryNode(), CPIdx, + PseudoSourceValue::getConstantPool(), 0, + MVT::f32); + } + + return BitConvertToInteger(DAG.getNode(ISD::FADD, DestVT, Tmp1, FudgeInReg)); }