Add half precision floating point support (float16) to APFloat,

patch by Peter Johnson! (PR5195)


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@84239 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2009-10-16 02:13:51 +00:00
parent a43fc3452b
commit cc4287a374
2 changed files with 72 additions and 1 deletions

View File

@ -125,6 +125,7 @@ namespace llvm {
public:
/* We support the following floating point semantics. */
static const fltSemantics IEEEhalf;
static const fltSemantics IEEEsingle;
static const fltSemantics IEEEdouble;
static const fltSemantics IEEEquad;
@ -321,12 +322,14 @@ namespace llvm {
opStatus roundSignificandWithExponent(const integerPart *, unsigned int,
int, roundingMode);
APInt convertHalfAPFloatToAPInt() const;
APInt convertFloatAPFloatToAPInt() const;
APInt convertDoubleAPFloatToAPInt() const;
APInt convertQuadrupleAPFloatToAPInt() const;
APInt convertF80LongDoubleAPFloatToAPInt() const;
APInt convertPPCDoubleDoubleAPFloatToAPInt() const;
void initFromAPInt(const APInt& api, bool isIEEE = false);
void initFromHalfAPInt(const APInt& api);
void initFromFloatAPInt(const APInt& api);
void initFromDoubleAPInt(const APInt& api);
void initFromQuadrupleAPInt(const APInt &api);

View File

@ -48,6 +48,7 @@ namespace llvm {
unsigned int arithmeticOK;
};
const fltSemantics APFloat::IEEEhalf = { 15, -14, 11, true };
const fltSemantics APFloat::IEEEsingle = { 127, -126, 24, true };
const fltSemantics APFloat::IEEEdouble = { 1023, -1022, 53, true };
const fltSemantics APFloat::IEEEquad = { 16383, -16382, 113, true };
@ -2812,6 +2813,35 @@ APFloat::convertFloatAPFloatToAPInt() const
(mysignificand & 0x7fffff)));
}
APInt
APFloat::convertHalfAPFloatToAPInt() const
{
assert(semantics == (const llvm::fltSemantics*)&IEEEhalf);
assert (partCount()==1);
uint32_t myexponent, mysignificand;
if (category==fcNormal) {
myexponent = exponent+15; //bias
mysignificand = (uint32_t)*significandParts();
if (myexponent == 1 && !(mysignificand & 0x400))
myexponent = 0; // denormal
} else if (category==fcZero) {
myexponent = 0;
mysignificand = 0;
} else if (category==fcInfinity) {
myexponent = 0xff;
mysignificand = 0;
} else {
assert(category == fcNaN && "Unknown category!");
myexponent = 0xff;
mysignificand = (uint32_t)*significandParts();
}
return APInt(16, (((sign&1) << 15) | ((myexponent&0x1f) << 10) |
(mysignificand & 0x3ff)));
}
// This function creates an APInt that is just a bit map of the floating
// point constant as it would appear in memory. It is not a conversion,
// and treating the result as a normal integer is unlikely to be useful.
@ -2819,6 +2849,9 @@ APFloat::convertFloatAPFloatToAPInt() const
APInt
APFloat::bitcastToAPInt() const
{
if (semantics == (const llvm::fltSemantics*)&IEEEhalf)
return convertHalfAPFloatToAPInt();
if (semantics == (const llvm::fltSemantics*)&IEEEsingle)
return convertFloatAPFloatToAPInt();
@ -3051,6 +3084,39 @@ APFloat::initFromFloatAPInt(const APInt & api)
}
}
void
APFloat::initFromHalfAPInt(const APInt & api)
{
assert(api.getBitWidth()==16);
uint32_t i = (uint32_t)*api.getRawData();
uint32_t myexponent = (i >> 15) & 0x1f;
uint32_t mysignificand = i & 0x3ff;
initialize(&APFloat::IEEEhalf);
assert(partCount()==1);
sign = i >> 15;
if (myexponent==0 && mysignificand==0) {
// exponent, significand meaningless
category = fcZero;
} else if (myexponent==0x1f && mysignificand==0) {
// exponent, significand meaningless
category = fcInfinity;
} else if (myexponent==0x1f && mysignificand!=0) {
// sign, exponent, significand meaningless
category = fcNaN;
*significandParts() = mysignificand;
} else {
category = fcNormal;
exponent = myexponent - 15; //bias
*significandParts() = mysignificand;
if (myexponent==0) // denormal
exponent = -14;
else
*significandParts() |= 0x400; // integer bit
}
}
/// Treat api as containing the bits of a floating point number. Currently
/// we infer the floating point type from the size of the APInt. The
/// isIEEE argument distinguishes between PPC128 and IEEE128 (not meaningful
@ -3058,7 +3124,9 @@ APFloat::initFromFloatAPInt(const APInt & api)
void
APFloat::initFromAPInt(const APInt& api, bool isIEEE)
{
if (api.getBitWidth() == 32)
if (api.getBitWidth() == 16)
return initFromHalfAPInt(api);
else if (api.getBitWidth() == 32)
return initFromFloatAPInt(api);
else if (api.getBitWidth()==64)
return initFromDoubleAPInt(api);