From 8324d9159453c1e580600f6f1c8d1d7d0d54539d Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Wed, 7 Jul 2021 18:17:36 -0700 Subject: [PATCH 1/2] Remove dead code from half * move eLut.h, imath_float_half_exp_table, and long_convert to ImathTest. They're useful to validate behavior in the test but have no use in the actual library. Signed-off-by: Cary Phillips --- src/Imath/CMakeLists.txt | 1 - src/Imath/eLut.cpp | 82 ---------------- src/Imath/half.cpp | 164 ------------------------------- src/Imath/half.h | 11 --- src/{Imath => ImathTest}/eLut.h | 0 src/ImathTest/half_c_main.c | 2 +- src/ImathTest/half_perf_test.cpp | 162 +++++++++++++++++++++++++++++- 7 files changed, 162 insertions(+), 260 deletions(-) delete mode 100644 src/Imath/eLut.cpp rename src/{Imath => ImathTest}/eLut.h (100%) diff --git a/src/Imath/CMakeLists.txt b/src/Imath/CMakeLists.txt index ccb6cb85..fde5bc59 100644 --- a/src/Imath/CMakeLists.txt +++ b/src/Imath/CMakeLists.txt @@ -10,7 +10,6 @@ imath_define_library(Imath ImathFun.cpp ImathMatrixAlgo.cpp toFloat.h - eLut.h half.cpp HEADERS ImathBoxAlgo.h diff --git a/src/Imath/eLut.cpp b/src/Imath/eLut.cpp deleted file mode 100644 index 2ab9a356..00000000 --- a/src/Imath/eLut.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// -// SPDX-License-Identifier: BSD-3-Clause -// Copyright Contributors to the OpenEXR Project. -// - -#include -#include - -using namespace std; - -//----------------------------------------------------- -// Compute a lookup table for float-to-half conversion. -// -// When indexed with the combined sign and exponent of -// a float, the table either returns the combined sign -// and exponent of the corresponding half, or zero if -// the corresponding half may not be normalized (zero, -// denormalized, overflow). -//----------------------------------------------------- - -void -initELut (unsigned short eLut[]) -{ - for (int i = 0; i < 0x100; i++) - { - int e = (i & 0x0ff) - (127 - 15); - - if (e <= 0 || e >= 30) - { - // - // Special case - // - - eLut[i] = 0; - eLut[i | 0x100] = 0; - } - else - { - // - // Common case - normalized half, no exponent overflow possible - // - - eLut[i] = (e << 10); - eLut[i | 0x100] = ((e << 10) | 0x8000); - } - } -} - -//------------------------------------------------------------ -// Main - prints the sign-and-exponent conversion lookup table -//------------------------------------------------------------ - -int -main() -{ - const int tableSize = 1 << 9; - unsigned short eLut[tableSize]; - initELut (eLut); - - cout << "//\n" - "// This is an automatically generated file.\n" - "// Do not edit.\n" - "//\n\n"; - - cout << "{\n "; - - for (int i = 0; i < tableSize; i++) - { - cout << setw (5) << eLut[i] << ", "; - - if (i % 8 == 7) - { - cout << "\n"; - - if (i < tableSize - 1) - cout << " "; - } - } - - cout << "};\n"; - return 0; -} diff --git a/src/Imath/half.cpp b/src/Imath/half.cpp index b00623a3..037666b6 100644 --- a/src/Imath/half.cpp +++ b/src/Imath/half.cpp @@ -37,178 +37,14 @@ using namespace std; const imath_half_uif_t imath_half_to_float_table_data[1 << 16] = #include "toFloat.h" -const uint16_t imath_float_half_exp_table_data[1 << 9] = -#include "eLut.h" - extern "C" { EXPORT_CONST const imath_half_uif_t *imath_half_to_float_table = imath_half_to_float_table_data; -EXPORT_CONST const uint16_t *imath_float_half_exp_table = imath_float_half_exp_table_data; } // extern "C" #endif // clang-format on -//#ifdef IMATH_USE_ORIGINAL_HALF_IMPLEMENTATION -//----------------------------------------------- -// Overflow handler for float-to-half conversion; -// generates a hardware floating-point overflow, -// which may be trapped by the operating system. -//----------------------------------------------- - -static float -half_overflow() IMATH_NOEXCEPT -{ - float f = 1e10; - - for (int i = 0; i < 10; i++) - f *= f; // this will overflow before the for loop terminates - - return f; -} - -//----------------------------------------------------- -// Float-to-half conversion -- general case, including -// zeroes, denormalized numbers and exponent overflows. -//----------------------------------------------------- - -IMATH_EXPORT uint16_t -half::long_convert (int i) IMATH_NOEXCEPT -{ - // - // Our floating point number, f, is represented by the bit - // pattern in integer i. Disassemble that bit pattern into - // the sign, s, the exponent, e, and the significand, m. - // Shift s into the position where it will go in in the - // resulting half number. - // Adjust e, accounting for the different exponent bias - // of float and half (127 versus 15). - // - - int s = (i >> 16) & 0x00008000; - int e = ((i >> 23) & 0x000000ff) - (127 - 15); - int m = i & 0x007fffff; - - // - // Now reassemble s, e and m into a half: - // - - if (e <= 0) - { - if (e < -10) - { - // - // E is less than -10. The absolute value of f is - // less than HALF_DENORM_MIN (f may be a small normalized - // float, a denormalized float or a zero). - // - // We convert f to a half zero with the same sign as f. - // - - return s; - } - - // - // E is between -10 and 0. F is a normalized float - // whose magnitude is less than HALF_NRM_MIN. - // - // We convert f to a denormalized half. - // - - // - // Add an explicit leading 1 to the significand. - // - - m = m | 0x00800000; - - // - // Round to m to the nearest (10+e)-bit value (with e between - // -10 and 0); in case of a tie, round to the nearest even value. - // - // Rounding may cause the significand to overflow and make - // our number normalized. Because of the way a half's bits - // are laid out, we don't have to treat this case separately; - // the code below will handle it correctly. - // - - int t = 14 - e; - int a = (1 << (t - 1)) - 1; - int b = (m >> t) & 1; - - m = (m + a + b) >> t; - - // - // Assemble the half from s, e (zero) and m. - // - - return s | m; - } - else if (e == 0xff - (127 - 15)) - { - if (m == 0) - { - // - // F is an infinity; convert f to a half - // infinity with the same sign as f. - // - - return s | 0x7c00; - } - else - { - // - // F is a NAN; we produce a half NAN that preserves - // the sign bit and the 10 leftmost bits of the - // significand of f, with one exception: If the 10 - // leftmost bits are all zero, the NAN would turn - // into an infinity, so we have to set at least one - // bit in the significand. - // - - m >>= 13; - return s | 0x7c00 | m | (m == 0); - } - } - else - { - // - // E is greater than zero. F is a normalized float. - // We try to convert f to a normalized half. - // - - // - // Round to m to the nearest 10-bit value. In case of - // a tie, round to the nearest even value. - // - - m = m + 0x00000fff + ((m >> 13) & 1); - - if (m & 0x00800000) - { - m = 0; // overflow in significand, - e += 1; // adjust exponent - } - - // - // Handle exponent overflow - // - - if (e > 30) - { - half_overflow (); // Cause a hardware floating point overflow; - return s | 0x7c00; // if this returns, the half becomes an - } // infinity with the same sign as f. - - // - // Assemble the half from s, e and m. - // - - return s | (e << 10) | (m >> 13); - } -} - -//#endif - //--------------------- // Stream I/O operators //--------------------- diff --git a/src/Imath/half.h b/src/Imath/half.h index 2516637d..8ad41784 100644 --- a/src/Imath/half.h +++ b/src/Imath/half.h @@ -144,15 +144,6 @@ extern # endif IMATH_EXPORT const imath_half_uif_t* imath_half_to_float_table; -// This is still exposed as a symbol, but is no longer actively used -// other than within the performance test @sa half_perf_test.cpp -// TODO: consider deprecating and removing it -# if defined(__cplusplus) -extern "C" -# else -extern -# endif - IMATH_EXPORT const uint16_t* imath_float_half_exp_table; #endif //////////////////////////////////////// @@ -180,8 +171,6 @@ imath_half_to_float (imath_half_bits_t h) // (1.06 vs 1.08 ns/call) to avoid the constants and just do 4 // shifts. // - //uint32_t hexpmant = (h & ~0x8000) << 13; - //v.i = (h & 0x8000) << 16; uint32_t hexpmant = ( (uint32_t)(h) << 17 ) >> 4; v.i = ((uint32_t)(h >> 15)) << 31; diff --git a/src/Imath/eLut.h b/src/ImathTest/eLut.h similarity index 100% rename from src/Imath/eLut.h rename to src/ImathTest/eLut.h diff --git a/src/ImathTest/half_c_main.c b/src/ImathTest/half_c_main.c index 660aafc5..97ef07b4 100644 --- a/src/ImathTest/half_c_main.c +++ b/src/ImathTest/half_c_main.c @@ -21,7 +21,7 @@ static const c_half_uif half_to_float[1 << 16] = #include "../Imath/toFloat.h" static const unsigned short half_eLut[1 << 9] = -#include "../Imath/eLut.h" +#include "eLut.h" static short exp_long_convert (int i) { diff --git a/src/ImathTest/half_perf_test.cpp b/src/ImathTest/half_perf_test.cpp index 5458cabf..14eefb3e 100644 --- a/src/ImathTest/half_perf_test.cpp +++ b/src/ImathTest/half_perf_test.cpp @@ -24,6 +24,9 @@ #include +static const unsigned short imath_float_half_exp_table[1 << 9] = +#include "eLut.h" + using namespace IMATH_NAMESPACE; #ifdef IMATH_ENABLE_HALF_LOOKUP_TABLES @@ -32,6 +35,163 @@ static inline float table_half_cast(const half &h) return imath_half_to_float_table[h.bits()].f; } +//----------------------------------------------- +// Overflow handler for float-to-half conversion; +// generates a hardware floating-point overflow, +// which may be trapped by the operating system. +//----------------------------------------------- + +static float +half_overflow() +{ + float f = 1e10; + + for (int i = 0; i < 10; i++) + f *= f; // this will overflow before the for loop terminates + + return f; +} + +//----------------------------------------------------- +// Float-to-half conversion -- general case, including +// zeroes, denormalized numbers and exponent overflows. +//----------------------------------------------------- + +static uint16_t +long_convert (int i) +{ + // + // Our floating point number, f, is represented by the bit + // pattern in integer i. Disassemble that bit pattern into + // the sign, s, the exponent, e, and the significand, m. + // Shift s into the position where it will go in in the + // resulting half number. + // Adjust e, accounting for the different exponent bias + // of float and half (127 versus 15). + // + + int s = (i >> 16) & 0x00008000; + int e = ((i >> 23) & 0x000000ff) - (127 - 15); + int m = i & 0x007fffff; + + // + // Now reassemble s, e and m into a half: + // + + if (e <= 0) + { + if (e < -10) + { + // + // E is less than -10. The absolute value of f is + // less than HALF_DENORM_MIN (f may be a small normalized + // float, a denormalized float or a zero). + // + // We convert f to a half zero with the same sign as f. + // + + return s; + } + + // + // E is between -10 and 0. F is a normalized float + // whose magnitude is less than HALF_NRM_MIN. + // + // We convert f to a denormalized half. + // + + // + // Add an explicit leading 1 to the significand. + // + + m = m | 0x00800000; + + // + // Round to m to the nearest (10+e)-bit value (with e between + // -10 and 0); in case of a tie, round to the nearest even value. + // + // Rounding may cause the significand to overflow and make + // our number normalized. Because of the way a half's bits + // are laid out, we don't have to treat this case separately; + // the code below will handle it correctly. + // + + int t = 14 - e; + int a = (1 << (t - 1)) - 1; + int b = (m >> t) & 1; + + m = (m + a + b) >> t; + + // + // Assemble the half from s, e (zero) and m. + // + + return s | m; + } + else if (e == 0xff - (127 - 15)) + { + if (m == 0) + { + // + // F is an infinity; convert f to a half + // infinity with the same sign as f. + // + + return s | 0x7c00; + } + else + { + // + // F is a NAN; we produce a half NAN that preserves + // the sign bit and the 10 leftmost bits of the + // significand of f, with one exception: If the 10 + // leftmost bits are all zero, the NAN would turn + // into an infinity, so we have to set at least one + // bit in the significand. + // + + m >>= 13; + return s | 0x7c00 | m | (m == 0); + } + } + else + { + // + // E is greater than zero. F is a normalized float. + // We try to convert f to a normalized half. + // + + // + // Round to m to the nearest 10-bit value. In case of + // a tie, round to the nearest even value. + // + + m = m + 0x00000fff + ((m >> 13) & 1); + + if (m & 0x00800000) + { + m = 0; // overflow in significand, + e += 1; // adjust exponent + } + + // + // Handle exponent overflow + // + + if (e > 30) + { + half_overflow (); // Cause a hardware floating point overflow; + return s | 0x7c00; // if this returns, the half becomes an + } // infinity with the same sign as f. + + // + // Assemble the half from s, e and m. + // + + return s | (e << 10) | (m >> 13); + } +} + static inline half exptable_half_constructor(float f) { half ret; @@ -86,7 +246,7 @@ static inline half exptable_half_constructor(float f) // Difficult case - call a function. // - ret.setBits (half::long_convert (x.i)); + ret.setBits (long_convert (x.i)); } } return ret; From 1c154264f14f9eaa6078d9925ddfafa1c7ef3744 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Wed, 7 Jul 2021 18:28:01 -0700 Subject: [PATCH 2/2] Remove long_convert declaration from half.h Signed-off-by: Cary Phillips --- src/Imath/half.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Imath/half.h b/src/Imath/half.h index 8ad41784..3dd23d37 100644 --- a/src/Imath/half.h +++ b/src/Imath/half.h @@ -494,8 +494,6 @@ class IMATH_EXPORT_TYPE half "Assumption about the size of floats correct"); using uif = imath_half_uif; - // preserved for legacy conversion - IMATH_EXPORT static uint16_t long_convert ( int i ) IMATH_NOEXCEPT; private: constexpr uint16_t mantissa() const IMATH_NOEXCEPT;