summaryrefslogtreecommitdiffstats
path: root/src/libs/softfloat-3e/source/s_roundPackToExtF80.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/softfloat-3e/source/s_roundPackToExtF80.c')
-rw-r--r--src/libs/softfloat-3e/source/s_roundPackToExtF80.c370
1 files changed, 370 insertions, 0 deletions
diff --git a/src/libs/softfloat-3e/source/s_roundPackToExtF80.c b/src/libs/softfloat-3e/source/s_roundPackToExtF80.c
new file mode 100644
index 00000000..77d004ab
--- /dev/null
+++ b/src/libs/softfloat-3e/source/s_roundPackToExtF80.c
@@ -0,0 +1,370 @@
+
+/*============================================================================
+
+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, 2015, 2017 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.
+
+=============================================================================*/
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+#include <iprt/types.h> /* VBox: RTFLOAT80U_EXP_BIAS_ADJUST */
+#include <iprt/assert.h>
+
+static extFloat80_t
+ softfloat_roundPackToExtF80Inner(
+ bool sign,
+ int_fast32_t exp,
+ uint_fast64_t sig,
+ uint_fast64_t sigExtra,
+ uint_fast8_t roundingPrecision
+ SOFTFLOAT_STATE_DECL_COMMA
+ )
+{
+ uint_fast8_t roundingMode;
+ bool roundNearEven;
+ uint_fast64_t roundIncrement, roundMask, roundBits;
+ bool isTiny, doIncrement = 0;
+ struct uint64_extra sig64Extra;
+ union { struct extFloat80M s; extFloat80_t f; } uZ;
+ //RTAssertMsg2("softfloat_roundPackToExtF80: exp=%d sig=%RX64 sigExtra=%RX64 rp=%d\n", exp, sig, sigExtra, roundingPrecision);
+
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ roundingMode = softfloat_roundingMode;
+ roundNearEven = (roundingMode == softfloat_round_near_even);
+ if ( roundingPrecision == 80 ) goto precision80;
+ if ( roundingPrecision == 64 ) {
+ roundIncrement = UINT64_C( 0x0000000000000400 );
+ roundMask = UINT64_C( 0x00000000000007FF );
+ } else if ( roundingPrecision == 32 ) {
+ roundIncrement = UINT64_C( 0x0000008000000000 );
+ roundMask = UINT64_C( 0x000000FFFFFFFFFF );
+ } else {
+ goto precision80;
+ }
+ sig |= (sigExtra != 0);
+ if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
+ roundIncrement =
+ (roundingMode
+ == (sign ? softfloat_round_min : softfloat_round_max))
+ ? roundMask
+ : 0;
+ }
+ roundBits = sig & roundMask;
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
+ if ( exp <= 0 ) {
+ /*----------------------------------------------------------------
+ *----------------------------------------------------------------*/
+ isTiny =
+ (softfloat_detectTininess
+ == softfloat_tininess_beforeRounding)
+ || (exp < 0)
+ || (sig <= (uint64_t) (sig + roundIncrement));
+ sig = softfloat_shiftRightJam64(sig, 1 - exp);
+ uint64_t const uOldSig = sig; /* VBox: C1 */
+ roundBits = sig & roundMask;
+ if ( roundBits ) {
+ if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow SOFTFLOAT_STATE_ARG_COMMA );
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+#ifdef SOFTFLOAT_ROUND_ODD
+ if ( roundingMode == softfloat_round_odd ) {
+ sig |= roundMask + 1;
+ }
+#endif
+ }
+ sig += roundIncrement;
+ exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
+ roundIncrement = roundMask + 1;
+ if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
+ roundMask |= roundIncrement;
+ }
+ sig &= ~roundMask;
+ if ( sig > uOldSig ) { /* VBox: C1 */
+ softfloat_exceptionFlags |= softfloat_flag_c1; /* VBox: C1 */
+ //RTAssertMsg2("softfloat_roundPackToExtF80: C1 #1\n"); /* VBox: C1 */
+ } /* VBox: C1 */
+ goto packReturn;
+ }
+ if (
+ (0x7FFE < exp)
+ || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig))
+ ) {
+ goto overflow;
+ }
+ }
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ { /* VBox: C1 */
+ uint64_t const uOldSig = sig; /* VBox: C1 */
+ if ( roundBits ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+#ifdef SOFTFLOAT_ROUND_ODD
+ if ( roundingMode == softfloat_round_odd ) {
+ sig = (sig & ~roundMask) | (roundMask + 1);
+ if ( sig > uOldSig ) { /* VBox: C1 */
+ softfloat_exceptionFlags |= softfloat_flag_c1; /* VBox: C1 */
+ //RTAssertMsg2("softfloat_roundPackToExtF80: C1 #2\n"); /* VBox: C1 */
+ } /* VBox: C1 */
+ goto packReturn;
+ }
+#endif
+ }
+ sig = (uint64_t) (sig + roundIncrement);
+ if ( sig < roundIncrement ) {
+ ++exp;
+ sig = UINT64_C( 0x8000000000000000 );
+ softfloat_exceptionFlags |= softfloat_flag_c1; /* VBox: C1 */
+ //RTAssertMsg2("softfloat_roundPackToExtF80: C1 #3\n"); /* VBox: C1 */
+ }
+ roundIncrement = roundMask + 1;
+ if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
+ roundMask |= roundIncrement;
+ }
+ sig &= ~roundMask;
+ if ( sig > uOldSig ) { /* VBox: C1 */
+ softfloat_exceptionFlags |= softfloat_flag_c1; /* VBox: C1 */
+ //RTAssertMsg2("softfloat_roundPackToExtF80: C1 #4\n"); /* VBox: C1 */
+ } /* VBox: C1 */
+ goto packReturn;
+ } /* VBox: C1 */
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ precision80:
+ doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra);
+ if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
+ doIncrement =
+ (roundingMode
+ == (sign ? softfloat_round_min : softfloat_round_max))
+ && sigExtra;
+ }
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
+ if ( exp <= 0 ) {
+ /*----------------------------------------------------------------
+ *----------------------------------------------------------------*/
+ isTiny =
+ (softfloat_detectTininess
+ == softfloat_tininess_beforeRounding)
+ || (exp < 0)
+ || ! doIncrement
+ || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF ));
+//RTAssertMsg2("softfloat_roundPackToExtF80: #2: sig=%#RX64 sigExtra=%#RX64 isTiny=%d exp=%d 1-exp=%d\n", sig, sigExtra, isTiny, exp, 1-exp);
+ sig64Extra =
+ softfloat_shiftRightJam64Extra( sig, sigExtra, 1 - exp );
+ if ( (exp < -63 || sig64Extra.extra != 0) /* VBox: Missing inexact result flag */
+ && ( sig != 0 || sigExtra != 0 ) /*!zero*/ ) { /* VBox: Missing inexact result flag */
+ softfloat_exceptionFlags |= softfloat_flag_inexact; /* VBox: Missing inexact result flag */
+ } /* VBox: Missing inexact result flag */
+ exp = 0;
+ sig = sig64Extra.v;
+ sigExtra = sig64Extra.extra;
+//RTAssertMsg2("softfloat_roundPackToExtF80: #3: sig=%#RX64 sigExtra=%#RX64 isTiny=%d\n", sig, sigExtra, isTiny);
+ if ( sigExtra
+ || ( !(pState->exceptionMask & softfloat_flag_underflow) /* VBox: Unmasked underflow conditions differ */
+ && (sig != 0 || sigExtra != 0) /*zero*/ ) ) { /* VBox: Unmasked underflow conditions differ */
+ if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow SOFTFLOAT_STATE_ARG_COMMA );
+#ifdef SOFTFLOAT_ROUND_ODD
+ if ( roundingMode == softfloat_round_odd ) {
+ sig |= 1;
+ goto packReturn;
+ }
+#endif
+ }
+ doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra);
+ if (
+ ! roundNearEven
+ && (roundingMode != softfloat_round_near_maxMag)
+ ) {
+ doIncrement =
+ (roundingMode
+ == (sign ? softfloat_round_min : softfloat_round_max))
+ && sigExtra;
+ }
+ if ( doIncrement ) {
+ uint64_t const uOldSig = sig; /* VBox: C1 */
+ ++sig;
+ sig &=
+ ~(uint_fast64_t)
+ (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF ))
+ & roundNearEven);
+ if (sig > uOldSig) { /* VBox: C1 */
+ softfloat_exceptionFlags |= softfloat_flag_c1; /* VBox: C1 */
+ //RTAssertMsg2("softfloat_roundPackToExtF80: C1 #5\n"); /* VBox: C1 */
+ } /* VBox: C1 */
+ exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
+ }
+ goto packReturn;
+ }
+ if (
+ (0x7FFE < exp)
+ || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF ))
+ && doIncrement)
+ ) {
+ /*----------------------------------------------------------------
+ *----------------------------------------------------------------*/
+ roundMask = 0;
+ overflow:
+ softfloat_raiseFlags(
+ softfloat_flag_overflow | softfloat_flag_inexact
+ SOFTFLOAT_STATE_ARG_COMMA );
+ if (
+ roundNearEven
+ || (roundingMode == softfloat_round_near_maxMag)
+ || (roundingMode
+ == (sign ? softfloat_round_min : softfloat_round_max))
+ ) {
+ exp = 0x7FFF;
+ sig = UINT64_C( 0x8000000000000000 );
+ softfloat_exceptionFlags |= softfloat_flag_c1; /* Inf means rounding up */ /* VBox: C1 */
+ //RTAssertMsg2("softfloat_roundPackToExtF80: C1 #6\n"); /* VBox: C1 */
+ } else {
+ exp = 0x7FFE;
+ sig = ~roundMask;
+ }
+ goto packReturn;
+ }
+ }
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ if ( sigExtra ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+#ifdef SOFTFLOAT_ROUND_ODD
+ if ( roundingMode == softfloat_round_odd ) {
+ sig |= 1;
+ goto packReturn;
+ }
+#endif
+ }
+ if ( doIncrement ) {
+ uint64_t const uOldSig = sig; /* VBox */
+ ++sig;
+ if ( ! sig ) {
+ ++exp;
+ sig = UINT64_C( 0x8000000000000000 );
+ softfloat_exceptionFlags |= softfloat_flag_c1; /* VBox: C1 */
+ //RTAssertMsg2("softfloat_roundPackToExtF80: C1 #7\n"); /* VBox: C1 */
+ } else {
+ sig &=
+ ~(uint_fast64_t)
+ (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF ))
+ & roundNearEven);
+ if ( sig > uOldSig ) { /* VBox: C1 */
+ softfloat_exceptionFlags |= softfloat_flag_c1; /* VBox: C1 */
+ //RTAssertMsg2("softfloat_roundPackToExtF80: C1 #8\n"); /* VBox: C1 */
+ }
+ }
+ }
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ packReturn:
+ uZ.s.signExp = packToExtF80UI64( sign, exp );
+ uZ.s.signif = sig;
+ return uZ.f;
+
+}
+
+/**
+ * VBox: Wrapper for implementing underflow and overflow bias adjustment.
+ */
+extFloat80_t
+ softfloat_roundPackToExtF80(
+ bool sign,
+ int_fast32_t exp,
+ uint_fast64_t sig,
+ uint_fast64_t sigExtra,
+ uint_fast8_t roundingPrecision
+ SOFTFLOAT_STATE_DECL_COMMA
+ )
+{
+ static union extF80M_extF80 const s_aExtF80Zero[2] =
+ {
+ EXTF80M_EXTF80_INIT3_C( 0, 0, 0 ), EXTF80M_EXTF80_INIT3_C( 1, 0, 0 ),
+ };
+ static union extF80M_extF80 const s_aExtF80Infinity[2] =
+ {
+ EXTF80M_EXTF80_INIT3( 0, RT_BIT_64( 63 ), RTFLOAT80U_EXP_MAX ),
+ EXTF80M_EXTF80_INIT3( 1, RT_BIT_64( 63 ), RTFLOAT80U_EXP_MAX ),
+ };
+
+ uint8_t const exceptionFlagsSaved = softfloat_exceptionFlags;
+ softfloat_exceptionFlags = 0;
+ extFloat80_t r80Result = softfloat_roundPackToExtF80Inner( sign, exp, sig, sigExtra, roundingPrecision, pState );
+ if ( !(softfloat_exceptionFlags & ~pState->exceptionMask & (softfloat_flag_underflow | softfloat_flag_overflow)) ) {
+ /* Denormals are fun, because they don't cause #U when masked, and the inner
+ code here assume it's always masked. So, detect denormals and check if it
+ was masked or not, in the latter case do bias adjust. */
+ if ( (r80Result.signif & RT_BIT_64( 63 ))
+ || !r80Result.signif
+ || (pState->exceptionMask & softfloat_flag_underflow) ) {
+ softfloat_exceptionFlags |= exceptionFlagsSaved;
+ return r80Result;
+ }
+
+ /* Denormal and underflow not masked, need to adjust the exponent bias
+ to match 387 behaviour. */
+ Assert( expExtF80UI64( r80Result.signExp ) == 0 );
+ softfloat_exceptionFlags |= softfloat_flag_underflow;
+ }
+
+ /* On Intel 10980XE the FSCALE instruction can cause really large exponents
+ and the rounding changes when we exceed the bias adjust. */
+ if (exp >= RTFLOAT80U_EXP_BIAS_ADJUST + RTFLOAT80U_EXP_MAX) {
+ Assert( softfloat_exceptionFlags & softfloat_flag_overflow );
+ softfloat_exceptionFlags |= softfloat_flag_inexact | softfloat_flag_c1;
+ r80Result = s_aExtF80Infinity[sign].f;
+ } else if (exp <= -RTFLOAT80U_EXP_BIAS_ADJUST) {
+ Assert( softfloat_exceptionFlags & softfloat_flag_underflow );
+ softfloat_exceptionFlags &= ~softfloat_flag_c1;
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ r80Result = s_aExtF80Zero[sign].f;
+ } else {
+ /* Redo the conversion with the bias applied. */
+ softfloat_exceptionFlags &= softfloat_flag_underflow | softfloat_flag_overflow;
+ if ( softfloat_exceptionFlags & softfloat_flag_underflow ) {
+ exp += RTFLOAT80U_EXP_BIAS_ADJUST;
+ Assert( exp > 0 );
+ } else {
+ exp -= RTFLOAT80U_EXP_BIAS_ADJUST;
+ Assert( exp < RTFLOAT80U_EXP_MAX );
+ }
+ r80Result = softfloat_roundPackToExtF80Inner( sign, exp, sig, sigExtra, roundingPrecision, pState );
+ }
+ softfloat_exceptionFlags |= exceptionFlagsSaved;
+ return r80Result;
+}
+