[LLVMdev] Soft floating point support

Neil Booth neil at daikokuya.co.uk
Sat Aug 18 00:33:52 PDT 2007


Neil Booth wrote:-

> This patch supplies software IEEE floating point support.

Ahem.
-------------- next part --------------
Index: include/llvm/ADT/APInt.h
===================================================================
--- include/llvm/ADT/APInt.h	(revision 41166)
+++ include/llvm/ADT/APInt.h	(working copy)
@@ -19,9 +19,7 @@
 #include <cassert>
 #include <string>
 
-#define HOST_CHAR_BIT 8
-#define compileTimeAssert(cond) extern int CTAssert[(cond) ? 1 : -1]
-#define integerPartWidth (HOST_CHAR_BIT * sizeof(llvm::integerPart))
+#define COMPILE_TIME_ASSERT(cond) extern int CTAssert[(cond) ? 1 : -1]
 
 namespace llvm {
 
@@ -29,6 +27,9 @@
      bignum.  */
   typedef uint64_t integerPart;
 
+  const unsigned int host_char_bit = 8;
+  const unsigned int integerPartWidth = host_char_bit * sizeof(integerPart);
+
 //===----------------------------------------------------------------------===//
 //                              APInt Class
 //===----------------------------------------------------------------------===//
Index: include/llvm/ADT/APFloat.h
===================================================================
--- include/llvm/ADT/APFloat.h	(revision 0)
+++ include/llvm/ADT/APFloat.h	(revision 0)
@@ -0,0 +1,258 @@
+//== llvm/Support/APFloat.h - Arbitrary Precision Floating Point -*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Neil Booth and is distributed under the
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares a class to represent arbitrary precision floating
+// point values and provide a variety of arithmetic operations on them.
+//
+//===----------------------------------------------------------------------===//
+
+/*  A self-contained host- and target-independent arbitrary-precision
+    floating-point software implementation using bignum integer
+    arithmetic, as provided by static functions in the APInt class.
+    The library will work with bignum integers whose parts are any
+    unsigned type at least 16 bits wide.  64 bits is recommended.
+
+    Written for clarity rather than speed, in particular with a view
+    to use in the front-end of a cross compiler so that target
+    arithmetic can be correctly performed on the host.  Performance
+    should nonetheless be reasonable, particularly for its intended
+    use.  It may be useful as a base implementation for a run-time
+    library during development of a faster target-specific one.
+
+    All 5 rounding modes in the IEEE-754R draft are handled correctly
+    for all implemented operations.  Currently implemented operations
+    are add, subtract, multiply, divide, fused-multiply-add,
+    conversion-to-float, conversion-to-integer and
+    conversion-from-integer.  New rounding modes (e.g. away from zero)
+    can be added with three or four lines of code.  The library reads
+    and correctly rounds hexadecimal floating point numbers as per
+    C99; syntax is required to have been validated by the caller.
+    Conversion from decimal is not currently implemented.
+
+    Four formats are built-in: IEEE single precision, double
+    precision, quadruple precision, and x87 80-bit extended double
+    (when operating with full extended precision).  Adding a new
+    format that obeys IEEE semantics only requires adding two lines of
+    code: a declaration and definition of the format.
+
+    All operations return the status of that operation as an exception
+    bit-mask, so multiple operations can be done consecutively with
+    their results or-ed together.  The returned status can be useful
+    for compiler diagnostics; e.g., inexact, underflow and overflow
+    can be easily diagnosed on constant folding, and compiler
+    optimizers can determine what exceptions would be raised by
+    folding operations and optimize, or perhaps not optimize,
+    accordingly.
+
+    At present, underflow tininess is detected after rounding; it
+    should be straight forward to add support for the before-rounding
+    case too.
+
+    Non-zero finite numbers are represented internally as a sign bit,
+    a 16-bit signed exponent, and the significand as an array of
+    integer parts.  After normalization of a number of precision P the
+    exponent is within the range of the format, and if the number is
+    not denormal the P-th bit of the significand is set as an explicit
+    integer bit.  For denormals the most significant bit is shifted
+    right so that the exponent is maintained at the format's minimum,
+    so that the smallest denormal has just the least significant bit
+    of the significand set.  The sign of zeroes and infinities is
+    significant; the exponent and significand of such numbers is
+    indeterminate and meaningless.  For QNaNs the sign bit, as well as
+    the exponent and significand are indeterminate and meaningless.
+
+    TODO
+    ====
+
+    Some features that may or may not be worth adding:
+
+    Conversions to and from decimal strings (hard).
+
+    Conversions to hexadecimal string.
+
+    Read and write IEEE-format in-memory representations.
+
+    Optional ability to detect underflow tininess before rounding.
+
+    New formats: x87 in single and double precision mode (IEEE apart
+    from extended exponent range) and IBM two-double extended
+    precision (hard).
+
+    New operations: sqrt, copysign, nextafter, nexttoward.
+*/
+
+#ifndef LLVM_FLOAT_H
+#define LLVM_FLOAT_H
+
+// APInt contains static functions implementing bignum arithmetic.
+#include "llvm/ADT/APInt.h"
+
+namespace llvm {
+
+  /* Exponents are stored as signed numbers.  */
+  typedef signed short exponent_t;
+
+  struct fltSemantics;
+
+  /* When bits of a floating point number are truncated, this enum is
+     used to indicate what fraction of the LSB those bits represented.
+     It essentially combines the roles of guard and sticky bits.  */
+  enum lostFraction {		// Example of truncated bits:
+    lfExactlyZero,		// 000000
+    lfLessThanHalf,		// 0xxxxx  x's not all zero
+    lfExactlyHalf,		// 100000
+    lfMoreThanHalf		// 1xxxxx  x's not all zero
+  };
+
+  class APFloat {
+  public:
+
+    /* We support the following floating point semantics.  */
+    static const fltSemantics IEEEsingle;
+    static const fltSemantics IEEEdouble;
+    static const fltSemantics IEEEquad;
+    static const fltSemantics x87DoubleExtended;
+
+    static unsigned int semanticsPrecision(const fltSemantics &);
+
+    /* Floating point numbers have a four-state comparison relation.  */
+    enum cmpResult {
+      cmpLessThan,
+      cmpEqual,
+      cmpGreaterThan,
+      cmpUnordered
+    };
+
+    /* IEEE-754R gives five rounding modes.  */
+    enum roundingMode {
+      rmNearestTiesToEven,
+      rmTowardPositive,
+      rmTowardNegative,
+      rmTowardZero,
+      rmNearestTiesToAway
+    };
+
+    /* Operation status.  opUnderflow or opOverflow are always returned
+       or-ed with opInexact.  */
+    enum opStatus {
+      opOK          = 0x00,
+      opInvalidOp   = 0x01,
+      opDivByZero   = 0x02,
+      opOverflow    = 0x04,
+      opUnderflow   = 0x08,
+      opInexact     = 0x10
+    };
+
+    /* Category of internally-represented number.  */
+    enum fltCategory {
+      fcInfinity,
+      fcQNaN,
+      fcNormal,
+      fcZero
+    };
+
+    /* Constructors.  */
+    APFloat(const fltSemantics &, const char *);
+    APFloat(const fltSemantics &, integerPart);
+    APFloat(const fltSemantics &, fltCategory, bool negative);
+    APFloat(const APFloat &);
+    ~APFloat();
+
+    /* Arithmetic.  */
+    opStatus add(const APFloat &, roundingMode);
+    opStatus subtract(const APFloat &, roundingMode);
+    opStatus multiply(const APFloat &, roundingMode);
+    opStatus divide(const APFloat &, roundingMode);
+    opStatus fusedMultiplyAdd(const APFloat &, const APFloat &, roundingMode);
+    void changeSign();
+
+    /* Conversions.  */
+    opStatus convert(const fltSemantics &, roundingMode);
+    opStatus convertToInteger(integerPart *, unsigned int, bool,
+			      roundingMode) const;
+    opStatus convertFromInteger(const integerPart *, unsigned int, bool,
+				roundingMode);
+    opStatus convertFromString(const char *, roundingMode);
+
+    /* Comparison with another floating point number.  */
+    cmpResult compare(const APFloat &) const;
+
+    /* Simple queries.  */
+    fltCategory getCategory() const { return category; }
+    const fltSemantics &getSemantics() const { return *semantics; }
+    bool isZero() const { return category == fcZero; }
+    bool isNonZero() const { return category != fcZero; }
+    bool isNegative() const { return sign; }
+
+    APFloat& operator=(const APFloat &);
+
+  private:
+
+    /* Trivial queries.  */
+    integerPart *significandParts();
+    const integerPart *significandParts() const;
+    unsigned int partCount() const;
+
+    /* Significand operations.  */
+    integerPart addSignificand(const APFloat &);
+    integerPart subtractSignificand(const APFloat &, integerPart);
+    lostFraction addOrSubtractSignificand(const APFloat &, bool subtract);
+    lostFraction multiplySignificand(const APFloat &, const APFloat *);
+    lostFraction divideSignificand(const APFloat &);
+    void incrementSignificand();
+    void initialize(const fltSemantics *);
+    void shiftSignificandLeft(unsigned int);
+    lostFraction shiftSignificandRight(unsigned int);
+    unsigned int significandLSB() const;
+    unsigned int significandMSB() const;
+    void zeroSignificand();
+
+    /* Arithmetic on special values.  */
+    opStatus addOrSubtractSpecials(const APFloat &, bool subtract);
+    opStatus divideSpecials(const APFloat &);
+    opStatus multiplySpecials(const APFloat &);
+
+    /* Miscellany.  */
+    opStatus normalize(roundingMode, lostFraction);
+    opStatus addOrSubtract(const APFloat &, roundingMode, bool subtract);
+    cmpResult compareAbsoluteValue(const APFloat &) const;
+    opStatus handleOverflow(roundingMode);
+    bool roundAwayFromZero(roundingMode, lostFraction);
+    opStatus convertFromUnsignedInteger(integerPart *, unsigned int,
+					roundingMode);
+    lostFraction combineLostFractions(lostFraction, lostFraction);
+    opStatus convertFromHexadecimalString(const char *, roundingMode);
+
+    void assign(const APFloat &);
+    void copySignificand(const APFloat &);
+    void freeSignificand();
+
+    /* What kind of semantics does this value obey?  */
+    const fltSemantics *semantics;
+
+    /* Significand - the fraction with an explicit integer bit.  Must be
+       at least one bit wider than the target precision.  */
+    union Significand
+    {
+      integerPart part;
+      integerPart *parts;
+    } significand;
+
+    /* The exponent - a signed number.  */
+    exponent_t exponent;
+
+    /* What kind of floating point number this is.  */
+    fltCategory category: 2;
+
+    /* The sign bit of this number.  */
+    unsigned int sign: 1;
+  };
+} /* namespace llvm */
+
+#endif /* LLVM_FLOAT_H */
Index: lib/Support/APInt.cpp
===================================================================
--- lib/Support/APInt.cpp	(revision 41166)
+++ lib/Support/APInt.cpp	(working copy)
@@ -2018,19 +2018,39 @@
 
 /* Assumed by lowHalf, highHalf, partMSB and partLSB.  A fairly safe
    and unrestricting assumption.  */
-compileTimeAssert(integerPartWidth % 2 == 0);
+COMPILE_TIME_ASSERT(integerPartWidth % 2 == 0);
 
-#define lowBitMask(bits) (~(integerPart) 0 >> (integerPartWidth - (bits)))
-#define lowHalf(part) ((part) & lowBitMask(integerPartWidth / 2))
-#define highHalf(part) ((part) >> (integerPartWidth / 2))
-
 /* Some handy functions local to this file.  */
 namespace {
 
+  /* Returns the integer part with the least significant BITS set.
+     BITS cannot be zero.  */
+  inline integerPart
+  lowBitMask(unsigned int bits)
+  {
+    assert (bits != 0 && bits <= integerPartWidth);
+
+    return ~(integerPart) 0 >> (integerPartWidth - bits);
+  }
+
+  /* Returns the value of the lower nibble of PART.  */
+  inline integerPart
+  lowHalf(integerPart part)
+  {
+    return part & lowBitMask(integerPartWidth / 2);
+  }
+
+  /* Returns the value of the upper nibble of PART.  */
+  inline integerPart
+  highHalf(integerPart part)
+  {
+    return part >> (integerPartWidth / 2);
+  }
+
   /* Returns the bit number of the most significant bit of a part.  If
      the input number has no bits set -1U is returned.  */
   unsigned int
-  PartMSB(integerPart value)
+  partMSB(integerPart value)
   {
     unsigned int n, msb;
 
@@ -2157,7 +2177,7 @@
       --n;
 
       if (parts[n] != 0) {
-          msb = PartMSB(parts[n]);
+          msb = partMSB(parts[n]);
 
           return msb + n * integerPartWidth;
       }
@@ -2388,11 +2408,11 @@
 
   assert(lhs != remainder && lhs != srhs && remainder != srhs);
 
-  shiftCount = tcMSB(rhs, parts);
-  if (shiftCount == -1U)
+  shiftCount = tcMSB(rhs, parts) + 1;
+  if (shiftCount == 0)
     return true;
 
-  shiftCount = parts * integerPartWidth - shiftCount - 1;
+  shiftCount = parts * integerPartWidth - shiftCount;
   n = shiftCount / integerPartWidth;
   mask = (integerPart) 1 << (shiftCount % integerPartWidth);
 
Index: lib/Support/APFloat.cpp
===================================================================
--- lib/Support/APFloat.cpp	(revision 0)
+++ lib/Support/APFloat.cpp	(revision 0)
@@ -0,0 +1,1488 @@
+//===-- APFloat.cpp - Implement APFloat class -----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Neil Booth and is distributed under the
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a class to represent arbitrary precision floating
+// point values and provide a variety of arithmetic operations on them.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cassert>
+#include "llvm/ADT/APFloat.h"
+
+using namespace llvm;
+
+#define convolve(lhs, rhs) ((lhs) * 4 + (rhs))
+
+/* Assumed in hexadecimal significand parsing.  */
+COMPILE_TIME_ASSERT(integerPartWidth % 4 == 0);
+
+namespace llvm {
+
+  /* Represents floating point arithmetic semantics.  */
+  struct fltSemantics {
+    /* The largest E such that 2^E is representable; this matches the
+       definition of IEEE 754.  */
+    exponent_t maxExponent;
+
+    /* The smallest E such that 2^E is a normalized number; this
+       matches the definition of IEEE 754.  */
+    exponent_t minExponent;
+
+    /* Number of bits in the significand.  This includes the integer
+       bit.  */
+    unsigned char precision;
+
+    /* If the target format has an implicit integer bit.  */
+    bool implicitIntegerBit;
+  };
+
+  const fltSemantics APFloat::IEEEsingle = { 127, -126, 24, true };
+  const fltSemantics APFloat::IEEEdouble = { 1023, -1022, 53, true };
+  const fltSemantics APFloat::IEEEquad = { 16383, -16382, 113, true };
+  const fltSemantics APFloat::x87DoubleExtended = { 16383, -16382, 64, false };
+}
+
+/* Put a bunch of private, handy routines in an anonymous namespace.  */
+namespace {
+
+  inline unsigned int
+  partCountForBits(unsigned int bits)
+  {
+    return ((bits) + integerPartWidth - 1) / integerPartWidth;
+  }
+
+  unsigned int
+  digitValue(unsigned int c)
+  {
+    unsigned int r;
+
+    r = c - '0';
+    if(r <= 9)
+      return r;
+
+    return -1U;
+  }
+
+  unsigned int
+  hexDigitValue (unsigned int c)
+  {
+    unsigned int r;
+
+    r = c - '0';
+    if(r <= 9)
+      return r;
+
+    r = c - 'A';
+    if(r <= 5)
+      return r + 10;
+
+    r = c - 'a';
+    if(r <= 5)
+      return r + 10;
+
+    return -1U;
+  }
+
+  /* This is ugly and needs cleaning up, but I don't immediately see
+     how whilst remaining safe.  */
+  static int
+  totalExponent(const char *p, int exponentAdjustment)
+  {
+    integerPart unsignedExponent;
+    bool negative, overflow;
+    long exponent;
+
+    /* Move past the exponent letter and sign to the digits.  */
+    p++;
+    negative = *p == '-';
+    if(*p == '-' || *p == '+')
+      p++;
+
+    unsignedExponent = 0;
+    overflow = false;
+    for(;;) {
+      unsigned int value;
+
+      value = digitValue(*p);
+      if(value == -1U)
+	break;
+
+      p++;
+      unsignedExponent = unsignedExponent * 10 + value;
+      if(unsignedExponent > 65535)
+	overflow = true;
+    }
+
+    if(exponentAdjustment > 65535 || exponentAdjustment < -65536)
+      overflow = true;
+
+    if(!overflow) {
+      exponent = unsignedExponent;
+      if(negative)
+	exponent = -exponent;
+      exponent += exponentAdjustment;
+      if(exponent > 65535 || exponent < -65536)
+	overflow = true;
+    }
+
+    if(overflow)
+      exponent = negative ? -65536: 65535;
+
+    return exponent;
+  }
+
+  const char *
+  skipLeadingZeroesAndAnyDot(const char *p, const char **dot)
+  {
+    *dot = 0;
+    while(*p == '0')
+      p++;
+
+    if(*p == '.') {
+      *dot = p++;
+      while(*p == '0')
+	p++;
+    }
+
+    return p;
+  }
+
+  /* Return the trailing fraction of a hexadecimal number.
+     DIGITVALUE is the first hex digit of the fraction, P points to
+     the next digit.  */
+  lostFraction
+  trailingHexadecimalFraction(const char *p, unsigned int digitValue)
+  {
+    unsigned int hexDigit;
+
+    /* If the first trailing digit isn't 0 or 8 we can work out the
+       fraction immediately.  */
+    if(digitValue > 8)
+      return lfMoreThanHalf;
+    else if(digitValue < 8 && digitValue > 0)
+      return lfLessThanHalf;
+
+    /* Otherwise we need to find the first non-zero digit.  */
+    while(*p == '0')
+      p++;
+
+    hexDigit = hexDigitValue(*p);
+
+    /* If we ran off the end it is exactly zero or one-half, otherwise
+       a little more.  */
+    if(hexDigit == -1U)
+      return digitValue == 0 ? lfExactlyZero: lfExactlyHalf;
+    else
+      return digitValue == 0 ? lfLessThanHalf: lfMoreThanHalf;
+  }
+
+  /* Return the fraction lost were a bignum truncated.  */
+  lostFraction
+  lostFractionThroughTruncation(integerPart *parts,
+				unsigned int partCount,
+				unsigned int bits)
+  {
+    unsigned int lsb;
+
+    lsb = APInt::tcLSB(parts, partCount);
+
+    /* Note this is guaranteed true if bits == 0, or LSB == -1U.  */
+    if(bits <= lsb)
+      return lfExactlyZero;
+    if(bits == lsb + 1)
+      return lfExactlyHalf;
+    if(bits <= partCount * integerPartWidth
+       && APInt::tcExtractBit(parts, bits - 1))
+      return lfMoreThanHalf;
+
+    return lfLessThanHalf;
+  }
+
+  /* Shift DST right BITS bits noting lost fraction.  */
+  lostFraction
+  shiftRight(integerPart *dst, unsigned int parts, unsigned int bits)
+  {
+    lostFraction lost_fraction;
+
+    lost_fraction = lostFractionThroughTruncation(dst, parts, bits);
+
+    APInt::tcShiftRight(dst, parts, bits);
+
+    return lost_fraction;
+  }
+}
+
+/* Constructors.  */
+void
+APFloat::initialize(const fltSemantics *ourSemantics)
+{
+  unsigned int count;
+
+  semantics = ourSemantics;
+  count = partCount();
+  if(count > 1)
+    significand.parts = new integerPart[count];
+}
+
+void
+APFloat::freeSignificand()
+{
+  if(partCount() > 1)
+    delete [] significand.parts;
+}
+
+void
+APFloat::assign(const APFloat &rhs)
+{
+  assert(semantics == rhs.semantics);
+
+  sign = rhs.sign;
+  category = rhs.category;
+  exponent = rhs.exponent;
+  if(category == fcNormal)
+    copySignificand(rhs);
+}
+
+void
+APFloat::copySignificand(const APFloat &rhs)
+{
+  assert(category == fcNormal);
+  assert(rhs.partCount() >= partCount());
+
+  APInt::tcAssign(significandParts(), rhs.significandParts(),
+		  partCount());
+}
+
+APFloat &
+APFloat::operator=(const APFloat &rhs)
+{
+  if(this != &rhs) {
+    if(semantics != rhs.semantics) {
+      freeSignificand();
+      initialize(rhs.semantics);
+    }
+    assign(rhs);
+  }
+
+  return *this;
+}
+
+APFloat::APFloat(const fltSemantics &ourSemantics, integerPart value)
+{
+  initialize(&ourSemantics);
+  sign = 0;
+  zeroSignificand();
+  exponent = ourSemantics.precision - 1;
+  significandParts()[0] = value;
+  normalize(rmNearestTiesToEven, lfExactlyZero);
+}
+
+APFloat::APFloat(const fltSemantics &ourSemantics,
+		 fltCategory ourCategory, bool negative)
+{
+  initialize(&ourSemantics);
+  category = ourCategory;
+  sign = negative;
+  if(category == fcNormal)
+    category = fcZero;
+}
+
+APFloat::APFloat(const fltSemantics &ourSemantics, const char *text)
+{
+  initialize(&ourSemantics);
+  convertFromString(text, rmNearestTiesToEven);
+}
+
+APFloat::APFloat(const APFloat &rhs)
+{
+  initialize(rhs.semantics);
+  assign(rhs);
+}
+
+APFloat::~APFloat()
+{
+  freeSignificand();
+}
+
+unsigned int
+APFloat::partCount() const
+{
+  return partCountForBits(semantics->precision + 1);
+}
+
+unsigned int
+APFloat::semanticsPrecision(const fltSemantics &semantics)
+{
+  return semantics.precision;
+}
+
+const integerPart *
+APFloat::significandParts() const
+{
+  return const_cast<APFloat *>(this)->significandParts();
+}
+
+integerPart *
+APFloat::significandParts()
+{
+  assert(category == fcNormal);
+
+  if(partCount() > 1)
+    return significand.parts;
+  else
+    return &significand.part;
+}
+
+/* Combine the effect of two lost fractions.  */
+lostFraction
+APFloat::combineLostFractions(lostFraction moreSignificant,
+			      lostFraction lessSignificant)
+{
+  if(lessSignificant != lfExactlyZero) {
+    if(moreSignificant == lfExactlyZero)
+      moreSignificant = lfLessThanHalf;
+    else if(moreSignificant == lfExactlyHalf)
+      moreSignificant = lfMoreThanHalf;
+  }
+
+  return moreSignificant;
+}
+
+void
+APFloat::zeroSignificand()
+{
+  category = fcNormal;
+  APInt::tcSet(significandParts(), 0, partCount());
+}
+
+/* Increment an fcNormal floating point number's significand.  */
+void
+APFloat::incrementSignificand()
+{
+  integerPart carry;
+
+  carry = APInt::tcIncrement(significandParts(), partCount());
+
+  /* Our callers should never cause us to overflow.  */
+  assert(carry == 0);
+}
+
+/* Add the significand of the RHS.  Returns the carry flag.  */
+integerPart
+APFloat::addSignificand(const APFloat &rhs)
+{
+  integerPart *parts;
+
+  parts = significandParts();
+
+  assert(semantics == rhs.semantics);
+  assert(exponent == rhs.exponent);
+
+  return APInt::tcAdd(parts, rhs.significandParts(), 0, partCount());
+}
+
+/* Subtract the significand of the RHS with a borrow flag.  Returns
+   the borrow flag.  */
+integerPart
+APFloat::subtractSignificand(const APFloat &rhs, integerPart borrow)
+{
+  integerPart *parts;
+
+  parts = significandParts();
+
+  assert(semantics == rhs.semantics);
+  assert(exponent == rhs.exponent);
+
+  return APInt::tcSubtract(parts, rhs.significandParts(), borrow,
+			   partCount());
+}
+
+/* Multiply the significand of the RHS.  If ADDEND is non-NULL, add it
+   on to the full-precision result of the multiplication.  Returns the
+   lost fraction.  */
+lostFraction
+APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend)
+{
+  unsigned int omsb;	// One, not zero, based MSB.
+  unsigned int partsCount, newPartsCount, precision;
+  integerPart *lhsSignificand;
+  integerPart scratch[4];
+  integerPart *fullSignificand;
+  lostFraction lost_fraction;
+
+  assert(semantics == rhs.semantics);
+
+  precision = semantics->precision;
+  newPartsCount = partCountForBits(precision * 2);
+
+  if(newPartsCount > 4)
+    fullSignificand = new integerPart[newPartsCount];
+  else
+    fullSignificand = scratch;
+
+  lhsSignificand = significandParts();
+  partsCount = partCount();
+
+  APInt::tcFullMultiply(fullSignificand, lhsSignificand,
+			rhs.significandParts(), partsCount);
+
+  lost_fraction = lfExactlyZero;
+  omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1;
+  exponent += rhs.exponent;
+
+  if(addend) {
+    Significand savedSignificand = significand;
+    const fltSemantics *savedSemantics = semantics;
+    fltSemantics extendedSemantics;
+    opStatus status;
+    unsigned int extendedPrecision;
+
+    /* Normalize our MSB.  */
+    extendedPrecision = precision + precision - 1;
+    if(omsb != extendedPrecision)
+      {
+	APInt::tcShiftLeft(fullSignificand, newPartsCount,
+			   extendedPrecision - omsb);
+	exponent -= extendedPrecision - omsb;
+      }
+
+    /* Create new semantics.  */
+    extendedSemantics = *semantics;
+    extendedSemantics.precision = extendedPrecision;
+
+    if(newPartsCount == 1)
+      significand.part = fullSignificand[0];
+    else
+      significand.parts = fullSignificand;
+    semantics = &extendedSemantics;
+
+    APFloat extendedAddend(*addend);
+    status = extendedAddend.convert(extendedSemantics, rmTowardZero);
+    assert(status == opOK);
+    lost_fraction = addOrSubtractSignificand(extendedAddend, false);
+
+    /* Restore our state.  */
+    if(newPartsCount == 1)
+      fullSignificand[0] = significand.part;
+    significand = savedSignificand;
+    semantics = savedSemantics;
+
+    omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1;
+  }
+
+  exponent -= (precision - 1);
+
+  if(omsb > precision) {
+    unsigned int bits, significantParts;
+    lostFraction lf;
+
+    bits = omsb - precision;
+    significantParts = partCountForBits(omsb);
+    lf = shiftRight(fullSignificand, significantParts, bits);
+    lost_fraction = combineLostFractions(lf, lost_fraction);
+    exponent += bits;
+  }
+
+  APInt::tcAssign(lhsSignificand, fullSignificand, partsCount);
+
+  if(newPartsCount > 4)
+    delete [] fullSignificand;
+
+  return lost_fraction;
+}
+
+/* Multiply the significands of LHS and RHS to DST.  */
+lostFraction
+APFloat::divideSignificand(const APFloat &rhs)
+{
+  unsigned int bit, i, partsCount;
+  const integerPart *rhsSignificand;
+  integerPart *lhsSignificand, *dividend, *divisor;
+  integerPart scratch[4];
+  lostFraction lost_fraction;
+
+  assert(semantics == rhs.semantics);
+
+  lhsSignificand = significandParts();
+  rhsSignificand = rhs.significandParts();
+  partsCount = partCount();
+
+  if(partsCount > 2)
+    dividend = new integerPart[partsCount * 2];
+  else
+    dividend = scratch;
+
+  divisor = dividend + partsCount;
+
+  /* Copy the dividend and divisor as they will be modified in-place.  */
+  for(i = 0; i < partsCount; i++) {
+    dividend[i] = lhsSignificand[i];
+    divisor[i] = rhsSignificand[i];
+    lhsSignificand[i] = 0;
+  }
+
+  exponent -= rhs.exponent;
+
+  unsigned int precision = semantics->precision;
+
+  /* Normalize the divisor.  */
+  bit = precision - APInt::tcMSB(divisor, partsCount) - 1;
+  if(bit) {
+    exponent += bit;
+    APInt::tcShiftLeft(divisor, partsCount, bit);
+  }
+
+  /* Normalize the dividend.  */
+  bit = precision - APInt::tcMSB(dividend, partsCount) - 1;
+  if(bit) {
+    exponent -= bit;
+    APInt::tcShiftLeft(dividend, partsCount, bit);
+  }
+
+  if(APInt::tcCompare(dividend, divisor, partsCount) < 0) {
+    exponent--;
+    APInt::tcShiftLeft(dividend, partsCount, 1);
+    assert(APInt::tcCompare(dividend, divisor, partsCount) >= 0);
+  }
+
+  /* Long division.  */
+  for(bit = precision; bit; bit -= 1) {
+    if(APInt::tcCompare(dividend, divisor, partsCount) >= 0) {
+      APInt::tcSubtract(dividend, divisor, 0, partsCount);
+      APInt::tcSetBit(lhsSignificand, bit - 1);
+    }
+
+    APInt::tcShiftLeft(dividend, partsCount, 1);
+  }
+
+  /* Figure out the lost fraction.  */
+  int cmp = APInt::tcCompare(dividend, divisor, partsCount);
+
+  if(cmp > 0)
+    lost_fraction = lfMoreThanHalf;
+  else if(cmp == 0)
+    lost_fraction = lfExactlyHalf;
+  else if(APInt::tcIsZero(dividend, partsCount))
+    lost_fraction = lfExactlyZero;
+  else
+    lost_fraction = lfLessThanHalf;
+
+  if(partsCount > 2)
+    delete [] dividend;
+
+  return lost_fraction;
+}
+
+unsigned int
+APFloat::significandMSB() const
+{
+  return APInt::tcMSB(significandParts(), partCount());
+}
+
+unsigned int
+APFloat::significandLSB() const
+{
+  return APInt::tcLSB(significandParts(), partCount());
+}
+
+/* Note that a zero result is NOT normalized to fcZero.  */
+lostFraction
+APFloat::shiftSignificandRight(unsigned int bits)
+{
+  /* Our exponent should not overflow.  */
+  assert((exponent_t) (exponent + bits) >= exponent);
+
+  exponent += bits;
+
+  return shiftRight(significandParts(), partCount(), bits);
+}
+
+/* Shift the significand left BITS bits, subtract BITS from its exponent.  */
+void
+APFloat::shiftSignificandLeft(unsigned int bits)
+{
+  assert(bits < semantics->precision);
+
+  if(bits) {
+    unsigned int partsCount = partCount();
+
+    APInt::tcShiftLeft(significandParts(), partsCount, bits);
+    exponent -= bits;
+
+    assert(!APInt::tcIsZero(significandParts(), partsCount));
+  }
+}
+
+APFloat::cmpResult
+APFloat::compareAbsoluteValue(const APFloat &rhs) const
+{
+  int compare;
+
+  assert(semantics == rhs.semantics);
+  assert(category == fcNormal);
+  assert(rhs.category == fcNormal);
+
+  compare = exponent - rhs.exponent;
+
+  /* If exponents are equal, do an unsigned bignum comparison of the
+     significands.  */
+  if(compare == 0)
+    compare = APInt::tcCompare(significandParts(), rhs.significandParts(),
+			       partCount());
+
+  if(compare > 0)
+    return cmpGreaterThan;
+  else if(compare < 0)
+    return cmpLessThan;
+  else
+    return cmpEqual;
+}
+
+/* Handle overflow.  Sign is preserved.  We either become infinity or
+   the largest finite number.  */
+APFloat::opStatus
+APFloat::handleOverflow(roundingMode rounding_mode)
+{
+  /* Infinity?  */
+  if(rounding_mode == rmNearestTiesToEven
+     || rounding_mode == rmNearestTiesToAway
+     || (rounding_mode == rmTowardPositive && !sign)
+     || (rounding_mode == rmTowardNegative && sign))
+    {
+      category = fcInfinity;
+      return (opStatus) (opOverflow | opInexact);
+    }
+
+  /* Otherwise we become the largest finite number.  */
+  category = fcNormal;
+  exponent = semantics->maxExponent;
+  APInt::tcSetLeastSignificantBits(significandParts(), partCount(),
+				   semantics->precision);
+
+  return opInexact;
+}
+
+/* This routine must work for fcZero of both signs, and fcNormal
+   numbers.  */
+bool
+APFloat::roundAwayFromZero(roundingMode rounding_mode,
+			   lostFraction lost_fraction)
+{
+  /* QNaNs and infinities should not have lost fractions.  */
+  assert(category == fcNormal || category == fcZero);
+
+  /* Our caller has already handled this case.  */
+  assert(lost_fraction != lfExactlyZero);
+
+  switch(rounding_mode) {
+  default:
+    assert(0);
+
+  case rmNearestTiesToAway:
+    return lost_fraction == lfExactlyHalf || lost_fraction == lfMoreThanHalf;
+
+  case rmNearestTiesToEven:
+    if(lost_fraction == lfMoreThanHalf)
+      return true;
+
+    /* Our zeroes don't have a significand to test.  */
+    if(lost_fraction == lfExactlyHalf && category != fcZero)
+      return significandParts()[0] & 1;
+
+    return false;
+
+  case rmTowardZero:
+    return false;
+
+  case rmTowardPositive:
+    return sign == false;
+
+  case rmTowardNegative:
+    return sign == true;
+  }
+}
+
+APFloat::opStatus
+APFloat::normalize(roundingMode rounding_mode,
+		   lostFraction lost_fraction)
+{
+  unsigned int omsb;		/* One, not zero, based MSB.  */
+  int exponentChange;
+
+  if(category != fcNormal)
+    return opOK;
+
+  /* Before rounding normalize the exponent of fcNormal numbers.  */
+  omsb = significandMSB() + 1;
+
+  if(omsb) {
+    /* OMSB is numbered from 1.  We want to place it in the integer
+       bit numbered PRECISON if possible, with a compensating change in
+       the exponent.  */
+    exponentChange = omsb - semantics->precision;
+
+    /* If the resulting exponent is too high, overflow according to
+       the rounding mode.  */
+    if(exponent + exponentChange > semantics->maxExponent)
+      return handleOverflow(rounding_mode);
+
+    /* Subnormal numbers have exponent minExponent, and their MSB
+       is forced based on that.  */
+    if(exponent + exponentChange < semantics->minExponent)
+      exponentChange = semantics->minExponent - exponent;
+
+    /* Shifting left is easy as we don't lose precision.  */
+    if(exponentChange < 0) {
+      assert(lost_fraction == lfExactlyZero);
+
+      shiftSignificandLeft(-exponentChange);
+
+      return opOK;
+    }
+
+    if(exponentChange > 0) {
+      lostFraction lf;
+
+      /* Shift right and capture any new lost fraction.  */
+      lf = shiftSignificandRight(exponentChange);
+
+      lost_fraction = combineLostFractions(lf, lost_fraction);
+
+      /* Keep OMSB up-to-date.  */
+      if(omsb > (unsigned) exponentChange)
+	omsb -= (unsigned) exponentChange;
+      else
+	omsb = 0;
+    }
+  }
+
+  /* Now round the number according to rounding_mode given the lost
+     fraction.  */
+
+  /* As specified in IEEE 754, since we do not trap we do not report
+     underflow for exact results.  */
+  if(lost_fraction == lfExactlyZero) {
+    /* Canonicalize zeroes.  */
+    if(omsb == 0)
+      category = fcZero;
+
+    return opOK;
+  }
+
+  /* Increment the significand if we're rounding away from zero.  */
+  if(roundAwayFromZero(rounding_mode, lost_fraction)) {
+    if(omsb == 0)
+      exponent = semantics->minExponent;
+
+    incrementSignificand();
+    omsb = significandMSB() + 1;
+
+    /* Did the significand increment overflow?  */
+    if(omsb == (unsigned) semantics->precision + 1) {
+      /* Renormalize by incrementing the exponent and shifting our
+	 significand right one.  However if we already have the
+	 maximum exponent we overflow to infinity.  */
+      if(exponent == semantics->maxExponent) {
+	category = fcInfinity;
+
+	return (opStatus) (opOverflow | opInexact);
+      }
+
+      shiftSignificandRight(1);
+
+      return opInexact;
+    }
+  }
+
+  /* The normal case - we were and are not denormal, and any
+     significand increment above didn't overflow.  */
+  if(omsb == semantics->precision)
+    return opInexact;
+
+  /* We have a non-zero denormal.  */
+  assert(omsb < semantics->precision);
+  assert(exponent == semantics->minExponent);
+
+  /* Canonicalize zeroes.  */
+  if(omsb == 0)
+    category = fcZero;
+
+  /* The fcZero case is a denormal that underflowed to zero.  */
+  return (opStatus) (opUnderflow | opInexact);
+}
+
+APFloat::opStatus
+APFloat::addOrSubtractSpecials(const APFloat &rhs, bool subtract)
+{
+  switch(convolve(category, rhs.category)) {
+  default:
+    assert(0);
+
+  case convolve(fcQNaN, fcZero):
+  case convolve(fcQNaN, fcNormal):
+  case convolve(fcQNaN, fcInfinity):
+  case convolve(fcQNaN, fcQNaN):
+  case convolve(fcNormal, fcZero):
+  case convolve(fcInfinity, fcNormal):
+  case convolve(fcInfinity, fcZero):
+    return opOK;
+
+  case convolve(fcZero, fcQNaN):
+  case convolve(fcNormal, fcQNaN):
+  case convolve(fcInfinity, fcQNaN):
+    category = fcQNaN;
+    return opOK;
+
+  case convolve(fcNormal, fcInfinity):
+  case convolve(fcZero, fcInfinity):
+    category = fcInfinity;
+    sign = rhs.sign ^ subtract;
+    return opOK;
+
+  case convolve(fcZero, fcNormal):
+    assign(rhs);
+    sign = rhs.sign ^ subtract;
+    return opOK;
+
+  case convolve(fcZero, fcZero):
+    /* Sign depends on rounding mode; handled by caller.  */
+    return opOK;
+
+  case convolve(fcInfinity, fcInfinity):
+    /* Differently signed infinities can only be validly
+       subtracted.  */
+    if(sign ^ rhs.sign != subtract) {
+      category = fcQNaN;
+      return opInvalidOp;
+    }
+
+    return opOK;
+
+  case convolve(fcNormal, fcNormal):
+    return opDivByZero;
+  }
+}
+
+/* Add or subtract two normal numbers.  */
+lostFraction
+APFloat::addOrSubtractSignificand(const APFloat &rhs, bool subtract)
+{
+  integerPart carry;
+  lostFraction lost_fraction;
+  int bits;
+
+  /* Determine if the operation on the absolute values is effectively
+     an addition or subtraction.  */
+  subtract ^= (sign ^ rhs.sign);
+
+  /* Are we bigger exponent-wise than the RHS?  */
+  bits = exponent - rhs.exponent;
+
+  /* Subtraction is more subtle than one might naively expect.  */
+  if(subtract) {
+    APFloat temp_rhs(rhs);
+    bool reverse;
+
+    if(bits == 0) {
+      reverse = compareAbsoluteValue(temp_rhs) == cmpLessThan;
+      lost_fraction = lfExactlyZero;
+    } else if(bits > 0) {
+      lost_fraction = temp_rhs.shiftSignificandRight(bits - 1);
+      shiftSignificandLeft(1);
+      reverse = false;
+    } else if(bits < 0) {
+      lost_fraction = shiftSignificandRight(-bits - 1);
+      temp_rhs.shiftSignificandLeft(1);
+      reverse = true;
+    }
+
+    if(reverse) {
+      carry = temp_rhs.subtractSignificand
+	(*this, lost_fraction != lfExactlyZero);
+      copySignificand(temp_rhs);
+      sign = !sign;
+    } else {
+      carry = subtractSignificand
+	(temp_rhs, lost_fraction != lfExactlyZero);
+    }
+
+    /* Invert the lost fraction - it was on the RHS and
+       subtracted.  */
+    if(lost_fraction == lfLessThanHalf)
+      lost_fraction = lfMoreThanHalf;
+    else if(lost_fraction == lfMoreThanHalf)
+      lost_fraction = lfLessThanHalf;
+
+    /* The code above is intended to ensure that no borrow is
+       necessary.  */
+    assert(!carry);
+  } else {
+    if(bits > 0) {
+      APFloat temp_rhs(rhs);
+
+      lost_fraction = temp_rhs.shiftSignificandRight(bits);
+      carry = addSignificand(temp_rhs);
+    } else {
+      lost_fraction = shiftSignificandRight(-bits);
+      carry = addSignificand(rhs);
+    }
+
+    /* We have a guard bit; generating a carry cannot happen.  */
+    assert(!carry);
+  }
+
+  return lost_fraction;
+}
+
+APFloat::opStatus
+APFloat::multiplySpecials(const APFloat &rhs)
+{
+  switch(convolve(category, rhs.category)) {
+  default:
+    assert(0);
+
+  case convolve(fcQNaN, fcZero):
+  case convolve(fcQNaN, fcNormal):
+  case convolve(fcQNaN, fcInfinity):
+  case convolve(fcQNaN, fcQNaN):
+  case convolve(fcZero, fcQNaN):
+  case convolve(fcNormal, fcQNaN):
+  case convolve(fcInfinity, fcQNaN):
+    category = fcQNaN;
+    return opOK;
+
+  case convolve(fcNormal, fcInfinity):
+  case convolve(fcInfinity, fcNormal):
+  case convolve(fcInfinity, fcInfinity):
+    category = fcInfinity;
+    return opOK;
+
+  case convolve(fcZero, fcNormal):
+  case convolve(fcNormal, fcZero):
+  case convolve(fcZero, fcZero):
+    category = fcZero;
+    return opOK;
+
+  case convolve(fcZero, fcInfinity):
+  case convolve(fcInfinity, fcZero):
+    category = fcQNaN;
+    return opInvalidOp;
+
+  case convolve(fcNormal, fcNormal):
+    return opOK;
+  }
+}
+
+APFloat::opStatus
+APFloat::divideSpecials(const APFloat &rhs)
+{
+  switch(convolve(category, rhs.category)) {
+  default:
+    assert(0);
+
+  case convolve(fcQNaN, fcZero):
+  case convolve(fcQNaN, fcNormal):
+  case convolve(fcQNaN, fcInfinity):
+  case convolve(fcQNaN, fcQNaN):
+  case convolve(fcInfinity, fcZero):
+  case convolve(fcInfinity, fcNormal):
+  case convolve(fcZero, fcInfinity):
+  case convolve(fcZero, fcNormal):
+    return opOK;
+
+  case convolve(fcZero, fcQNaN):
+  case convolve(fcNormal, fcQNaN):
+  case convolve(fcInfinity, fcQNaN):
+    category = fcQNaN;
+    return opOK;
+
+  case convolve(fcNormal, fcInfinity):
+    category = fcZero;
+    return opOK;
+
+  case convolve(fcNormal, fcZero):
+    category = fcInfinity;
+    return opDivByZero;
+
+  case convolve(fcInfinity, fcInfinity):
+  case convolve(fcZero, fcZero):
+    category = fcQNaN;
+    return opInvalidOp;
+
+  case convolve(fcNormal, fcNormal):
+    return opOK;
+  }
+}
+
+/* Change sign.  */
+void
+APFloat::changeSign()
+{
+  /* Look mummy, this one's easy.  */
+  sign = !sign;
+}
+
+/* Normalized addition or subtraction.  */
+APFloat::opStatus
+APFloat::addOrSubtract(const APFloat &rhs, roundingMode rounding_mode,
+		       bool subtract)
+{
+  opStatus fs;
+
+  fs = addOrSubtractSpecials(rhs, subtract);
+
+  /* This return code means it was not a simple case.  */
+  if(fs == opDivByZero) {
+    lostFraction lost_fraction;
+
+    lost_fraction = addOrSubtractSignificand(rhs, subtract);
+    fs = normalize(rounding_mode, lost_fraction);
+
+    /* Can only be zero if we lost no fraction.  */
+    assert(category != fcZero || lost_fraction == lfExactlyZero);
+  }
+
+  /* If two numbers add (exactly) to zero, IEEE 754 decrees it is a
+     positive zero unless rounding to minus infinity, except that
+     adding two like-signed zeroes gives that zero.  */
+  if(category == fcZero) {
+    if(rhs.category != fcZero || (sign == rhs.sign) == subtract)
+      sign = (rounding_mode == rmTowardNegative);
+  }
+
+  return fs;
+}
+
+/* Normalized addition.  */
+APFloat::opStatus
+APFloat::add(const APFloat &rhs, roundingMode rounding_mode)
+{
+  return addOrSubtract(rhs, rounding_mode, false);
+}
+
+/* Normalized subtraction.  */
+APFloat::opStatus
+APFloat::subtract(const APFloat &rhs, roundingMode rounding_mode)
+{
+  return addOrSubtract(rhs, rounding_mode, true);
+}
+
+/* Normalized multiply.  */
+APFloat::opStatus
+APFloat::multiply(const APFloat &rhs, roundingMode rounding_mode)
+{
+  opStatus fs;
+
+  sign ^= rhs.sign;
+  fs = multiplySpecials(rhs);
+
+  if(category == fcNormal) {
+    lostFraction lost_fraction = multiplySignificand(rhs, 0);
+    fs = normalize(rounding_mode, lost_fraction);
+    if(lost_fraction != lfExactlyZero)
+      fs = (opStatus) (fs | opInexact);
+  }
+
+  return fs;
+}
+
+/* Normalized divide.  */
+APFloat::opStatus
+APFloat::divide(const APFloat &rhs, roundingMode rounding_mode)
+{
+  opStatus fs;
+
+  sign ^= rhs.sign;
+  fs = divideSpecials(rhs);
+
+  if(category == fcNormal) {
+    lostFraction lost_fraction = divideSignificand(rhs);
+    fs = normalize(rounding_mode, lost_fraction);
+    if(lost_fraction != lfExactlyZero)
+      fs = (opStatus) (fs | opInexact);
+  }
+
+  return fs;
+}
+
+/* Normalized fused-multiply-add.  */
+APFloat::opStatus
+APFloat::fusedMultiplyAdd(const APFloat &multiplicand,
+			  const APFloat &addend,
+			  roundingMode rounding_mode)
+{
+  opStatus fs;
+
+  /* Post-multiplication sign, before addition.  */
+  sign ^= multiplicand.sign;
+
+  /* If and only if all arguments are normal do we need to do an
+     extended-precision calculation.  */
+  if(category == fcNormal
+     && multiplicand.category == fcNormal
+     && addend.category == fcNormal) {
+    lostFraction lost_fraction;
+
+    lost_fraction = multiplySignificand(multiplicand, &addend);
+    fs = normalize(rounding_mode, lost_fraction);
+    if(lost_fraction != lfExactlyZero)
+      fs = (opStatus) (fs | opInexact);
+
+    /* If two numbers add (exactly) to zero, IEEE 754 decrees it is a
+       positive zero unless rounding to minus infinity, except that
+       adding two like-signed zeroes gives that zero.  */
+    if(category == fcZero && sign != addend.sign)
+      sign = (rounding_mode == rmTowardNegative);
+  } else {
+    fs = multiplySpecials(multiplicand);
+
+    /* FS can only be opOK or opInvalidOp.  There is no more work
+       to do in the latter case.  The IEEE-754R standard says it is
+       implementation-defined in this case whether, if ADDEND is a
+       quiet QNaN, we raise invalid op; this implementation does so.
+
+       If we need to do the addition we can do so with normal
+       precision.  */
+    if(fs == opOK)
+      fs = addOrSubtract(addend, rounding_mode, false);
+  }
+
+  return fs;
+}
+
+/* Comparison requires normalized numbers.  */
+APFloat::cmpResult
+APFloat::compare(const APFloat &rhs) const
+{
+  cmpResult result;
+
+  assert(semantics == rhs.semantics);
+
+  switch(convolve(category, rhs.category)) {
+  default:
+    assert(0);
+
+  case convolve(fcQNaN, fcZero):
+  case convolve(fcQNaN, fcNormal):
+  case convolve(fcQNaN, fcInfinity):
+  case convolve(fcQNaN, fcQNaN):
+  case convolve(fcZero, fcQNaN):
+  case convolve(fcNormal, fcQNaN):
+  case convolve(fcInfinity, fcQNaN):
+    return cmpUnordered;
+
+  case convolve(fcInfinity, fcNormal):
+  case convolve(fcInfinity, fcZero):
+  case convolve(fcNormal, fcZero):
+    if(sign)
+      return cmpLessThan;
+    else
+      return cmpGreaterThan;
+
+  case convolve(fcNormal, fcInfinity):
+  case convolve(fcZero, fcInfinity):
+  case convolve(fcZero, fcNormal):
+    if(rhs.sign)
+      return cmpGreaterThan;
+    else
+      return cmpLessThan;
+
+  case convolve(fcInfinity, fcInfinity):
+    if(sign == rhs.sign)
+      return cmpEqual;
+    else if(sign)
+      return cmpLessThan;
+    else
+      return cmpGreaterThan;
+
+  case convolve(fcZero, fcZero):
+    return cmpEqual;
+
+  case convolve(fcNormal, fcNormal):
+    break;
+  }
+
+  /* Two normal numbers.  Do they have the same sign?  */
+  if(sign != rhs.sign) {
+    if(sign)
+      result = cmpLessThan;
+    else
+      result = cmpGreaterThan;
+  } else {
+    /* Compare absolute values; invert result if negative.  */
+    result = compareAbsoluteValue(rhs);
+
+    if(sign) {
+      if(result == cmpLessThan)
+	result = cmpGreaterThan;
+      else if(result == cmpGreaterThan)
+	result = cmpLessThan;
+    }
+  }
+
+  return result;
+}
+
+APFloat::opStatus
+APFloat::convert(const fltSemantics &toSemantics,
+		 roundingMode rounding_mode)
+{
+  unsigned int newPartCount;
+  opStatus fs;
+
+  newPartCount = partCountForBits(toSemantics.precision + 1);
+
+  /* If our new form is wider, re-allocate our bit pattern into wider
+     storage.  */
+  if(newPartCount > partCount()) {
+    integerPart *newParts;
+
+    newParts = new integerPart[newPartCount];
+    APInt::tcSet(newParts, 0, newPartCount);
+    APInt::tcAssign(newParts, significandParts(), partCount());
+    freeSignificand();
+    significand.parts = newParts;
+  }
+
+  if(category == fcNormal) {
+    /* Re-interpret our bit-pattern.  */
+    exponent += toSemantics.precision - semantics->precision;
+    semantics = &toSemantics;
+    fs = normalize(rounding_mode, lfExactlyZero);
+  } else {
+    semantics = &toSemantics;
+    fs = opOK;
+  }
+
+  return fs;
+}
+
+/* Convert a floating point number to an integer according to the
+   rounding mode.  If the rounded integer value is out of range this
+   returns an invalid operation exception.  If the rounded value is in
+   range but the floating point number is not the exact integer, the C
+   standard doesn't require an inexact exception to be raised.  IEEE
+   854 does require it so we do that.
+
+   Note that for conversions to integer type the C standard requires
+   round-to-zero to always be used.  */
+APFloat::opStatus
+APFloat::convertToInteger(integerPart *parts, unsigned int width,
+			  bool isSigned,
+			  roundingMode rounding_mode) const
+{
+  lostFraction lost_fraction;
+  unsigned int msb, partsCount;
+  int bits;
+
+  /* Handle the three special cases first.  */
+  if(category == fcInfinity || category == fcQNaN)
+    return opInvalidOp;
+
+  partsCount = partCountForBits(width);
+
+  if(category == fcZero) {
+    APInt::tcSet(parts, 0, partsCount);
+    return opOK;
+  }
+
+  /* Shift the bit pattern so the fraction is lost.  */
+  APFloat tmp(*this);
+
+  bits = (int) semantics->precision - 1 - exponent;
+
+  if(bits > 0) {
+    lost_fraction = tmp.shiftSignificandRight(bits);
+  } else {
+    tmp.shiftSignificandLeft(-bits);
+    lost_fraction = lfExactlyZero;
+  }
+
+  if(lost_fraction != lfExactlyZero
+     && tmp.roundAwayFromZero(rounding_mode, lost_fraction))
+    tmp.incrementSignificand();
+
+  msb = tmp.significandMSB();
+
+  /* Negative numbers cannot be represented as unsigned.  */
+  if(!isSigned && tmp.sign && msb != -1U)
+    return opInvalidOp;
+
+  /* It takes exponent + 1 bits to represent the truncated floating
+     point number without its sign.  We lose a bit for the sign, but
+     the maximally negative integer is a special case.  */
+  if(msb + 1 > width)		/* !! Not same as msb >= width !! */
+    return opInvalidOp;
+
+  if(isSigned && msb + 1 == width
+     && (!tmp.sign || tmp.significandLSB() != msb))
+    return opInvalidOp;
+
+  APInt::tcAssign(parts, tmp.significandParts(), partsCount);
+
+  if(tmp.sign)
+    APInt::tcNegate(parts, partsCount);
+
+  if(lost_fraction == lfExactlyZero)
+    return opOK;
+  else
+    return opInexact;
+}
+
+APFloat::opStatus
+APFloat::convertFromUnsignedInteger(integerPart *parts,
+				    unsigned int partCount,
+				    roundingMode rounding_mode)
+{
+  unsigned int msb, precision;
+  lostFraction lost_fraction;
+
+  msb = APInt::tcMSB(parts, partCount) + 1;
+  precision = semantics->precision;
+
+  category = fcNormal;
+  exponent = precision - 1;
+
+  if(msb > precision) {
+    exponent += (msb - precision);
+    lost_fraction = shiftRight(parts, partCount, msb - precision);
+    msb = precision;
+  } else
+    lost_fraction = lfExactlyZero;
+
+  /* Copy the bit image.  */
+  zeroSignificand();
+  APInt::tcAssign(significandParts(), parts, partCountForBits(msb));
+
+  return normalize(rounding_mode, lost_fraction);
+}
+
+APFloat::opStatus
+APFloat::convertFromInteger(const integerPart *parts,
+			    unsigned int partCount, bool isSigned,
+			    roundingMode rounding_mode)
+{
+  unsigned int width;
+  opStatus status;
+  integerPart *copy;
+
+  copy = new integerPart[partCount];
+  APInt::tcAssign(copy, parts, partCount);
+
+  width = partCount * integerPartWidth;
+
+  sign = false;
+  if(isSigned && APInt::tcExtractBit(parts, width - 1)) {
+    sign = true;
+    APInt::tcNegate(copy, partCount);
+  }
+
+  status = convertFromUnsignedInteger(copy, partCount, rounding_mode);
+  delete [] copy;
+
+  return status;
+}
+
+APFloat::opStatus
+APFloat::convertFromHexadecimalString(const char *p,
+				      roundingMode rounding_mode)
+{
+  lostFraction lost_fraction;
+  integerPart *significand;
+  unsigned int bitPos, partsCount;
+  const char *dot, *firstSignificantDigit;
+
+  zeroSignificand();
+  exponent = 0;
+  category = fcNormal;
+
+  significand = significandParts();
+  partsCount = partCount();
+  bitPos = partsCount * integerPartWidth;
+
+  /* Skip leading zeroes and any(hexa)decimal point.  */
+  p = skipLeadingZeroesAndAnyDot(p, &dot);
+  firstSignificantDigit = p;
+
+  for(;;) {
+    integerPart hex_value;
+
+    if(*p == '.') {
+      assert(dot == 0);
+      dot = p++;
+    }
+
+    hex_value = hexDigitValue(*p);
+    if(hex_value == -1U) {
+      lost_fraction = lfExactlyZero;
+      break;
+    }
+
+    p++;
+
+    /* Store the number whilst 4-bit nibbles remain.  */
+    if(bitPos) {
+      bitPos -= 4;
+      hex_value <<= bitPos % integerPartWidth;
+      significand[bitPos / integerPartWidth] |= hex_value;
+    } else {
+      lost_fraction = trailingHexadecimalFraction(p, hex_value);
+      while(hexDigitValue(*p) != -1U)
+	p++;
+      break;
+    }
+  }
+
+  /* Hex floats require an exponent but not a hexadecimal point.  */
+  assert(*p == 'p' || *p == 'P');
+
+  /* Ignore the exponent if we are zero.  */
+  if(p != firstSignificantDigit) {
+    int expAdjustment;
+
+    /* Implicit hexadecimal point?  */
+    if(!dot)
+      dot = p;
+
+    /* Calculate the exponent adjustment implicit in the number of
+       significant digits.  */
+    expAdjustment = dot - firstSignificantDigit;
+    if(expAdjustment < 0)
+      expAdjustment++;
+    expAdjustment = expAdjustment * 4 - 1;
+
+    /* Adjust for writing the significand starting at the most
+       significant nibble.  */
+    expAdjustment += semantics->precision;
+    expAdjustment -= partsCount * integerPartWidth;
+
+    /* Adjust for the given exponent.  */
+    exponent = totalExponent(p, expAdjustment);
+  }
+
+  return normalize(rounding_mode, lost_fraction);
+}
+
+APFloat::opStatus
+APFloat::convertFromString(const char *p, roundingMode rounding_mode)
+{
+  /* Handle a leading minus sign.  */
+  if(*p == '-')
+    sign = 1, p++;
+  else
+    sign = 0;
+
+  if(p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
+    return convertFromHexadecimalString(p + 2, rounding_mode);
+  else
+    {
+      assert(0 && "Decimal to binary conversions not yet imlemented");
+      abort();
+    }
+}


More information about the llvm-dev mailing list