From cc4287a374a33fb03ef41b92f74783e31ef47650 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Fri, 16 Oct 2009 02:13:51 +0000 Subject: [PATCH] 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 --- include/llvm/ADT/APFloat.h | 3 ++ lib/Support/APFloat.cpp | 70 +++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index 4d7e7ae11e8..30d998fc3c1 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -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); diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index e431d279023..361614a8283 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -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);