From 6a2951d061d61f8bc1d626e40ce51c6555e549ae Mon Sep 17 00:00:00 2001 From: John Byrd Date: Wed, 18 Feb 2026 21:40:40 -0800 Subject: [PATCH] Handle non-canonical extFloat80 encodings in all extF80 operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 80-bit extended double format stores the integer bit (J bit) explicitly in the significand, making it possible to construct encodings where the J bit is inconsistent with the exponent. These non-canonical encodings — unnormals, pseudo-denormals, pseudo- infinities, and pseudo-NaNs — are accepted by hardware but were silently mishandled by SoftFloat, producing wrong results. Add four canonicalization functions that rewrite non-canonical encodings to their canonical equivalents, preserving the represented value: softfloat_canonicalizeExtF80 (FAST_INT64, unpacked exp/sig) softfloat_canonicalizeExtF80UI (FAST_INT64, packed signExp/sig) softfloat_canonicalizeExtF80M (non-FAST_INT64, unpacked exp/sig) softfloat_canonicalizeExtF80MUI (non-FAST_INT64, packed signExp/sig) Call the appropriate function at the top of every extF80 operation so that all subsequent logic sees only canonical inputs. This fixes wrong results across all 37 affected functions on both code paths: - 12 FAST_INT64 conversions (to f16/f32/f64/f128/i32/i64/ui32/ui64) - 4 non-FAST_INT64 conversions (to i32/i64/ui32/ui64) - 6 FAST_INT64 comparisons (eq, lt, le, and signaling/quiet variants) - 6 non-FAST_INT64 comparisons - FAST_INT64 add/sub (s_addMagsExtF80, s_subMagsExtF80) - non-FAST_INT64 add/sub (s_addExtF80M) - FAST_INT64 mul, sqrt, rem - non-FAST_INT64 rem - non-FAST_INT64 three-way compare (s_compareNonnormExtF80M) Additional fixes beyond canonicalization: - extF80_mul: the unified 'infArg' path tested (expB | sigB) to detect infinity * zero, but an unnormal has nonzero sigB even when its value is zero. Split into separate 'invalid' and 'infinity' labels with direct significand checks. - extF80_sqrt: sqrt of a pseudo-infinity returned the raw input instead of a canonical infinity. - extF80_rem: a pseudo-denormal divisor confused the normalization logic because sigB already had J=1 but expB was 0. - s_addMagsExtF80: adding two pseudo-denormals could overflow the significand without being caught; infinity results propagated the raw (possibly non-canonical) significand. - s_subMagsExtF80: equal-magnitude subtraction after alignment fell through to the wrong label instead of producing zero; infinity results propagated non-canonical significands. - s_addExtF80M: replaced pointer-swapping with local variable swapping so that canonicalized values are used throughout. Move struct exp32_sig64 and softfloat_normSubnormalExtF80Sig above the SOFTFLOAT_FAST_INT64 guard in internals.h so both code paths can use them. Update all 10 platform Makefiles. Tested with TestFloat level-1 on both FAST_INT64 (Linux-x86_64-GCC) and non-FAST_INT64 (Linux-386-GCC) builds: 0 errors across all extF80 operations. --- build/Linux-386-GCC/Makefile | 3 + build/Linux-386-SSE2-GCC/Makefile | 3 + build/Linux-ARM-VFPv2-GCC/Makefile | 3 + build/Linux-RISCV64-GCC/Makefile | 2 + build/Linux-x86_64-GCC/Makefile | 2 + build/Win32-MinGW/Makefile | 3 + build/Win32-SSE2-MinGW/Makefile | 3 + build/Win64-MinGW-w64/Makefile | 2 + build/template-FAST_INT64/Makefile | 2 + build/template-not-FAST_INT64/Makefile | 3 + source/extF80M_eq.c | 2 + source/extF80M_eq_signaling.c | 2 + source/extF80M_le.c | 2 + source/extF80M_le_quiet.c | 2 + source/extF80M_lt.c | 2 + source/extF80M_lt_quiet.c | 2 + source/extF80M_rem.c | 6 +- source/extF80M_to_i32.c | 1 + source/extF80M_to_i64.c | 1 + source/extF80M_to_ui32.c | 1 + source/extF80M_to_ui64.c | 1 + source/extF80_eq.c | 2 + source/extF80_eq_signaling.c | 2 + source/extF80_le.c | 2 + source/extF80_le_quiet.c | 2 + source/extF80_lt.c | 2 + source/extF80_lt_quiet.c | 2 + source/extF80_mul.c | 28 +++--- source/extF80_rem.c | 1 + source/extF80_sqrt.c | 6 +- source/extF80_to_f128.c | 8 +- source/extF80_to_f16.c | 1 + source/extF80_to_f32.c | 1 + source/extF80_to_f64.c | 1 + source/extF80_to_i32.c | 1 + source/extF80_to_i32_r_minMag.c | 1 + source/extF80_to_i64.c | 1 + source/extF80_to_i64_r_minMag.c | 1 + source/extF80_to_ui32.c | 1 + source/extF80_to_ui32_r_minMag.c | 1 + source/extF80_to_ui64.c | 1 + source/extF80_to_ui64_r_minMag.c | 1 + source/include/internals.h | 15 ++- source/s_addExtF80M.c | 23 +++-- source/s_addMagsExtF80.c | 18 +++- source/s_canonicalizeExtF80.c | 122 +++++++++++++++++++++++++ source/s_canonicalizeExtF80M.c | 81 ++++++++++++++++ source/s_canonicalizeExtF80MUI.c | 62 +++++++++++++ source/s_canonicalizeExtF80UI.c | 62 +++++++++++++ source/s_compareNonnormExtF80M.c | 8 +- source/s_subMagsExtF80.c | 16 +++- 51 files changed, 483 insertions(+), 38 deletions(-) create mode 100644 source/s_canonicalizeExtF80.c create mode 100644 source/s_canonicalizeExtF80M.c create mode 100644 source/s_canonicalizeExtF80MUI.c create mode 100644 source/s_canonicalizeExtF80UI.c diff --git a/build/Linux-386-GCC/Makefile b/build/Linux-386-GCC/Makefile index faeb3972..24d9b735 100644 --- a/build/Linux-386-GCC/Makefile +++ b/build/Linux-386-GCC/Makefile @@ -133,6 +133,9 @@ OBJS_OTHERS = \ s_tryPropagateNaNExtF80M$(OBJ) \ s_invalidExtF80M$(OBJ) \ s_normExtF80SigM$(OBJ) \ + s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80M$(OBJ) \ + s_canonicalizeExtF80MUI$(OBJ) \ s_roundPackMToExtF80M$(OBJ) \ s_normRoundPackMToExtF80M$(OBJ) \ s_addExtF80M$(OBJ) \ diff --git a/build/Linux-386-SSE2-GCC/Makefile b/build/Linux-386-SSE2-GCC/Makefile index ced977b6..b041561d 100644 --- a/build/Linux-386-SSE2-GCC/Makefile +++ b/build/Linux-386-SSE2-GCC/Makefile @@ -133,6 +133,9 @@ OBJS_OTHERS = \ s_tryPropagateNaNExtF80M$(OBJ) \ s_invalidExtF80M$(OBJ) \ s_normExtF80SigM$(OBJ) \ + s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80M$(OBJ) \ + s_canonicalizeExtF80MUI$(OBJ) \ s_roundPackMToExtF80M$(OBJ) \ s_normRoundPackMToExtF80M$(OBJ) \ s_addExtF80M$(OBJ) \ diff --git a/build/Linux-ARM-VFPv2-GCC/Makefile b/build/Linux-ARM-VFPv2-GCC/Makefile index a1e7c830..23252179 100644 --- a/build/Linux-ARM-VFPv2-GCC/Makefile +++ b/build/Linux-ARM-VFPv2-GCC/Makefile @@ -131,6 +131,9 @@ OBJS_OTHERS = \ s_tryPropagateNaNExtF80M$(OBJ) \ s_invalidExtF80M$(OBJ) \ s_normExtF80SigM$(OBJ) \ + s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80M$(OBJ) \ + s_canonicalizeExtF80MUI$(OBJ) \ s_roundPackMToExtF80M$(OBJ) \ s_normRoundPackMToExtF80M$(OBJ) \ s_addExtF80M$(OBJ) \ diff --git a/build/Linux-RISCV64-GCC/Makefile b/build/Linux-RISCV64-GCC/Makefile index 72e1f632..fa34548e 100644 --- a/build/Linux-RISCV64-GCC/Makefile +++ b/build/Linux-RISCV64-GCC/Makefile @@ -140,6 +140,8 @@ OBJS_OTHERS = \ s_subMagsF64$(OBJ) \ s_mulAddF64$(OBJ) \ s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80$(OBJ) \ + s_canonicalizeExtF80UI$(OBJ) \ s_roundPackToExtF80$(OBJ) \ s_normRoundPackToExtF80$(OBJ) \ s_addMagsExtF80$(OBJ) \ diff --git a/build/Linux-x86_64-GCC/Makefile b/build/Linux-x86_64-GCC/Makefile index 72f251a5..b7744aef 100644 --- a/build/Linux-x86_64-GCC/Makefile +++ b/build/Linux-x86_64-GCC/Makefile @@ -137,6 +137,8 @@ OBJS_OTHERS = \ s_subMagsF64$(OBJ) \ s_mulAddF64$(OBJ) \ s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80$(OBJ) \ + s_canonicalizeExtF80UI$(OBJ) \ s_roundPackToExtF80$(OBJ) \ s_normRoundPackToExtF80$(OBJ) \ s_addMagsExtF80$(OBJ) \ diff --git a/build/Win32-MinGW/Makefile b/build/Win32-MinGW/Makefile index faeb3972..24d9b735 100644 --- a/build/Win32-MinGW/Makefile +++ b/build/Win32-MinGW/Makefile @@ -133,6 +133,9 @@ OBJS_OTHERS = \ s_tryPropagateNaNExtF80M$(OBJ) \ s_invalidExtF80M$(OBJ) \ s_normExtF80SigM$(OBJ) \ + s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80M$(OBJ) \ + s_canonicalizeExtF80MUI$(OBJ) \ s_roundPackMToExtF80M$(OBJ) \ s_normRoundPackMToExtF80M$(OBJ) \ s_addExtF80M$(OBJ) \ diff --git a/build/Win32-SSE2-MinGW/Makefile b/build/Win32-SSE2-MinGW/Makefile index ced977b6..b041561d 100644 --- a/build/Win32-SSE2-MinGW/Makefile +++ b/build/Win32-SSE2-MinGW/Makefile @@ -133,6 +133,9 @@ OBJS_OTHERS = \ s_tryPropagateNaNExtF80M$(OBJ) \ s_invalidExtF80M$(OBJ) \ s_normExtF80SigM$(OBJ) \ + s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80M$(OBJ) \ + s_canonicalizeExtF80MUI$(OBJ) \ s_roundPackMToExtF80M$(OBJ) \ s_normRoundPackMToExtF80M$(OBJ) \ s_addExtF80M$(OBJ) \ diff --git a/build/Win64-MinGW-w64/Makefile b/build/Win64-MinGW-w64/Makefile index cc5bc0c5..d3686ccb 100644 --- a/build/Win64-MinGW-w64/Makefile +++ b/build/Win64-MinGW-w64/Makefile @@ -133,6 +133,8 @@ OBJS_OTHERS = \ s_subMagsF64$(OBJ) \ s_mulAddF64$(OBJ) \ s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80$(OBJ) \ + s_canonicalizeExtF80UI$(OBJ) \ s_roundPackToExtF80$(OBJ) \ s_normRoundPackToExtF80$(OBJ) \ s_addMagsExtF80$(OBJ) \ diff --git a/build/template-FAST_INT64/Makefile b/build/template-FAST_INT64/Makefile index e04c2160..867674a0 100644 --- a/build/template-FAST_INT64/Makefile +++ b/build/template-FAST_INT64/Makefile @@ -136,6 +136,8 @@ OBJS_OTHERS = \ s_subMagsF64$(OBJ) \ s_mulAddF64$(OBJ) \ s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80$(OBJ) \ + s_canonicalizeExtF80UI$(OBJ) \ s_roundPackToExtF80$(OBJ) \ s_normRoundPackToExtF80$(OBJ) \ s_addMagsExtF80$(OBJ) \ diff --git a/build/template-not-FAST_INT64/Makefile b/build/template-not-FAST_INT64/Makefile index 48b2cd6b..33d79759 100644 --- a/build/template-not-FAST_INT64/Makefile +++ b/build/template-not-FAST_INT64/Makefile @@ -133,6 +133,9 @@ OBJS_OTHERS = \ s_tryPropagateNaNExtF80M$(OBJ) \ s_invalidExtF80M$(OBJ) \ s_normExtF80SigM$(OBJ) \ + s_normSubnormalExtF80Sig$(OBJ) \ + s_canonicalizeExtF80M$(OBJ) \ + s_canonicalizeExtF80MUI$(OBJ) \ s_roundPackMToExtF80M$(OBJ) \ s_normRoundPackMToExtF80M$(OBJ) \ s_addExtF80M$(OBJ) \ diff --git a/source/extF80M_eq.c b/source/extF80M_eq.c index 24800371..533c28eb 100644 --- a/source/extF80M_eq.c +++ b/source/extF80M_eq.c @@ -70,6 +70,8 @@ bool extF80M_eq( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) uiA0 = aSPtr->signif; uiB64 = bSPtr->signExp; uiB0 = bSPtr->signif; + softfloat_canonicalizeExtF80MUI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80MUI( &uiB64, &uiB0 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { diff --git a/source/extF80M_eq_signaling.c b/source/extF80M_eq_signaling.c index 785eba1e..81b31ab9 100644 --- a/source/extF80M_eq_signaling.c +++ b/source/extF80M_eq_signaling.c @@ -69,6 +69,8 @@ bool extF80M_eq_signaling( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) uiA0 = aSPtr->signif; uiB64 = bSPtr->signExp; uiB0 = bSPtr->signif; + softfloat_canonicalizeExtF80MUI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80MUI( &uiB64, &uiB0 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { diff --git a/source/extF80M_le.c b/source/extF80M_le.c index 24edae87..a164f97b 100644 --- a/source/extF80M_le.c +++ b/source/extF80M_le.c @@ -70,6 +70,8 @@ bool extF80M_le( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) uiA0 = aSPtr->signif; uiB64 = bSPtr->signExp; uiB0 = bSPtr->signif; + softfloat_canonicalizeExtF80MUI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80MUI( &uiB64, &uiB0 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { diff --git a/source/extF80M_le_quiet.c b/source/extF80M_le_quiet.c index 3880e36d..16e4ee4c 100644 --- a/source/extF80M_le_quiet.c +++ b/source/extF80M_le_quiet.c @@ -71,6 +71,8 @@ bool extF80M_le_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) uiA0 = aSPtr->signif; uiB64 = bSPtr->signExp; uiB0 = bSPtr->signif; + softfloat_canonicalizeExtF80MUI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80MUI( &uiB64, &uiB0 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { diff --git a/source/extF80M_lt.c b/source/extF80M_lt.c index 70fa8f05..ec9a33a6 100644 --- a/source/extF80M_lt.c +++ b/source/extF80M_lt.c @@ -70,6 +70,8 @@ bool extF80M_lt( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) uiA0 = aSPtr->signif; uiB64 = bSPtr->signExp; uiB0 = bSPtr->signif; + softfloat_canonicalizeExtF80MUI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80MUI( &uiB64, &uiB0 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { diff --git a/source/extF80M_lt_quiet.c b/source/extF80M_lt_quiet.c index b119af30..385e358c 100644 --- a/source/extF80M_lt_quiet.c +++ b/source/extF80M_lt_quiet.c @@ -71,6 +71,8 @@ bool extF80M_lt_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) uiA0 = aSPtr->signif; uiB64 = bSPtr->signExp; uiB0 = bSPtr->signif; + softfloat_canonicalizeExtF80MUI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80MUI( &uiB64, &uiB0 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { diff --git a/source/extF80M_rem.c b/source/extF80M_rem.c index 065e271a..18355e93 100644 --- a/source/extF80M_rem.c +++ b/source/extF80M_rem.c @@ -79,6 +79,10 @@ void uiA64 = aSPtr->signExp; expA = expExtF80UI64( uiA64 ); expB = expExtF80UI64( bSPtr->signExp ); + sigA = aSPtr->signif; + x64 = bSPtr->signif; + softfloat_canonicalizeExtF80M( &expA, &sigA ); + softfloat_canonicalizeExtF80M( &expB, &x64 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { @@ -95,14 +99,12 @@ void /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expB ) expB = 1; - x64 = bSPtr->signif; if ( ! (x64 & UINT64_C( 0x8000000000000000 )) ) { if ( ! x64 ) goto invalid; expB += softfloat_normExtF80SigM( &x64 ); } signRem = signExtF80UI64( uiA64 ); if ( ! expA ) expA = 1; - sigA = aSPtr->signif; if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { if ( ! sigA ) { expA = 0; diff --git a/source/extF80M_to_i32.c b/source/extF80M_to_i32.c index c0464b13..e8b7046d 100644 --- a/source/extF80M_to_i32.c +++ b/source/extF80M_to_i32.c @@ -72,6 +72,7 @@ int_fast32_t sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = aSPtr->signif; + softfloat_canonicalizeExtF80M( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x4032 - exp; diff --git a/source/extF80M_to_i64.c b/source/extF80M_to_i64.c index 2e07207a..892dba80 100644 --- a/source/extF80M_to_i64.c +++ b/source/extF80M_to_i64.c @@ -73,6 +73,7 @@ int_fast64_t sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = aSPtr->signif; + softfloat_canonicalizeExtF80M( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x403E - exp; diff --git a/source/extF80M_to_ui32.c b/source/extF80M_to_ui32.c index 72579e41..9a9a01d7 100644 --- a/source/extF80M_to_ui32.c +++ b/source/extF80M_to_ui32.c @@ -72,6 +72,7 @@ uint_fast32_t sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = aSPtr->signif; + softfloat_canonicalizeExtF80M( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x4032 - exp; diff --git a/source/extF80M_to_ui64.c b/source/extF80M_to_ui64.c index a7ee39fb..53bbdfb3 100644 --- a/source/extF80M_to_ui64.c +++ b/source/extF80M_to_ui64.c @@ -73,6 +73,7 @@ uint_fast64_t sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = aSPtr->signif; + softfloat_canonicalizeExtF80M( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x403E - exp; diff --git a/source/extF80_eq.c b/source/extF80_eq.c index 60f29daf..e2034921 100644 --- a/source/extF80_eq.c +++ b/source/extF80_eq.c @@ -65,6 +65,8 @@ bool extF80_eq( extFloat80_t a, extFloat80_t b ) } return false; } + softfloat_canonicalizeExtF80UI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80UI( &uiB64, &uiB0 ); return (uiA0 == uiB0) && ((uiA64 == uiB64) || (! uiA0 && ! ((uiA64 | uiB64) & 0x7FFF))); diff --git a/source/extF80_eq_signaling.c b/source/extF80_eq_signaling.c index 5a0dfe4a..45d8b862 100644 --- a/source/extF80_eq_signaling.c +++ b/source/extF80_eq_signaling.c @@ -59,6 +59,8 @@ bool extF80_eq_signaling( extFloat80_t a, extFloat80_t b ) softfloat_raiseFlags( softfloat_flag_invalid ); return false; } + softfloat_canonicalizeExtF80UI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80UI( &uiB64, &uiB0 ); return (uiA0 == uiB0) && ((uiA64 == uiB64) || (! uiA0 && ! ((uiA64 | uiB64) & 0x7FFF))); diff --git a/source/extF80_le.c b/source/extF80_le.c index 2a1ee60f..dd352954 100644 --- a/source/extF80_le.c +++ b/source/extF80_le.c @@ -61,6 +61,8 @@ bool extF80_le( extFloat80_t a, extFloat80_t b ) softfloat_raiseFlags( softfloat_flag_invalid ); return false; } + softfloat_canonicalizeExtF80UI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80UI( &uiB64, &uiB0 ); signA = signExtF80UI64( uiA64 ); signB = signExtF80UI64( uiB64 ); return diff --git a/source/extF80_le_quiet.c b/source/extF80_le_quiet.c index 5d0c3ae7..62309bad 100644 --- a/source/extF80_le_quiet.c +++ b/source/extF80_le_quiet.c @@ -66,6 +66,8 @@ bool extF80_le_quiet( extFloat80_t a, extFloat80_t b ) } return false; } + softfloat_canonicalizeExtF80UI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80UI( &uiB64, &uiB0 ); signA = signExtF80UI64( uiA64 ); signB = signExtF80UI64( uiB64 ); return diff --git a/source/extF80_lt.c b/source/extF80_lt.c index 9560d8ec..400ce084 100644 --- a/source/extF80_lt.c +++ b/source/extF80_lt.c @@ -61,6 +61,8 @@ bool extF80_lt( extFloat80_t a, extFloat80_t b ) softfloat_raiseFlags( softfloat_flag_invalid ); return false; } + softfloat_canonicalizeExtF80UI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80UI( &uiB64, &uiB0 ); signA = signExtF80UI64( uiA64 ); signB = signExtF80UI64( uiB64 ); return diff --git a/source/extF80_lt_quiet.c b/source/extF80_lt_quiet.c index 711652c7..d37c6a73 100644 --- a/source/extF80_lt_quiet.c +++ b/source/extF80_lt_quiet.c @@ -66,6 +66,8 @@ bool extF80_lt_quiet( extFloat80_t a, extFloat80_t b ) } return false; } + softfloat_canonicalizeExtF80UI( &uiA64, &uiA0 ); + softfloat_canonicalizeExtF80UI( &uiB64, &uiB0 ); signA = signExtF80UI64( uiA64 ); signB = signExtF80UI64( uiB64 ); return diff --git a/source/extF80_mul.c b/source/extF80_mul.c index c0c50a6c..06b48c77 100644 --- a/source/extF80_mul.c +++ b/source/extF80_mul.c @@ -56,7 +56,6 @@ extFloat80_t extF80_mul( extFloat80_t a, extFloat80_t b ) int_fast32_t expB; uint_fast64_t sigB; bool signZ; - uint_fast64_t magBits; struct exp32_sig64 normExpSig; int_fast32_t expZ; struct uint128 sig128Z, uiZ; @@ -88,13 +87,13 @@ extFloat80_t extF80_mul( extFloat80_t a, extFloat80_t b ) ) { goto propagateNaN; } - magBits = expB | sigB; - goto infArg; + if ( (expB != 0x7FFF) && ! sigB ) goto invalid; + goto infinity; } if ( expB == 0x7FFF ) { if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - magBits = expA | sigA; - goto infArg; + if ( ! sigA ) goto invalid; + goto infinity; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ @@ -134,15 +133,16 @@ extFloat80_t extF80_mul( extFloat80_t a, extFloat80_t b ) goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - } else { - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } + invalid: + softfloat_raiseFlags( softfloat_flag_invalid ); + uiZ64 = defaultNaNExtF80UI64; + uiZ0 = defaultNaNExtF80UI0; + goto uiZ; + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + infinity: + uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); + uiZ0 = UINT64_C( 0x8000000000000000 ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ diff --git a/source/extF80_rem.c b/source/extF80_rem.c index a2ebaad8..85f2310c 100644 --- a/source/extF80_rem.c +++ b/source/extF80_rem.c @@ -97,6 +97,7 @@ extFloat80_t extF80_rem( extFloat80_t a, extFloat80_t b ) | that `expDiff' later is less than -1, which will result in returning | a canonicalized version of argument a. *--------------------------------------------------------------------*/ + sigB = UINT64_C( 0x8000000000000000 ); expB += expB; } /*------------------------------------------------------------------------ diff --git a/source/extF80_sqrt.c b/source/extF80_sqrt.c index 5d328a0e..0b7964ba 100644 --- a/source/extF80_sqrt.c +++ b/source/extF80_sqrt.c @@ -78,7 +78,11 @@ extFloat80_t extF80_sqrt( extFloat80_t a ) uiZ0 = uiZ.v0; goto uiZ; } - if ( ! signA ) return a; + if ( ! signA ) { + uiZ64 = packToExtF80UI64( 0, 0x7FFF ); + uiZ0 = UINT64_C( 0x8000000000000000 ); + goto uiZ; + } goto invalid; } /*------------------------------------------------------------------------ diff --git a/source/extF80_to_f128.c b/source/extF80_to_f128.c index 7fbc9cb6..a190ac9a 100644 --- a/source/extF80_to_f128.c +++ b/source/extF80_to_f128.c @@ -46,8 +46,8 @@ float128_t extF80_to_f128( extFloat80_t a ) union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64; uint_fast64_t uiA0; - uint_fast16_t exp; - uint_fast64_t frac; + int_fast32_t exp; + uint_fast64_t sig, frac; struct commonNaN commonNaN; struct uint128 uiZ; bool sign; @@ -58,7 +58,9 @@ float128_t extF80_to_f128( extFloat80_t a ) uiA64 = uA.s.signExp; uiA0 = uA.s.signif; exp = expExtF80UI64( uiA64 ); - frac = uiA0 & UINT64_C( 0x7FFFFFFFFFFFFFFF ); + sig = uiA0; + softfloat_canonicalizeExtF80( &exp, &sig ); + frac = sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ); if ( (exp == 0x7FFF) && frac ) { softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); uiZ = softfloat_commonNaNToF128UI( &commonNaN ); diff --git a/source/extF80_to_f16.c b/source/extF80_to_f16.c index ca5050f4..8e410663 100644 --- a/source/extF80_to_f16.c +++ b/source/extF80_to_f16.c @@ -61,6 +61,7 @@ float16_t extF80_to_f16( extFloat80_t a ) sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uiA0; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { diff --git a/source/extF80_to_f32.c b/source/extF80_to_f32.c index 357f56e9..78739441 100644 --- a/source/extF80_to_f32.c +++ b/source/extF80_to_f32.c @@ -61,6 +61,7 @@ float32_t extF80_to_f32( extFloat80_t a ) sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uiA0; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { diff --git a/source/extF80_to_f64.c b/source/extF80_to_f64.c index c3873992..0716fdb5 100644 --- a/source/extF80_to_f64.c +++ b/source/extF80_to_f64.c @@ -61,6 +61,7 @@ float64_t extF80_to_f64( extFloat80_t a ) sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uiA0; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! (exp | sig) ) { diff --git a/source/extF80_to_i32.c b/source/extF80_to_i32.c index 549ca765..78ecf6ea 100644 --- a/source/extF80_to_i32.c +++ b/source/extF80_to_i32.c @@ -58,6 +58,7 @@ int_fast32_t sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) diff --git a/source/extF80_to_i32_r_minMag.c b/source/extF80_to_i32_r_minMag.c index 2b7b9e2b..13d3ce04 100644 --- a/source/extF80_to_i32_r_minMag.c +++ b/source/extF80_to_i32_r_minMag.c @@ -57,6 +57,7 @@ int_fast32_t extF80_to_i32_r_minMag( extFloat80_t a, bool exact ) uiA64 = uA.s.signExp; exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x403E - exp; diff --git a/source/extF80_to_i64.c b/source/extF80_to_i64.c index 35f55de8..9b194c36 100644 --- a/source/extF80_to_i64.c +++ b/source/extF80_to_i64.c @@ -60,6 +60,7 @@ int_fast64_t sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x403E - exp; diff --git a/source/extF80_to_i64_r_minMag.c b/source/extF80_to_i64_r_minMag.c index 215876da..a12c2546 100644 --- a/source/extF80_to_i64_r_minMag.c +++ b/source/extF80_to_i64_r_minMag.c @@ -57,6 +57,7 @@ int_fast64_t extF80_to_i64_r_minMag( extFloat80_t a, bool exact ) uiA64 = uA.s.signExp; exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x403E - exp; diff --git a/source/extF80_to_ui32.c b/source/extF80_to_ui32.c index d121c480..d193e6f0 100644 --- a/source/extF80_to_ui32.c +++ b/source/extF80_to_ui32.c @@ -58,6 +58,7 @@ uint_fast32_t sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) diff --git a/source/extF80_to_ui32_r_minMag.c b/source/extF80_to_ui32_r_minMag.c index ad304834..fb5b1465 100644 --- a/source/extF80_to_ui32_r_minMag.c +++ b/source/extF80_to_ui32_r_minMag.c @@ -57,6 +57,7 @@ uint_fast32_t extF80_to_ui32_r_minMag( extFloat80_t a, bool exact ) uiA64 = uA.s.signExp; exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x403E - exp; diff --git a/source/extF80_to_ui64.c b/source/extF80_to_ui64.c index a81bbd1b..191f5cde 100644 --- a/source/extF80_to_ui64.c +++ b/source/extF80_to_ui64.c @@ -60,6 +60,7 @@ uint_fast64_t sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x403E - exp; diff --git a/source/extF80_to_ui64_r_minMag.c b/source/extF80_to_ui64_r_minMag.c index 65adfe7e..7f658790 100644 --- a/source/extF80_to_ui64_r_minMag.c +++ b/source/extF80_to_ui64_r_minMag.c @@ -57,6 +57,7 @@ uint_fast64_t extF80_to_ui64_r_minMag( extFloat80_t a, bool exact ) uiA64 = uA.s.signExp; exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; + softfloat_canonicalizeExtF80( &exp, &sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x403E - exp; diff --git a/source/include/internals.h b/source/include/internals.h index 5e6d4bd3..3bfa52ac 100644 --- a/source/include/internals.h +++ b/source/include/internals.h @@ -162,14 +162,23 @@ float64_t #define isNaNExtF80UI( a64, a0 ) ((((a64) & 0x7FFF) == 0x7FFF) && ((a0) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) +struct exp32_sig64 { int_fast32_t exp; uint64_t sig; }; +struct exp32_sig64 softfloat_normSubnormalExtF80Sig( uint_fast64_t ); + +void + softfloat_canonicalizeExtF80( int_fast32_t *, uint_fast64_t * ); +void + softfloat_canonicalizeExtF80UI( uint_fast16_t *, uint_fast64_t * ); +void + softfloat_canonicalizeExtF80M( int32_t *, uint64_t * ); +void + softfloat_canonicalizeExtF80MUI( uint_fast16_t *, uint64_t * ); + #ifdef SOFTFLOAT_FAST_INT64 /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ -struct exp32_sig64 { int_fast32_t exp; uint64_t sig; }; -struct exp32_sig64 softfloat_normSubnormalExtF80Sig( uint_fast64_t ); - extFloat80_t softfloat_roundPackToExtF80( bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); diff --git a/source/s_addExtF80M.c b/source/s_addExtF80M.c index f0142905..343676a8 100644 --- a/source/s_addExtF80M.c +++ b/source/s_addExtF80M.c @@ -53,10 +53,11 @@ void int32_t expA; uint32_t uiB64; int32_t expB; + uint64_t sigA, sigB; uint32_t uiZ64; bool signZ, signB; const struct extFloat80M *tempSPtr; - uint64_t sigZ, sigB; + uint64_t sigZ; void (*roundPackRoutinePtr)( bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * ); @@ -69,6 +70,12 @@ void expA = expExtF80UI64( uiA64 ); uiB64 = bSPtr->signExp; expB = expExtF80UI64( uiB64 ); + sigA = aSPtr->signif; + sigB = bSPtr->signif; + softfloat_canonicalizeExtF80M( &expA, &sigA ); + softfloat_canonicalizeExtF80M( &expB, &sigB ); + uiA64 = packToExtF80UI64( signExtF80UI64( uiA64 ), expA ); + uiB64 = packToExtF80UI64( signExtF80UI64( uiB64 ), expB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { @@ -91,19 +98,21 @@ void signB = signExtF80UI64( uiB64 ) ^ negateB; negateB = (signZ != signB); if ( expA < expB ) { + int32_t tmpExp; + uint64_t tmpSig; signZ = signB; + tmpExp = expA; expA = expB; - expB = expExtF80UI64( uiA64 ); - tempSPtr = aSPtr; - aSPtr = bSPtr; - bSPtr = tempSPtr; + expB = tmpExp; + tmpSig = sigA; + sigA = sigB; + sigB = tmpSig; } if ( ! expB ) { expB = 1; if ( ! expA ) expA = 1; } - sigZ = aSPtr->signif; - sigB = bSPtr->signif; + sigZ = sigA; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundPackRoutinePtr = softfloat_roundPackMToExtF80M; diff --git a/source/s_addMagsExtF80.c b/source/s_addMagsExtF80.c index 6e7d1a6f..b4869296 100644 --- a/source/s_addMagsExtF80.c +++ b/source/s_addMagsExtF80.c @@ -69,6 +69,8 @@ extFloat80_t sigA = uiA0; expB = expExtF80UI64( uiB64 ); sigB = uiB0; + softfloat_canonicalizeExtF80( &expA, &sigA ); + softfloat_canonicalizeExtF80( &expB, &sigB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expA - expB; @@ -78,12 +80,21 @@ extFloat80_t goto propagateNaN; } uiZ64 = uiA64; - uiZ0 = uiA0; + uiZ0 = UINT64_C( 0x8000000000000000 ); goto uiZ; } sigZ = sigA + sigB; sigZExtra = 0; if ( ! expA ) { + if ( sigZ < sigA ) { + /*------------------------------------------------------------ + | Significand addition carried (e.g., two pseudo-denormals + | with J=1). Treat as effective exp=1 and fall through to + | `shiftRight1', which captures the carry. + *------------------------------------------------------------*/ + expZ = 1; + goto shiftRight1; + } normExpSig = softfloat_normSubnormalExtF80Sig( sigZ ); expZ = normExpSig.exp + 1; sigZ = normExpSig.sig; @@ -98,7 +109,7 @@ extFloat80_t if ( expB == 0x7FFF ) { if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = uiB0; + uiZ0 = UINT64_C( 0x8000000000000000 ); goto uiZ; } expZ = expB; @@ -114,7 +125,7 @@ extFloat80_t if ( expA == 0x7FFF ) { if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; uiZ64 = uiA64; - uiZ0 = uiA0; + uiZ0 = UINT64_C( 0x8000000000000000 ); goto uiZ; } expZ = expA; @@ -129,6 +140,7 @@ extFloat80_t } newlyAligned: sigZ = sigA + sigB; + if ( sigZ < sigA ) goto shiftRight1; if ( sigZ & UINT64_C( 0x8000000000000000 ) ) goto roundAndPack; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ diff --git a/source/s_canonicalizeExtF80.c b/source/s_canonicalizeExtF80.c new file mode 100644 index 00000000..c4ab5481 --- /dev/null +++ b/source/s_canonicalizeExtF80.c @@ -0,0 +1,122 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3e, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +/* This particular file was written by John Byrd. */ + +#include +#include "platform.h" +#include "internals.h" + +/*---------------------------------------------------------------------------- +| The 80-bit extended double format (extFloat80) is unique among IEEE 754 +| types in that it stores the integer bit of the significand explicitly as +| bit 63 of the 64-bit significand field, commonly called the 'J' bit. In +| all other IEEE 754 binary formats, the integer bit is implicit and +| determined solely by the exponent. Because the J bit is stored +| independently from the exponent in extFloat80, it is possible to construct +| encodings where the two are inconsistent. These inconsistent encodings +| are called "non-canonical" or, on the 8087 through 80287, "unnormal". +| Intel no longer generates non-canonical encodings, but the 80-bit format +| is still defined to accept them. +| This function rewrites the exponent '*expPtr' and significand '*sigPtr' +| of an extFloat80 value in place so that the encoding is canonical, i.e., +| the J bit is consistent with the exponent. The mathematical value +| represented by the encoding is preserved. If the encoding is already +| canonical, the values are unchanged. +| There are four classes of non-canonical encoding, each resolved as +| follows: +| +| 1. Unnormals (0 < exp < 0x7FFF, J = 0). The significand is nonzero +| but lacks its integer bit. If the significand can be left-shifted +| to set bit 63 without driving the biased exponent below 1, the value +| is renormalized. If the shift would require a biased exponent less +| than 1, the value is flushed to a denormal (exp = 0) with whatever +| significand bits survive the limited shift. If the significand is +| entirely zero, the exponent is set to 0 (encoding positive or +| negative zero, depending on the sign bit, which is not touched here). +| +| 2. Pseudo-denormals (exp = 0, J = 1). These represent the same value +| as a biased exponent of 1, so the exponent is set to 1 and the +| significand is left unchanged. +| +| 3. Pseudo-infinities (exp = 0x7FFF, J = 0, significand = 0). The +| J bit is forced to 1, producing the canonical infinity encoding. +| +| 4. Pseudo-NaNs (exp = 0x7FFF, J = 0, significand != 0). The J bit +| is forced to 1. The remaining significand bits (the NaN payload) +| are preserved, so quiet vs. signaling status is maintained. +| +| Cases 3 and 4 are handled together: when the biased exponent is +| 0x7FFF, the J bit is unconditionally set. +| +| This function does not modify the sign bit, which is not part of the +| exponent or significand fields passed here. It also does not raise any +| floating-point exception flags; canonicalization is a silent rewrite of +| the encoding only. +*----------------------------------------------------------------------------*/ +void + softfloat_canonicalizeExtF80( + int_fast32_t *expPtr, uint_fast64_t *sigPtr ) +{ + int_fast32_t exp; + uint_fast64_t sig; + struct exp32_sig64 normExpSig; + + exp = *expPtr; + sig = *sigPtr; + if ( exp == 0x7FFF ) { + *sigPtr = sig | UINT64_C( 0x8000000000000000 ); + } else if ( exp ) { + if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { + if ( ! sig ) { + *expPtr = 0; + } else { + normExpSig = softfloat_normSubnormalExtF80Sig( sig ); + if ( exp + normExpSig.exp >= 1 ) { + *expPtr = exp + normExpSig.exp; + *sigPtr = normExpSig.sig; + } else { + if ( exp > 1 ) *sigPtr = sig << (exp - 1); + *expPtr = 0; + } + } + } + } else { + if ( sig & UINT64_C( 0x8000000000000000 ) ) + *expPtr = 1; + } + +} diff --git a/source/s_canonicalizeExtF80M.c b/source/s_canonicalizeExtF80M.c new file mode 100644 index 00000000..ab10f0d2 --- /dev/null +++ b/source/s_canonicalizeExtF80M.c @@ -0,0 +1,81 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3e, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +/* This particular file was written by John Byrd. */ + +#include +#include "platform.h" +#include "internals.h" + +/*---------------------------------------------------------------------------- +| Equivalent to 'softfloat_canonicalizeExtF80' (see s_canonicalizeExtF80.c +| for the full description of extFloat80 non-canonical encodings and the +| canonicalization rules), but using 'int32_t' and 'uint64_t' parameter +| types to match the non-FAST_INT64 code paths. The algorithm and behavior +| are identical. +*----------------------------------------------------------------------------*/ +void + softfloat_canonicalizeExtF80M( int32_t *expPtr, uint64_t *sigPtr ) +{ + int32_t exp; + uint64_t sig; + struct exp32_sig64 normExpSig; + + exp = *expPtr; + sig = *sigPtr; + if ( exp == 0x7FFF ) { + *sigPtr = sig | UINT64_C( 0x8000000000000000 ); + } else if ( exp ) { + if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { + if ( ! sig ) { + *expPtr = 0; + } else { + normExpSig = softfloat_normSubnormalExtF80Sig( sig ); + if ( exp + normExpSig.exp >= 1 ) { + *expPtr = exp + normExpSig.exp; + *sigPtr = normExpSig.sig; + } else { + if ( exp > 1 ) *sigPtr = sig << (exp - 1); + *expPtr = 0; + } + } + } + } else { + if ( sig & UINT64_C( 0x8000000000000000 ) ) + *expPtr = 1; + } + +} diff --git a/source/s_canonicalizeExtF80MUI.c b/source/s_canonicalizeExtF80MUI.c new file mode 100644 index 00000000..0de3b7fc --- /dev/null +++ b/source/s_canonicalizeExtF80MUI.c @@ -0,0 +1,62 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3e, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +/* This particular file was written by John Byrd. */ + +#include +#include "platform.h" +#include "internals.h" + +/*---------------------------------------------------------------------------- +| Canonicalizes an extFloat80 value whose exponent and sign are stored in the +| packed 'signExp' layout used by the non-FAST_INT64 comparison functions. +| The packed 16-bit field '*signExpPtr' holds the sign in bit 15 and the +| 15-bit biased exponent in bits 14:0. This function extracts the exponent, +| passes it along with '*sigPtr' to 'softfloat_canonicalizeExtF80M' (see +| s_canonicalizeExtF80.c for the full canonicalization rules), and repacks +| the possibly-modified exponent back into '*signExpPtr' with the original +| sign bit preserved. +*----------------------------------------------------------------------------*/ +void + softfloat_canonicalizeExtF80MUI( + uint_fast16_t *signExpPtr, uint64_t *sigPtr ) +{ + int32_t exp = expExtF80UI64( *signExpPtr ); + + softfloat_canonicalizeExtF80M( &exp, sigPtr ); + *signExpPtr = packToExtF80UI64( signExtF80UI64( *signExpPtr ), exp ); + +} diff --git a/source/s_canonicalizeExtF80UI.c b/source/s_canonicalizeExtF80UI.c new file mode 100644 index 00000000..dbc1ea34 --- /dev/null +++ b/source/s_canonicalizeExtF80UI.c @@ -0,0 +1,62 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3e, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +/* This particular file was written by John Byrd. */ + +#include +#include "platform.h" +#include "internals.h" + +/*---------------------------------------------------------------------------- +| Canonicalizes an extFloat80 value whose exponent and sign are stored in the +| packed 'signExp' layout used by the FAST_INT64 comparison functions. The +| packed 16-bit field '*signExpPtr' holds the sign in bit 15 and the 15-bit +| biased exponent in bits 14:0. This function extracts the exponent, passes +| it along with '*sigPtr' to 'softfloat_canonicalizeExtF80' (see +| s_canonicalizeExtF80.c for the full canonicalization rules), and repacks +| the possibly-modified exponent back into '*signExpPtr' with the original +| sign bit preserved. +*----------------------------------------------------------------------------*/ +void + softfloat_canonicalizeExtF80UI( + uint_fast16_t *signExpPtr, uint_fast64_t *sigPtr ) +{ + int_fast32_t exp = *signExpPtr & 0x7FFF; + + softfloat_canonicalizeExtF80( &exp, sigPtr ); + *signExpPtr = (*signExpPtr & 0x8000) | exp; + +} diff --git a/source/s_compareNonnormExtF80M.c b/source/s_compareNonnormExtF80M.c index 6712e576..4d6b9833 100644 --- a/source/s_compareNonnormExtF80M.c +++ b/source/s_compareNonnormExtF80M.c @@ -56,16 +56,16 @@ int sigA = aSPtr->signif; signB = signExtF80UI64( uiB64 ); sigB = bSPtr->signif; + expA = expExtF80UI64( uiA64 ); + expB = expExtF80UI64( uiB64 ); + softfloat_canonicalizeExtF80M( &expA, &sigA ); + softfloat_canonicalizeExtF80M( &expB, &sigB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( (uiA64 ^ uiB64) & 0x8000 ) { if ( ! (sigA | sigB) ) return 0; goto resultFromSignB; } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expExtF80UI64( uiA64 ); - expB = expExtF80UI64( uiB64 ); if ( expA == 0x7FFF ) { if (expB == 0x7FFF) return 0; signB = ! signB; diff --git a/source/s_subMagsExtF80.c b/source/s_subMagsExtF80.c index 86ffd9b8..1a2ec530 100644 --- a/source/s_subMagsExtF80.c +++ b/source/s_subMagsExtF80.c @@ -68,6 +68,8 @@ extFloat80_t sigA = uiA0; expB = expExtF80UI64( uiB64 ); sigB = uiB0; + softfloat_canonicalizeExtF80( &expA, &sigA ); + softfloat_canonicalizeExtF80( &expB, &sigB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expA - expB; @@ -112,6 +114,12 @@ extFloat80_t sigExtra = sig128.v0; newlyAlignedBBigger: expZ = expB; + if ( sigA < sigB ) goto bBigger; + if ( sigB < sigA ) goto aBigger; + uiZ64 = + packToExtF80UI64( (softfloat_roundingMode == softfloat_round_min), 0 ); + uiZ0 = 0; + goto uiZ; bBigger: signZ = ! signZ; sig128 = softfloat_sub128( sigB, 0, sigA, sigExtra ); @@ -122,7 +130,7 @@ extFloat80_t if ( expA == 0x7FFF ) { if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; uiZ64 = uiA64; - uiZ0 = uiA0; + uiZ0 = UINT64_C( 0x8000000000000000 ); goto uiZ; } if ( ! expB ) { @@ -135,6 +143,12 @@ extFloat80_t sigExtra = sig128.v0; newlyAlignedABigger: expZ = expA; + if ( sigB < sigA ) goto aBigger; + if ( sigA < sigB ) goto bBigger; + uiZ64 = + packToExtF80UI64( (softfloat_roundingMode == softfloat_round_min), 0 ); + uiZ0 = 0; + goto uiZ; aBigger: sig128 = softfloat_sub128( sigA, 0, sigB, sigExtra ); /*------------------------------------------------------------------------