timshen created this revision.
timshen added reviewers: hfinkel, kbarton, iteratee, echristo.
timshen added subscribers: llvm-commits, cfe-commits.
Herald added subscribers: nemanjai, mehdi_amini.

This patch changes the layout of DoubleAPFloat, and adjust all
operations to do either:

1. (IEEEdouble, IEEEdouble) -> (uint64_t, uint64_t) -> PPCDoubleDoubleImpl, 
then run the old algorithm.
2. Do the right thing directly.

1. includes multiply, divide, remainder, mod, fusedMultiplyAdd, 
roundToIntegral, convertFromString, next, convertToInteger, convertFromAPInt, 
convertFromSignExtendedInteger, convertFromZeroExtendedInteger, 
convertToHexString, toString, getExactInverse.
2. includes makeZero, makeLargest, makeSmallest, makeSmallestNormalized, 
compare, bitwiseIsEqual, bitcastToAPInt, isDenormal, isSmallest, isLargest, 
isInteger, ilogb, scalbn, frexp, hash_value, Profile.

I could split this into two patches, e.g. use

1. for all operatoins first, then incrementally change some of them to

2). I didn't do that, because 1) involves code that converts data between
PPCDoubleDoubleImpl and (IEEEdouble, IEEEdouble) back and forth, and may
pessimize the compiler. Instead, I find easy functions and use
approach 2) for them directly.

Next step is to implement move multiply and divide from 1) to 2). I don't
have plans for other functions in 1).


https://reviews.llvm.org/D27872

Files:
  clang/test/CodeGen/ppc64-complex-parms.c
  llvm/include/llvm/ADT/APFloat.h
  llvm/lib/Support/APFloat.cpp
  llvm/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll
  llvm/unittests/ADT/APFloatTest.cpp

Index: llvm/unittests/ADT/APFloatTest.cpp
===================================================================
--- llvm/unittests/ADT/APFloatTest.cpp
+++ llvm/unittests/ADT/APFloatTest.cpp
@@ -9,6 +9,7 @@
 
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/raw_ostream.h"
@@ -3262,7 +3263,7 @@
         << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
-    EXPECT_EQ(Expected[1], A1.getSecondFloat().bitcastToAPInt().getRawData()[0])
+    EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
         << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
@@ -3296,7 +3297,7 @@
         << formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
-    EXPECT_EQ(Expected[1], A1.getSecondFloat().bitcastToAPInt().getRawData()[0])
+    EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
         << formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
@@ -3496,12 +3497,53 @@
     APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
     APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
     EXPECT_EQ(Expected, A1.compare(A2))
-        << formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
+        << formatv("compare(({0:x} + {1:x}), ({2:x} + {3:x}))", Op1[0], Op1[1],
+                   Op2[0], Op2[1])
+               .str();
+  }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleBitwiseIsEqual) {
+  using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, bool>;
+
+  DataType Data[] = {
+      // (1 + 0) = (1 + 0)
+      std::make_tuple(0x3ff0000000000000ull, 0, 0x3ff0000000000000ull, 0, true),
+      // (1 + 0) != (1.00...1 + 0)
+      std::make_tuple(0x3ff0000000000000ull, 0, 0x3ff0000000000001ull, 0,
+                      false),
+      // NaN = NaN
+      std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff8000000000000ull, 0, true),
+      // NaN != NaN with a different bit pattern
+      std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff8000000000000ull,
+                      0x3ff0000000000000ull, false),
+      // Inf = Inf
+      std::make_tuple(0x7ff0000000000000ull, 0, 0x7ff0000000000000ull, 0, true),
+  };
+
+  for (auto Tp : Data) {
+    uint64_t Op1[2], Op2[2];
+    bool Expected;
+    std::tie(Op1[0], Op1[1], Op2[0], Op2[1], Expected) = Tp;
+
+    APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+    APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+    EXPECT_EQ(Expected, A1.bitwiseIsEqual(A2))
+        << formatv("({0:x} + {1:x}) = ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
   }
 }
 
+TEST(APFloatTest, PPCDoubleDoubleHashValue) {
+  uint64_t Data1[] = {0x3ff0000000000001ull, 0x0000000000000001ull};
+  uint64_t Data2[] = {0x3ff0000000000001ull, 0};
+  // The hash values are *hopefully* different.
+  EXPECT_NE(
+      hash_value(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data1))),
+      hash_value(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data2))));
+}
+
 TEST(APFloatTest, PPCDoubleDoubleChangeSign) {
   uint64_t Data[] = {
       0x400f000000000000ull, 0xbcb0000000000000ull,
@@ -3531,6 +3573,13 @@
   }
   {
     uint64_t Data[] = {
+        0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+    };
+    EXPECT_EQ(APInt(128, 2, Data),
+              APFloat::getLargest(APFloat::PPCDoubleDouble()).bitcastToAPInt());
+  }
+  {
+    uint64_t Data[] = {
         0x0000000000000001ull, 0,
     };
     EXPECT_EQ(
@@ -3553,24 +3602,72 @@
   }
   {
     uint64_t Data[] = {
+        0xffefffffffffffffull, 0xfc8ffffffffffffeull,
+    };
+    EXPECT_EQ(
+        APInt(128, 2, Data),
+        APFloat::getLargest(APFloat::PPCDoubleDouble(), true).bitcastToAPInt());
+  }
+  {
+    uint64_t Data[] = {
         0x8000000000000001ull, 0x0000000000000000ull,
     };
     EXPECT_EQ(APInt(128, 2, Data),
               APFloat::getSmallest(APFloat::PPCDoubleDouble(), true)
                   .bitcastToAPInt());
   }
-
-  EXPECT_EQ(0x8360000000000000ull,
-            APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
-                .bitcastToAPInt()
-                .getRawData()[0]);
-  EXPECT_EQ(0x0000000000000000ull,
-            APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
-                .getSecondFloat()
-                .bitcastToAPInt()
-                .getRawData()[0]);
-
+  {
+    uint64_t Data[] = {
+        0x8360000000000000ull, 0x0000000000000000ull,
+    };
+    EXPECT_EQ(APInt(128, 2, Data),
+              APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
+                  .bitcastToAPInt());
+  }
   EXPECT_TRUE(APFloat::getSmallest(APFloat::PPCDoubleDouble()).isSmallest());
   EXPECT_TRUE(APFloat::getLargest(APFloat::PPCDoubleDouble()).isLargest());
 }
+
+TEST(APFloatTest, PPCDoubleDoubleIsDenormal) {
+  EXPECT_TRUE(APFloat::getSmallest(APFloat::PPCDoubleDouble()).isDenormal());
+  EXPECT_FALSE(APFloat::getLargest(APFloat::PPCDoubleDouble()).isDenormal());
+  EXPECT_FALSE(
+      APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble()).isDenormal());
+  {
+    // (4 + 3) is not normalized
+    uint64_t Data[] = {
+        0x4010000000000000ull, 0x4008000000000000ull,
+    };
+    EXPECT_TRUE(
+        APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data)).isDenormal());
+  }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleScalbn) {
+  // 3.0 + 3.0 << 53
+  uint64_t Input[] = {
+      0x4008000000000000ull, 0x3cb8000000000000ull,
+  };
+  APFloat Result =
+      scalbn(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Input)), 1,
+             APFloat::rmNearestTiesToEven);
+  // 6.0 + 6.0 << 53
+  EXPECT_EQ(0x4018000000000000ull, Result.bitcastToAPInt().getRawData()[0]);
+  EXPECT_EQ(0x3cc8000000000000ull, Result.bitcastToAPInt().getRawData()[1]);
+}
+
+TEST(APFloatTest, PPCDoubleDoubleFrexp) {
+  // 3.0 + 3.0 << 53
+  uint64_t Input[] = {
+      0x4008000000000000ull, 0x3cb8000000000000ull,
+  };
+  int Exp;
+  // 0.75 + 0.75 << 53
+  APFloat Result =
+      frexp(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Input)), Exp,
+            APFloat::rmNearestTiesToEven);
+  EXPECT_EQ(2, Exp);
+  EXPECT_EQ(0x3fe8000000000000ull, Result.bitcastToAPInt().getRawData()[0]);
+  EXPECT_EQ(0x3c98000000000000ull, Result.bitcastToAPInt().getRawData()[1]);
+}
 }
Index: llvm/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll
===================================================================
--- llvm/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll
+++ llvm/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll
@@ -128,7 +128,7 @@
 ; PPC32-DAG: oris {{[0-9]+}}, [[FLIP_BIT]], 16399
 ; PPC32-DAG: xoris {{[0-9]+}}, [[FLIP_BIT]], 48304
 ; PPC32: blr
-	%0 = tail call ppc_fp128 @llvm.copysign.ppcf128(ppc_fp128 0xMBCB0000000000000400F000000000000, ppc_fp128 %x)
+	%0 = tail call ppc_fp128 @llvm.copysign.ppcf128(ppc_fp128 0xM400F000000000000BCB0000000000000, ppc_fp128 %x)
 	%1 = bitcast ppc_fp128 %0 to i128
 	ret i128 %1
 }
Index: llvm/lib/Support/APFloat.cpp
===================================================================
--- llvm/lib/Support/APFloat.cpp
+++ llvm/lib/Support/APFloat.cpp
@@ -858,11 +858,6 @@
 
 IEEEFloat::~IEEEFloat() { freeSignificand(); }
 
-// Profile - This method 'profiles' an APFloat for use with FoldingSet.
-void IEEEFloat::Profile(FoldingSetNodeID &ID) const {
-  ID.Add(bitcastToAPInt());
-}
-
 unsigned int IEEEFloat::partCount() const {
   return partCountForBits(semantics->precision + 1);
 }
@@ -1607,16 +1602,6 @@
   sign = !sign;
 }
 
-void IEEEFloat::clearSign() {
-  /* So is this one. */
-  sign = 0;
-}
-
-void IEEEFloat::copySign(const IEEEFloat &rhs) {
-  /* And this one. */
-  sign = rhs.sign;
-}
-
 /* Normalized addition or subtraction.  */
 IEEEFloat::opStatus IEEEFloat::addOrSubtract(const IEEEFloat &rhs,
                                              roundingMode rounding_mode,
@@ -1836,7 +1821,7 @@
   IEEEFloat MagicConstant(*semantics);
   fs = MagicConstant.convertFromAPInt(IntegerConstant, false,
                                       rmNearestTiesToEven);
-  MagicConstant.copySign(*this);
+  MagicConstant.sign = sign;
 
   if (fs != opOK)
     return fs;
@@ -2181,22 +2166,6 @@
   return fs;
 }
 
-/* Same as convertToInteger(integerPart*, ...), except the result is returned in
-   an APSInt, whose initial bit-width and signed-ness are used to determine the
-   precision of the conversion.
- */
-IEEEFloat::opStatus IEEEFloat::convertToInteger(APSInt &result,
-                                                roundingMode rounding_mode,
-                                                bool *isExact) const {
-  unsigned bitWidth = result.getBitWidth();
-  SmallVector<uint64_t, 4> parts(result.getNumWords());
-  opStatus status = convertToInteger(
-    parts.data(), bitWidth, result.isSigned(), rounding_mode, isExact);
-  // Keeps the original signed-ness.
-  result = APInt(bitWidth, parts);
-  return status;
-}
-
 /* Convert an unsigned integer SRC to a floating point number,
    rounding according to ROUNDING_MODE.  The sign of the floating
    point number is not modified.  */
@@ -3616,7 +3585,7 @@
     Str.push_back(buffer[NDigits-I-1]);
 }
 
-bool IEEEFloat::getExactInverse(IEEEFloat *inv) const {
+bool IEEEFloat::getExactInverse(APFloat *inv) const {
   // Special floats and denormals have no exact inverse.
   if (!isFiniteNonZero())
     return false;
@@ -3640,7 +3609,7 @@
          reciprocal.significandLSB() == reciprocal.semantics->precision - 1);
 
   if (inv)
-    *inv = reciprocal;
+    *inv = APFloat(reciprocal, *semantics);
 
   return true;
 }
@@ -3852,39 +3821,38 @@
 }
 
 DoubleAPFloat::DoubleAPFloat(const fltSemantics &S)
-    : Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl),
-                                           APFloat(semIEEEdouble)}) {
+    : Semantics(&S),
+      Floats(new APFloat[2]{APFloat(semIEEEdouble), APFloat(semIEEEdouble)}) {
   assert(Semantics == &semPPCDoubleDouble);
 }
 
 DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, uninitializedTag)
     : Semantics(&S),
-      Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, uninitialized),
+      Floats(new APFloat[2]{APFloat(semIEEEdouble, uninitialized),
                             APFloat(semIEEEdouble, uninitialized)}) {
   assert(Semantics == &semPPCDoubleDouble);
 }
 
 DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, integerPart I)
-    : Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, I),
+    : Semantics(&S), Floats(new APFloat[2]{APFloat(semIEEEdouble, I),
                                            APFloat(semIEEEdouble)}) {
   assert(Semantics == &semPPCDoubleDouble);
 }
 
 DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, const APInt &I)
-    : Semantics(&S), Floats(new APFloat[2]{
-                         APFloat(semPPCDoubleDoubleImpl, I),
-                         APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) {
+    : Semantics(&S),
+      Floats(new APFloat[2]{
+          APFloat(semIEEEdouble, APInt(64, I.getRawData()[0])),
+          APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) {
   assert(Semantics == &semPPCDoubleDouble);
 }
 
 DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, APFloat &&First,
                              APFloat &&Second)
     : Semantics(&S),
       Floats(new APFloat[2]{std::move(First), std::move(Second)}) {
   assert(Semantics == &semPPCDoubleDouble);
-  // TODO Check for First == &IEEEdouble once the transition is done.
-  assert(&Floats[0].getSemantics() == &semPPCDoubleDoubleImpl ||
-         &Floats[0].getSemantics() == &semIEEEdouble);
+  assert(&Floats[0].getSemantics() == &semIEEEdouble);
   assert(&Floats[1].getSemantics() == &semIEEEdouble);
 }
 
@@ -4029,25 +3997,15 @@
   }
   assert(LHS.getCategory() == fcNormal && RHS.getCategory() == fcNormal);
 
-  // These conversions will go away once PPCDoubleDoubleImpl goes away.
-  // (PPCDoubleDoubleImpl, IEEEDouble) -> (IEEEDouble, IEEEDouble)
-  APFloat A(semIEEEdouble,
-            APInt(64, LHS.Floats[0].bitcastToAPInt().getRawData()[0])),
-      AA(LHS.Floats[1]),
-      C(semIEEEdouble, APInt(64, RHS.Floats[0].bitcastToAPInt().getRawData()[0])),
+  APFloat A(LHS.Floats[0]), AA(LHS.Floats[1]), C(RHS.Floats[0]),
       CC(RHS.Floats[1]);
+  assert(&A.getSemantics() == &semIEEEdouble);
   assert(&AA.getSemantics() == &semIEEEdouble);
+  assert(&C.getSemantics() == &semIEEEdouble);
   assert(&CC.getSemantics() == &semIEEEdouble);
-  Out.Floats[0] = APFloat(semIEEEdouble);
+  assert(&Out.Floats[0].getSemantics() == &semIEEEdouble);
   assert(&Out.Floats[1].getSemantics() == &semIEEEdouble);
-
-  auto Ret = Out.addImpl(A, AA, C, CC, RM);
-
-  // (IEEEDouble, IEEEDouble) -> (PPCDoubleDoubleImpl, IEEEDouble)
-  uint64_t Buffer[] = {Out.Floats[0].bitcastToAPInt().getRawData()[0],
-                       Out.Floats[1].bitcastToAPInt().getRawData()[0]};
-  Out.Floats[0] = APFloat(semPPCDoubleDoubleImpl, APInt(128, 2, Buffer));
-  return Ret;
+  return Out.addImpl(A, AA, C, CC, RM);
 }
 
 APFloat::opStatus DoubleAPFloat::add(const DoubleAPFloat &RHS,
@@ -4063,6 +4021,82 @@
   return Ret;
 }
 
+APFloat::opStatus DoubleAPFloat::multiply(const DoubleAPFloat &RHS,
+                                          APFloat::roundingMode RM) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt());
+    auto Ret =
+        Tmp.multiply(APFloat(semPPCDoubleDoubleImpl, RHS.bitcastToAPInt()), RM);
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus DoubleAPFloat::divide(const DoubleAPFloat &RHS,
+                                        APFloat::roundingMode RM) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt());
+    auto Ret =
+        Tmp.divide(APFloat(semPPCDoubleDoubleImpl, RHS.bitcastToAPInt()), RM);
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus DoubleAPFloat::remainder(const DoubleAPFloat &RHS) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt());
+    auto Ret =
+        Tmp.remainder(APFloat(semPPCDoubleDoubleImpl, RHS.bitcastToAPInt()));
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus DoubleAPFloat::mod(const DoubleAPFloat &RHS) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt());
+    auto Ret = Tmp.mod(APFloat(semPPCDoubleDoubleImpl, RHS.bitcastToAPInt()));
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus
+DoubleAPFloat::fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
+                                const DoubleAPFloat &Addend,
+                                APFloat::roundingMode RM) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt());
+    auto Ret = Tmp.fusedMultiplyAdd(
+        APFloat(semPPCDoubleDoubleImpl, Multiplicand.bitcastToAPInt()),
+        APFloat(semPPCDoubleDoubleImpl, Addend.bitcastToAPInt()), RM);
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus DoubleAPFloat::roundToIntegral(APFloat::roundingMode RM) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt());
+    auto Ret = Tmp.roundToIntegral(RM);
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
 void DoubleAPFloat::changeSign() {
   Floats[0].changeSign();
   Floats[1].changeSign();
@@ -4100,11 +4134,249 @@
   Floats[1].makeZero(false);
 }
 
+void DoubleAPFloat::makeZero(bool Neg) {
+  Floats[0].makeZero(Neg);
+  Floats[1].makeZero(false);
+}
+
+void DoubleAPFloat::makeLargest(bool Neg) {
+  if (Semantics == &semPPCDoubleDouble) {
+    Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x7fefffffffffffffull));
+    Floats[1] = APFloat(semIEEEdouble, APInt(64, 0x7c8ffffffffffffeull));
+    if (Neg)
+      changeSign();
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+void DoubleAPFloat::makeSmallest(bool Neg) {
+  if (Semantics == &semPPCDoubleDouble) {
+    Floats[0].makeSmallest(Neg);
+    Floats[1].makeZero(false);
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+void DoubleAPFloat::makeSmallestNormalized(bool Neg) {
+  if (Semantics == &semPPCDoubleDouble) {
+    Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x0360000000000000ull));
+    if (Neg)
+      Floats[0].changeSign();
+    Floats[1].makeZero(false);
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
 void DoubleAPFloat::makeNaN(bool SNaN, bool Neg, const APInt *fill) {
   Floats[0].makeNaN(SNaN, Neg, fill);
   Floats[1].makeZero(false);
 }
 
+APFloat::cmpResult DoubleAPFloat::compare(const DoubleAPFloat &RHS) const {
+  auto Result = Floats[0].compare(RHS.Floats[0]);
+  if (Result == APFloat::cmpEqual)
+    return Floats[1].compare(RHS.Floats[1]);
+  return Result;
+}
+
+bool DoubleAPFloat::bitwiseIsEqual(const DoubleAPFloat &RHS) const {
+  return Floats[0].bitwiseIsEqual(RHS.Floats[0]) &&
+         Floats[1].bitwiseIsEqual(RHS.Floats[1]);
+}
+
+hash_code hash_value(const DoubleAPFloat &Arg) {
+  if (Arg.Floats)
+    return hash_combine(hash_value(Arg.Floats[0]), hash_value(Arg.Floats[1]));
+  return hash_combine(Arg.Semantics);
+}
+
+APInt DoubleAPFloat::bitcastToAPInt() const {
+  if (Semantics == &semPPCDoubleDouble) {
+    uint64_t Data[] = {
+        Floats[0].bitcastToAPInt().getRawData()[0],
+        Floats[1].bitcastToAPInt().getRawData()[0],
+    };
+    return APInt(128, 2, Data);
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus DoubleAPFloat::convertFromString(StringRef S,
+                                                   roundingMode RM) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl);
+    auto Ret = Tmp.convertFromString(S, RM);
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus DoubleAPFloat::next(bool nextDown) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt());
+    auto Ret = Tmp.next(nextDown);
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus DoubleAPFloat::convertToInteger(integerPart *Input,
+                                                  unsigned int Width,
+                                                  bool IsSigned,
+                                                  roundingMode RM,
+                                                  bool *IsExact) const {
+  if (Semantics == &semPPCDoubleDouble) {
+    return APFloat(semPPCDoubleDoubleImpl, bitcastToAPInt())
+        .convertToInteger(Input, Width, IsSigned, RM, IsExact);
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus DoubleAPFloat::convertFromAPInt(const APInt &Input,
+                                                  bool IsSigned,
+                                                  roundingMode RM) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl);
+    auto Ret = Tmp.convertFromAPInt(Input, IsSigned, RM);
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus
+DoubleAPFloat::convertFromSignExtendedInteger(const integerPart *Input,
+                                              unsigned int InputSize,
+                                              bool IsSigned, roundingMode RM) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl);
+    auto Ret =
+        Tmp.convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM);
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+APFloat::opStatus
+DoubleAPFloat::convertFromZeroExtendedInteger(const integerPart *Input,
+                                              unsigned int InputSize,
+                                              bool IsSigned, roundingMode RM) {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl);
+    auto Ret =
+        Tmp.convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM);
+    *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+unsigned int DoubleAPFloat::convertToHexString(char *DST,
+                                               unsigned int HexDigits,
+                                               bool UpperCase,
+                                               roundingMode RM) const {
+  if (Semantics == &semPPCDoubleDouble) {
+    return APFloat(semPPCDoubleDoubleImpl, bitcastToAPInt())
+        .convertToHexString(DST, HexDigits, UpperCase, RM);
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+bool DoubleAPFloat::isDenormal() const {
+  return getCategory() == fcNormal &&
+         (Floats[0].isDenormal() || Floats[1].isDenormal() ||
+          Floats[0].compare(Floats[0] + Floats[1]) != cmpEqual);
+}
+
+bool DoubleAPFloat::isSmallest() const {
+  if (getCategory() != fcNormal)
+    return false;
+  DoubleAPFloat Tmp(*this);
+  Tmp.makeSmallest(this->isNegative());
+  return Tmp.compare(*this) == cmpEqual;
+}
+
+bool DoubleAPFloat::isLargest() const {
+  if (getCategory() != fcNormal)
+    return false;
+  DoubleAPFloat Tmp(*this);
+  Tmp.makeLargest(this->isNegative());
+  return Tmp.compare(*this) == cmpEqual;
+}
+
+bool DoubleAPFloat::isInteger() const {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl);
+    (void)Tmp.add(Floats[0], rmNearestTiesToEven);
+    (void)Tmp.add(Floats[1], rmNearestTiesToEven);
+    return Tmp.isInteger();
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+void DoubleAPFloat::toString(SmallVectorImpl<char> &Str,
+                             unsigned FormatPrecision,
+                             unsigned FormatMaxPadding) const {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat(semPPCDoubleDoubleImpl, bitcastToAPInt())
+        .toString(Str, FormatPrecision, FormatMaxPadding);
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+bool DoubleAPFloat::getExactInverse(APFloat *inv) const {
+  if (Semantics == &semPPCDoubleDouble) {
+    APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt());
+    if (!inv)
+      return Tmp.getExactInverse(nullptr);
+    APFloat Inv(semPPCDoubleDoubleImpl);
+    auto Ret = Tmp.getExactInverse(&Inv);
+    *inv = APFloat(semPPCDoubleDouble, Inv.bitcastToAPInt());
+    return Ret;
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+DoubleAPFloat scalbn(DoubleAPFloat Arg, int Exp, APFloat::roundingMode RM) {
+  if (Arg.Semantics == &semPPCDoubleDouble) {
+    return DoubleAPFloat(semPPCDoubleDouble, scalbn(Arg.Floats[0], Exp, RM),
+                         scalbn(Arg.Floats[1], Exp, RM));
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
+DoubleAPFloat frexp(const DoubleAPFloat &Arg, int &Exp,
+                    APFloat::roundingMode RM) {
+  if (Arg.Semantics == &semPPCDoubleDouble) {
+    APFloat First = frexp(Arg.Floats[0], Exp, RM);
+    APFloat Second = Arg.Floats[1];
+    if (Arg.getCategory() == APFloat::fcNormal)
+      Second = scalbn(Second, -Exp, RM);
+    return DoubleAPFloat(semPPCDoubleDouble, std::move(First),
+                         std::move(Second));
+  } else {
+    llvm_unreachable("Only PPCDoubleDouble is supported for now");
+  }
+}
+
 } // End detail namespace
 
 APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) {
@@ -4120,10 +4392,24 @@
 }
 
 APFloat::opStatus APFloat::convertFromString(StringRef Str, roundingMode RM) {
-  return getIEEE().convertFromString(Str, RM);
+  if (usesLayout<IEEEFloat>(getSemantics())) {
+    return U.IEEE.convertFromString(Str, RM);
+  } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+    return U.Double.convertFromString(Str, RM);
+  } else {
+    llvm_unreachable("Unexpected semantics");
+  }
 }
 
-hash_code hash_value(const APFloat &Arg) { return hash_value(Arg.getIEEE()); }
+hash_code hash_value(const APFloat &Arg) {
+  if (APFloat::usesLayout<detail::IEEEFloat>(Arg.getSemantics())) {
+    return hash_value(Arg.U.IEEE);
+  } else if (APFloat::usesLayout<detail::DoubleAPFloat>(Arg.getSemantics())) {
+    return hash_value(Arg.U.Double);
+  } else {
+    llvm_unreachable("Unexpected semantics");
+  }
+}
 
 APFloat::APFloat(const fltSemantics &Semantics, StringRef S)
     : APFloat(Semantics) {
@@ -4141,9 +4427,7 @@
              usesLayout<DoubleAPFloat>(ToSemantics)) {
     assert(&ToSemantics == &semPPCDoubleDouble);
     auto Ret = U.IEEE.convert(semPPCDoubleDoubleImpl, RM, losesInfo);
-    *this = APFloat(
-        DoubleAPFloat(semPPCDoubleDouble, std::move(*this), APFloat(semIEEEdouble)),
-        ToSemantics);
+    *this = APFloat(ToSemantics, U.IEEE.bitcastToAPInt());
     return Ret;
   } else if (usesLayout<DoubleAPFloat>(getSemantics()) &&
              usesLayout<IEEEFloat>(ToSemantics)) {
@@ -4185,4 +4469,24 @@
 
 void APFloat::dump() const { print(dbgs()); }
 
+void APFloat::Profile(FoldingSetNodeID &NID) const {
+  NID.Add(bitcastToAPInt());
+}
+
+/* Same as convertToInteger(integerPart*, ...), except the result is returned in
+   an APSInt, whose initial bit-width and signed-ness are used to determine the
+   precision of the conversion.
+ */
+APFloat::opStatus APFloat::convertToInteger(APSInt &result,
+                                            roundingMode rounding_mode,
+                                            bool *isExact) const {
+  unsigned bitWidth = result.getBitWidth();
+  SmallVector<uint64_t, 4> parts(result.getNumWords());
+  opStatus status = convertToInteger(parts.data(), bitWidth, result.isSigned(),
+                                     rounding_mode, isExact);
+  // Keeps the original signed-ness.
+  result = APInt(bitWidth, parts);
+  return status;
+}
+
 } // End llvm namespace
Index: llvm/include/llvm/ADT/APFloat.h
===================================================================
--- llvm/include/llvm/ADT/APFloat.h
+++ llvm/include/llvm/ADT/APFloat.h
@@ -235,10 +235,6 @@
 
   /// @}
 
-  /// Used to insert APFloat objects, or objects that contain APFloat objects,
-  /// into FoldingSets.
-  void Profile(FoldingSetNodeID &NID) const;
-
   /// \name Arithmetic
   /// @{
 
@@ -255,53 +251,12 @@
   /// IEEE-754R 5.3.1: nextUp/nextDown.
   opStatus next(bool nextDown);
 
-  /// \brief Operator+ overload which provides the default
-  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
-  IEEEFloat operator+(const IEEEFloat &RHS) const {
-    IEEEFloat Result = *this;
-    Result.add(RHS, rmNearestTiesToEven);
-    return Result;
-  }
-
-  /// \brief Operator- overload which provides the default
-  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
-  IEEEFloat operator-(const IEEEFloat &RHS) const {
-    IEEEFloat Result = *this;
-    Result.subtract(RHS, rmNearestTiesToEven);
-    return Result;
-  }
-
-  /// \brief Operator* overload which provides the default
-  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
-  IEEEFloat operator*(const IEEEFloat &RHS) const {
-    IEEEFloat Result = *this;
-    Result.multiply(RHS, rmNearestTiesToEven);
-    return Result;
-  }
-
-  /// \brief Operator/ overload which provides the default
-  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
-  IEEEFloat operator/(const IEEEFloat &RHS) const {
-    IEEEFloat Result = *this;
-    Result.divide(RHS, rmNearestTiesToEven);
-    return Result;
-  }
-
   /// @}
 
   /// \name Sign operations.
   /// @{
 
   void changeSign();
-  void clearSign();
-  void copySign(const IEEEFloat &);
-
-  /// \brief A static helper to produce a copy of an APFloat value with its sign
-  /// copied from some other APFloat.
-  static IEEEFloat copySign(IEEEFloat Value, const IEEEFloat &Sign) {
-    Value.copySign(Sign);
-    return Value;
-  }
 
   /// @}
 
@@ -311,7 +266,6 @@
   opStatus convert(const fltSemantics &, roundingMode, bool *);
   opStatus convertToInteger(integerPart *, unsigned int, bool, roundingMode,
                             bool *) const;
-  opStatus convertToInteger(APSInt &, roundingMode, bool *) const;
   opStatus convertFromAPInt(const APInt &, bool, roundingMode);
   opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int,
                                           bool, roundingMode);
@@ -443,7 +397,7 @@
 
   /// If this value has an exact multiplicative inverse, store it in inv and
   /// return true.
-  bool getExactInverse(IEEEFloat *inv) const;
+  bool getExactInverse(APFloat *inv) const;
 
   /// \brief Returns the exponent of the internal representation of the APFloat.
   ///
@@ -636,16 +590,63 @@
 
   opStatus add(const DoubleAPFloat &RHS, roundingMode RM);
   opStatus subtract(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus multiply(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus divide(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus remainder(const DoubleAPFloat &RHS);
+  opStatus mod(const DoubleAPFloat &RHS);
+  opStatus fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
+                            const DoubleAPFloat &Addend, roundingMode RM);
+  opStatus roundToIntegral(roundingMode RM);
   void changeSign();
   cmpResult compareAbsoluteValue(const DoubleAPFloat &RHS) const;
 
   fltCategory getCategory() const;
   bool isNegative() const;
 
   void makeInf(bool Neg);
+  void makeZero(bool Neg);
+  void makeLargest(bool Neg);
+  void makeSmallest(bool Neg);
+  void makeSmallestNormalized(bool Neg);
   void makeNaN(bool SNaN, bool Neg, const APInt *fill);
+
+  cmpResult compare(const DoubleAPFloat &RHS) const;
+  bool bitwiseIsEqual(const DoubleAPFloat &RHS) const;
+  APInt bitcastToAPInt() const;
+  opStatus convertFromString(StringRef, roundingMode);
+  opStatus next(bool nextDown);
+
+  opStatus convertToInteger(integerPart *Input, unsigned int Width,
+                            bool IsSigned, roundingMode RM,
+                            bool *IsExact) const;
+  opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM);
+  opStatus convertFromSignExtendedInteger(const integerPart *Input,
+                                          unsigned int InputSize, bool IsSigned,
+                                          roundingMode RM);
+  opStatus convertFromZeroExtendedInteger(const integerPart *Input,
+                                          unsigned int InputSize, bool IsSigned,
+                                          roundingMode RM);
+  unsigned int convertToHexString(char *DST, unsigned int HexDigits,
+                                  bool UpperCase, roundingMode RM) const;
+
+  bool isDenormal() const;
+  bool isSmallest() const;
+  bool isLargest() const;
+  bool isInteger() const;
+
+  void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
+                unsigned FormatMaxPadding) const;
+
+  bool getExactInverse(APFloat *inv) const;
+
+  friend int ilogb(const DoubleAPFloat &Arg);
+  friend DoubleAPFloat scalbn(DoubleAPFloat X, int Exp, roundingMode);
+  friend DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp, roundingMode);
+  friend hash_code hash_value(const DoubleAPFloat &Arg);
 };
 
+hash_code hash_value(const DoubleAPFloat &Arg);
+
 } // End detail namespace
 
 // This is a interface class that is currently forwarding functionalities from
@@ -766,7 +767,15 @@
     }
   }
 
-  void makeZero(bool Neg) { getIEEE().makeZero(Neg); }
+  void makeZero(bool Neg) {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.makeZero(Neg);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.makeZero(Neg);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
 
   void makeInf(bool Neg) {
     if (usesLayout<IEEEFloat>(*U.semantics)) {
@@ -779,15 +788,43 @@
   }
 
   void makeNaN(bool SNaN, bool Neg, const APInt *fill) {
-    getIEEE().makeNaN(SNaN, Neg, fill);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.makeNaN(SNaN, Neg, fill);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.makeNaN(SNaN, Neg, fill);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
 
-  void makeLargest(bool Neg) { getIEEE().makeLargest(Neg); }
+  void makeLargest(bool Neg) {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.makeLargest(Neg);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.makeLargest(Neg);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
 
-  void makeSmallest(bool Neg) { getIEEE().makeSmallest(Neg); }
+  void makeSmallest(bool Neg) {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.makeSmallest(Neg);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.makeSmallest(Neg);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
 
   void makeSmallestNormalized(bool Neg) {
-    getIEEE().makeSmallestNormalized(Neg);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.makeSmallestNormalized(Neg);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.makeSmallestNormalized(Neg);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
 
   // FIXME: This is due to clang 3.3 (or older version) always checks for the
@@ -802,7 +839,8 @@
       : U(std::move(F), S) {}
 
   cmpResult compareAbsoluteValue(const APFloat &RHS) const {
-    assert(&getSemantics() == &RHS.getSemantics());
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only compare APFloats with the same semantics");
     if (usesLayout<IEEEFloat>(getSemantics())) {
       return U.IEEE.compareAbsoluteValue(RHS.U.IEEE);
     } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
@@ -922,9 +960,13 @@
   /// \param isIEEE   - If 128 bit number, select between PPC and IEEE
   static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false);
 
-  void Profile(FoldingSetNodeID &NID) const { getIEEE().Profile(NID); }
+  /// Used to insert APFloat objects, or objects that contain APFloat objects,
+  /// into FoldingSets.
+  void Profile(FoldingSetNodeID &NID) const;
 
   opStatus add(const APFloat &RHS, roundingMode RM) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
     if (usesLayout<IEEEFloat>(getSemantics())) {
       return U.IEEE.add(RHS.U.IEEE, RM);
     } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
@@ -934,6 +976,8 @@
     }
   }
   opStatus subtract(const APFloat &RHS, roundingMode RM) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
     if (usesLayout<IEEEFloat>(getSemantics())) {
       return U.IEEE.subtract(RHS.U.IEEE, RM);
     } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
@@ -943,103 +987,256 @@
     }
   }
   opStatus multiply(const APFloat &RHS, roundingMode RM) {
-    return getIEEE().multiply(RHS.getIEEE(), RM);
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.multiply(RHS.U.IEEE, RM);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.multiply(RHS.U.Double, RM);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
   opStatus divide(const APFloat &RHS, roundingMode RM) {
-    return getIEEE().divide(RHS.getIEEE(), RM);
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.divide(RHS.U.IEEE, RM);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.divide(RHS.U.Double, RM);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
   opStatus remainder(const APFloat &RHS) {
-    return getIEEE().remainder(RHS.getIEEE());
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.remainder(RHS.U.IEEE);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.remainder(RHS.U.Double);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
+  opStatus mod(const APFloat &RHS) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.mod(RHS.U.IEEE);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.mod(RHS.U.Double);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
-  opStatus mod(const APFloat &RHS) { return getIEEE().mod(RHS.getIEEE()); }
   opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend,
                             roundingMode RM) {
-    return getIEEE().fusedMultiplyAdd(Multiplicand.getIEEE(), Addend.getIEEE(),
-                                      RM);
+    assert(&getSemantics() == &Multiplicand.getSemantics() &&
+           "Should only call on APFloats with the same semantics");
+    assert(&getSemantics() == &Addend.getSemantics() &&
+           "Should only call on APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.fusedMultiplyAdd(Multiplicand.U.IEEE, Addend.U.IEEE, RM);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.fusedMultiplyAdd(Multiplicand.U.Double, Addend.U.Double,
+                                       RM);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
   opStatus roundToIntegral(roundingMode RM) {
-    return getIEEE().roundToIntegral(RM);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.roundToIntegral(RM);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.roundToIntegral(RM);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
-  opStatus next(bool nextDown) { return getIEEE().next(nextDown); }
 
+  opStatus next(bool nextDown) {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.next(nextDown);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.next(nextDown);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
+
+  /// \brief Operator+ overload which provides the default
+  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
   APFloat operator+(const APFloat &RHS) const {
-    return APFloat(getIEEE() + RHS.getIEEE(), getSemantics());
+    APFloat Result(*this);
+    (void)Result.add(RHS, rmNearestTiesToEven);
+    return Result;
   }
 
+  /// \brief Operator- overload which provides the default
+  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
   APFloat operator-(const APFloat &RHS) const {
-    return APFloat(getIEEE() - RHS.getIEEE(), getSemantics());
+    APFloat Result(*this);
+    (void)Result.subtract(RHS, rmNearestTiesToEven);
+    return Result;
   }
 
+  /// \brief Operator* overload which provides the default
+  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
   APFloat operator*(const APFloat &RHS) const {
-    return APFloat(getIEEE() * RHS.getIEEE(), getSemantics());
+    APFloat Result(*this);
+    (void)Result.multiply(RHS, rmNearestTiesToEven);
+    return Result;
   }
 
+  /// \brief Operator/ overload which provides the default
+  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
   APFloat operator/(const APFloat &RHS) const {
-    return APFloat(getIEEE() / RHS.getIEEE(), getSemantics());
+    APFloat Result(*this);
+    (void)Result.divide(RHS, rmNearestTiesToEven);
+    return Result;
   }
 
-  void changeSign() { getIEEE().changeSign(); }
-  void clearSign() { getIEEE().clearSign(); }
-  void copySign(const APFloat &RHS) { getIEEE().copySign(RHS.getIEEE()); }
+  void changeSign() {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.changeSign();
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.changeSign();
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
+  void clearSign() {
+    if (isNegative())
+      changeSign();
+  }
+  void copySign(const APFloat &RHS) {
+    if (isNegative() != RHS.isNegative())
+      changeSign();
+  }
 
+  /// \brief A static helper to produce a copy of an APFloat value with its sign
+  /// copied from some other APFloat.
   static APFloat copySign(APFloat Value, const APFloat &Sign) {
-    return APFloat(IEEEFloat::copySign(Value.getIEEE(), Sign.getIEEE()),
-                   Value.getSemantics());
+    Value.copySign(Sign);
+    return Value;
   }
 
   opStatus convert(const fltSemantics &ToSemantics, roundingMode RM,
                    bool *losesInfo);
   opStatus convertToInteger(integerPart *Input, unsigned int Width,
                             bool IsSigned, roundingMode RM,
                             bool *IsExact) const {
-    return getIEEE().convertToInteger(Input, Width, IsSigned, RM, IsExact);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.convertToInteger(Input, Width, IsSigned, RM, IsExact);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.convertToInteger(Input, Width, IsSigned, RM, IsExact);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
   opStatus convertToInteger(APSInt &Result, roundingMode RM,
-                            bool *IsExact) const {
-    return getIEEE().convertToInteger(Result, RM, IsExact);
-  }
+                            bool *IsExact) const;
   opStatus convertFromAPInt(const APInt &Input, bool IsSigned,
                             roundingMode RM) {
-    return getIEEE().convertFromAPInt(Input, IsSigned, RM);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.convertFromAPInt(Input, IsSigned, RM);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.convertFromAPInt(Input, IsSigned, RM);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
   opStatus convertFromSignExtendedInteger(const integerPart *Input,
                                           unsigned int InputSize, bool IsSigned,
                                           roundingMode RM) {
-    return getIEEE().convertFromSignExtendedInteger(Input, InputSize, IsSigned,
-                                                    RM);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.convertFromSignExtendedInteger(Input, InputSize, IsSigned,
+                                                   RM);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.convertFromSignExtendedInteger(Input, InputSize, IsSigned,
+                                                     RM);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
   opStatus convertFromZeroExtendedInteger(const integerPart *Input,
                                           unsigned int InputSize, bool IsSigned,
                                           roundingMode RM) {
-    return getIEEE().convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
-                                                    RM);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
+                                                   RM);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
+                                                     RM);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
   opStatus convertFromString(StringRef, roundingMode);
-  APInt bitcastToAPInt() const { return getIEEE().bitcastToAPInt(); }
+  APInt bitcastToAPInt() const {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.bitcastToAPInt();
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.bitcastToAPInt();
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
   double convertToDouble() const { return getIEEE().convertToDouble(); }
   float convertToFloat() const { return getIEEE().convertToFloat(); }
 
   bool operator==(const APFloat &) const = delete;
 
   cmpResult compare(const APFloat &RHS) const {
-    return getIEEE().compare(RHS.getIEEE());
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only compare APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.compare(RHS.U.IEEE);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.compare(RHS.U.Double);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
 
   bool bitwiseIsEqual(const APFloat &RHS) const {
-    return getIEEE().bitwiseIsEqual(RHS.getIEEE());
+    if (&getSemantics() != &RHS.getSemantics())
+      return false;
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.bitwiseIsEqual(RHS.U.IEEE);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.bitwiseIsEqual(RHS.U.Double);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
 
   unsigned int convertToHexString(char *DST, unsigned int HexDigits,
                                   bool UpperCase, roundingMode RM) const {
-    return getIEEE().convertToHexString(DST, HexDigits, UpperCase, RM);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.convertToHexString(DST, HexDigits, UpperCase, RM);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.convertToHexString(DST, HexDigits, UpperCase, RM);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
 
   bool isZero() const { return getCategory() == fcZero; }
   bool isInfinity() const { return getCategory() == fcInfinity; }
   bool isNaN() const { return getCategory() == fcNaN; }
 
   bool isNegative() const { return getIEEE().isNegative(); }
-  bool isDenormal() const { return getIEEE().isDenormal(); }
+  bool isDenormal() const {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.isDenormal();
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.isDenormal();
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
   bool isSignaling() const { return getIEEE().isSignaling(); }
 
   bool isNormal() const { return !isDenormal() && isFiniteNonZero(); }
@@ -1051,30 +1248,59 @@
   bool isFiniteNonZero() const { return isFinite() && !isZero(); }
   bool isPosZero() const { return isZero() && !isNegative(); }
   bool isNegZero() const { return isZero() && isNegative(); }
-  bool isSmallest() const { return getIEEE().isSmallest(); }
-  bool isLargest() const { return getIEEE().isLargest(); }
-  bool isInteger() const { return getIEEE().isInteger(); }
+  bool isSmallest() const {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.isSmallest();
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.isSmallest();
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
+  bool isLargest() const {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.isLargest();
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.isLargest();
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
+  bool isInteger() const {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.isInteger();
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.isInteger();
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
 
   APFloat &operator=(const APFloat &RHS) = default;
   APFloat &operator=(APFloat &&RHS) = default;
 
   void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0,
                 unsigned FormatMaxPadding = 3) const {
-    return getIEEE().toString(Str, FormatPrecision, FormatMaxPadding);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.toString(Str, FormatPrecision, FormatMaxPadding);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.toString(Str, FormatPrecision, FormatMaxPadding);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
 
   void print(raw_ostream &) const;
   void dump() const;
 
   bool getExactInverse(APFloat *inv) const {
-    return getIEEE().getExactInverse(inv ? &inv->getIEEE() : nullptr);
-  }
-
-  // This is for internal test only.
-  // TODO: Remove it after the PPCDoubleDouble transition.
-  const APFloat &getSecondFloat() const {
-    assert(&getSemantics() == &PPCDoubleDouble());
-    return U.Double.getSecond();
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.getExactInverse(inv);
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.getExactInverse(inv);
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
   }
 
   friend hash_code hash_value(const APFloat &Arg);
@@ -1091,15 +1317,27 @@
 /// xlC compiler.
 hash_code hash_value(const APFloat &Arg);
 inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) {
-  return APFloat(scalbn(X.getIEEE(), Exp, RM), X.getSemantics());
+  if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics())) {
+    return APFloat(scalbn(X.U.IEEE, Exp, RM), X.getSemantics());
+  } else if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics())) {
+    return APFloat(scalbn(X.U.Double, Exp, RM), X.getSemantics());
+  } else {
+    llvm_unreachable("Unexpected semantics");
+  }
 }
 
 /// \brief Equivalent of C standard library function.
 ///
 /// While the C standard says Exp is an unspecified value for infinity and nan,
 /// this returns INT_MAX for infinities, and INT_MIN for NaNs.
 inline APFloat frexp(const APFloat &X, int &Exp, APFloat::roundingMode RM) {
-  return APFloat(frexp(X.getIEEE(), Exp, RM), X.getSemantics());
+  if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics())) {
+    return APFloat(frexp(X.U.IEEE, Exp, RM), X.getSemantics());
+  } else if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics())) {
+    return APFloat(frexp(X.U.Double, Exp, RM), X.getSemantics());
+  } else {
+    llvm_unreachable("Unexpected semantics");
+  }
 }
 /// \brief Returns the absolute value of the argument.
 inline APFloat abs(APFloat X) {
Index: clang/test/CodeGen/ppc64-complex-parms.c
===================================================================
--- clang/test/CodeGen/ppc64-complex-parms.c
+++ clang/test/CodeGen/ppc64-complex-parms.c
@@ -93,7 +93,7 @@
 // CHECK: %[[VAR22:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0
 // CHECK: %[[VAR23:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1
 // CHECK: store ppc_fp128 0xM40000000000000000000000000000000, ppc_fp128* %[[VAR22]]
-// CHECK: store ppc_fp128 0xMC0040000000000000000000000000000, ppc_fp128* %[[VAR23]]
+// CHECK: store ppc_fp128 0xMC0040000000000008000000000000000, ppc_fp128* %[[VAR23]]
 // CHECK: %[[VAR24:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0
 // CHECK: %[[VAR25:[A-Za-z0-9.]+]] = load ppc_fp128, ppc_fp128* %[[VAR24]], align 16
 // CHECK: %[[VAR26:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to