Add support for expanding PPC 128 bit floats.
authorDuncan Sands <baldrick@free.fr>
Wed, 25 Jun 2008 20:24:48 +0000 (20:24 +0000)
committerDuncan Sands <baldrick@free.fr>
Wed, 25 Jun 2008 20:24:48 +0000 (20:24 +0000)
For this it is convenient to permit floats to
be used with EXTRACT_ELEMENT, so I tweaked
things to allow that.  I also added libcalls
for ppcf128 to i32 forms of FP_TO_XINT, since
they exist in libgcc and this case can certainly
occur (and does occur in the testsuite) - before
the i64 libcall was being used.  Also, the
XINT_TO_FP result seemed to be wrong when
the argument is an i128: the wrong fudge
factor was added (the i32 and i64 cases were
handled directly, but the i128 code fell
through to some generic softening code which
seemed to think it was i64 to f32!).  So I
fixed it by adding a fudge factor that I
found in my breakfast cereal.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@52739 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/RuntimeLibcalls.h
include/llvm/CodeGen/SelectionDAGNodes.h
lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
lib/CodeGen/SelectionDAG/LegalizeTypes.h
lib/CodeGen/SelectionDAG/SelectionDAG.cpp
lib/CodeGen/SelectionDAG/TargetLowering.cpp

index 92a0b788866529efe94f8d6404d417a8b15d20e5..0138b0c4842d6db21de46769c2dd2ee43d2199c9 100644 (file)
@@ -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,
index 2e274558138604f0417df3b8885597c3fd9f96f1..f56863cd6ee5a384bbe991d4130f5600cf74fca8 100644 (file)
@@ -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.
index d99a9bd6dfd59c65627ed3e6c2ab9676df3bfabb..be1d45502dacb9cefa5aaf63acdd418a98df3b66 100644 (file)
@@ -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<ConstantFPSDNode>(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<StoreSDNode>(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);
index ea7ac8f26bde80d2d8066c9f6d16f7ba796049ce..add3dcdf1bc3a540019e660930582e7659106ee9 100644 (file)
@@ -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);
index 78281aa63263866e1e891794b6cca71b4f538bd1..fdff418a615786637e0aca836b5b442e24929612 100644 (file)
@@ -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
index c99319338e3aa9194d14215def9e7070abdc90b5..ae9b917f1bd54b451c28b60f03a9ee1e7db535c4 100644 (file)
@@ -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";