/*============================================================================ This C source file is part of TestFloat, Release 3b, a package of programs for testing the correctness of floating-point arithmetic complying with the IEEE Standard for Floating-Point, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 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 #include #include "platform.h" #include "uint128.h" #include "softfloat.h" #include "slowfloat.h" uint_fast8_t slowfloat_roundingMode; uint_fast8_t slowfloat_detectTininess; uint_fast8_t slowfloat_exceptionFlags; #ifdef EXTFLOAT80 uint_fast8_t slow_extF80_roundingPrecision; #endif #ifdef FLOAT16 union ui16_f16 { uint16_t ui; float16_t f; }; #endif union ui32_f32 { uint32_t ui; float32_t f; }; union ui64_f64 { uint64_t ui; float64_t f; }; /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ struct floatX { bool isNaN; bool isInf; bool isZero; bool sign; int_fast32_t exp; struct uint128 sig; }; static const struct floatX floatXNaN = { true, false, false, false, 0, { 0, 0 } }; static const struct floatX floatXPositiveZero = { false, false, true, false, 0, { 0, 0 } }; static const struct floatX floatXNegativeZero = { false, false, true, true, 0, { 0, 0 } }; static void roundFloatXTo11( bool isTiny, struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { uint_fast64_t roundBits, sigX64; sigX64 = xPtr->sig.v64; roundBits = (sigX64 & UINT64_C( 0x1FFFFFFFFFFF )) | (xPtr->sig.v0 != 0); if ( roundBits ) { sigX64 &= UINT64_C( 0xFFFFE00000000000 ); if ( exact ) slowfloat_exceptionFlags |= softfloat_flag_inexact; if ( isTiny ) slowfloat_exceptionFlags |= softfloat_flag_underflow; switch ( roundingMode ) { case softfloat_round_near_even: if ( roundBits < UINT64_C( 0x100000000000 ) ) goto noIncrement; if ( (roundBits == UINT64_C( 0x100000000000 )) && ! (sigX64 & UINT64_C( 0x200000000000 )) ) { goto noIncrement; } break; case softfloat_round_minMag: goto noIncrement; case softfloat_round_min: if ( ! xPtr->sign ) goto noIncrement; break; case softfloat_round_max: if ( xPtr->sign ) goto noIncrement; break; case softfloat_round_near_maxMag: if ( roundBits < UINT64_C( 0x100000000000 ) ) goto noIncrement; break; } sigX64 += UINT64_C( 0x200000000000 ); if ( sigX64 == UINT64_C( 0x0100000000000000 ) ) { ++xPtr->exp; sigX64 = UINT64_C( 0x0080000000000000 ); } noIncrement: xPtr->sig.v64 = sigX64; xPtr->sig.v0 = 0; } } static void roundFloatXTo24( bool isTiny, struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { uint_fast64_t sigX64; uint_fast32_t roundBits; sigX64 = xPtr->sig.v64; roundBits = (uint32_t) sigX64 | (xPtr->sig.v0 != 0); if ( roundBits ) { sigX64 &= UINT64_C( 0xFFFFFFFF00000000 ); if ( exact ) slowfloat_exceptionFlags |= softfloat_flag_inexact; if ( isTiny ) slowfloat_exceptionFlags |= softfloat_flag_underflow; switch ( roundingMode ) { case softfloat_round_near_even: if ( roundBits < 0x80000000 ) goto noIncrement; if ( (roundBits == 0x80000000) && ! (sigX64 & UINT64_C( 0x100000000 )) ) { goto noIncrement; } break; case softfloat_round_minMag: goto noIncrement; case softfloat_round_min: if ( ! xPtr->sign ) goto noIncrement; break; case softfloat_round_max: if ( xPtr->sign ) goto noIncrement; break; case softfloat_round_near_maxMag: if ( roundBits < 0x80000000 ) goto noIncrement; break; } sigX64 += UINT64_C( 0x100000000 ); if ( sigX64 == UINT64_C( 0x0100000000000000 ) ) { ++xPtr->exp; sigX64 = UINT64_C( 0x0080000000000000 ); } noIncrement: xPtr->sig.v64 = sigX64; xPtr->sig.v0 = 0; } } static void roundFloatXTo53( bool isTiny, struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { uint_fast64_t sigX64; uint_fast8_t roundBits; sigX64 = xPtr->sig.v64; roundBits = (sigX64 & 7) | (xPtr->sig.v0 != 0); if ( roundBits ) { sigX64 &= UINT64_C( 0xFFFFFFFFFFFFFFF8 ); if ( exact ) slowfloat_exceptionFlags |= softfloat_flag_inexact; if ( isTiny ) slowfloat_exceptionFlags |= softfloat_flag_underflow; switch ( roundingMode ) { case softfloat_round_near_even: if ( roundBits < 4 ) goto noIncrement; if ( (roundBits == 4) && ! (sigX64 & 8) ) goto noIncrement; break; case softfloat_round_minMag: goto noIncrement; case softfloat_round_min: if ( ! xPtr->sign ) goto noIncrement; break; case softfloat_round_max: if ( xPtr->sign ) goto noIncrement; break; case softfloat_round_near_maxMag: if ( roundBits < 4 ) goto noIncrement; break; } sigX64 += 8; if ( sigX64 == UINT64_C( 0x0100000000000000 ) ) { ++xPtr->exp; sigX64 = UINT64_C( 0x0080000000000000 ); } noIncrement: xPtr->sig.v64 = sigX64; xPtr->sig.v0 = 0; } } static void roundFloatXTo64( bool isTiny, struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { uint_fast64_t sigX0, roundBits, sigX64; sigX0 = xPtr->sig.v0; roundBits = sigX0 & UINT64_C( 0x00FFFFFFFFFFFFFF ); if ( roundBits ) { sigX0 &= UINT64_C( 0xFF00000000000000 ); if ( exact ) slowfloat_exceptionFlags |= softfloat_flag_inexact; if ( isTiny ) slowfloat_exceptionFlags |= softfloat_flag_underflow; switch ( roundingMode ) { case softfloat_round_near_even: if ( roundBits < UINT64_C( 0x0080000000000000 ) ) goto noIncrement; if ( (roundBits == UINT64_C( 0x0080000000000000 )) && ! (sigX0 & UINT64_C( 0x0100000000000000 )) ) { goto noIncrement; } break; case softfloat_round_minMag: goto noIncrement; case softfloat_round_min: if ( ! xPtr->sign ) goto noIncrement; break; case softfloat_round_max: if ( xPtr->sign ) goto noIncrement; break; case softfloat_round_near_maxMag: if ( roundBits < UINT64_C( 0x0080000000000000 ) ) goto noIncrement; break; } sigX0 += UINT64_C( 0x0100000000000000 ); sigX64 = xPtr->sig.v64 + ! sigX0; if ( sigX64 == UINT64_C( 0x0100000000000000 ) ) { ++xPtr->exp; sigX64 = UINT64_C( 0x0080000000000000 ); } xPtr->sig.v64 = sigX64; noIncrement: xPtr->sig.v0 = sigX0; } } static void roundFloatXTo113( bool isTiny, struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { uint_fast64_t sigX0; uint_fast8_t roundBits; uint_fast64_t sigX64; sigX0 = xPtr->sig.v0; roundBits = sigX0 & 0x7F; if ( roundBits ) { sigX0 &= UINT64_C( 0xFFFFFFFFFFFFFF80 ); if ( exact ) slowfloat_exceptionFlags |= softfloat_flag_inexact; if ( isTiny ) slowfloat_exceptionFlags |= softfloat_flag_underflow; switch ( roundingMode ) { case softfloat_round_near_even: if ( roundBits < 0x40 ) goto noIncrement; if ( (roundBits == 0x40) && ! (sigX0 & 0x80) ) goto noIncrement; break; case softfloat_round_minMag: goto noIncrement; case softfloat_round_min: if ( ! xPtr->sign ) goto noIncrement; break; case softfloat_round_max: if ( xPtr->sign ) goto noIncrement; break; case softfloat_round_near_maxMag: if ( roundBits < 0x40 ) goto noIncrement; break; } sigX0 += 0x80; sigX64 = xPtr->sig.v64 + ! sigX0; if ( sigX64 == UINT64_C( 0x0100000000000000 ) ) { ++xPtr->exp; sigX64 = UINT64_C( 0x0080000000000000 ); } xPtr->sig.v64 = sigX64; noIncrement: xPtr->sig.v0 = sigX0; } } static void ui32ToFloatX( uint_fast32_t a, struct floatX *xPtr ) { uint_fast64_t sig64; int_fast32_t exp; xPtr->isNaN = false; xPtr->isInf = false; xPtr->sign = false; sig64 = a; if ( a ) { xPtr->isZero = false; exp = 31; sig64 <<= 24; while ( sig64 < UINT64_C( 0x0080000000000000 ) ) { --exp; sig64 <<= 1; } xPtr->exp = exp; } else { xPtr->isZero = true; } xPtr->sig.v64 = sig64; xPtr->sig.v0 = 0; } static uint_fast32_t floatXToUI32( const struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { uint_fast8_t savedExceptionFlags; struct floatX x; int_fast32_t shiftDist; uint_fast32_t z; if ( xPtr->isInf || xPtr->isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; return (xPtr->isInf && xPtr->sign) ? 0 : 0xFFFFFFFF; } if ( xPtr->isZero ) return 0; savedExceptionFlags = slowfloat_exceptionFlags; x = *xPtr; shiftDist = 52 - x.exp; if ( 56 < shiftDist ) { x.sig.v64 = 0; x.sig.v0 = 1; } else { while ( 0 < shiftDist ) { x.sig = shortShiftRightJam128( x.sig, 1 ); --shiftDist; } } roundFloatXTo53( false, &x, roundingMode, exact ); x.sig = shortShiftRightJam128( x.sig, 3 ); z = x.sig.v64; if ( (shiftDist < 0) || x.sig.v64>>32 || (x.sign && z) ) { slowfloat_exceptionFlags = savedExceptionFlags | softfloat_flag_invalid; return x.sign ? 0 : 0xFFFFFFFF; } return z; } static void ui64ToFloatX( uint_fast64_t a, struct floatX *xPtr ) { struct uint128 sig; int_fast32_t exp; xPtr->isNaN = false; xPtr->isInf = false; xPtr->sign = false; sig.v64 = 0; sig.v0 = a; if ( a ) { xPtr->isZero = false; exp = 63; sig = shortShiftLeft128( sig, 56 ); while ( sig.v64 < UINT64_C( 0x0080000000000000 ) ) { --exp; sig = shortShiftLeft128( sig, 1 ); } xPtr->exp = exp; } else { xPtr->isZero = true; } xPtr->sig = sig; } static uint_fast64_t floatXToUI64( const struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { uint_fast8_t savedExceptionFlags; struct floatX x; int_fast32_t shiftDist; uint_fast64_t z; if ( xPtr->isInf || xPtr->isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; return (xPtr->isInf && xPtr->sign) ? 0 : UINT64_C( 0xFFFFFFFFFFFFFFFF ); } if ( xPtr->isZero ) return 0; savedExceptionFlags = slowfloat_exceptionFlags; x = *xPtr; shiftDist = 112 - x.exp; if ( 116 < shiftDist ) { x.sig.v64 = 0; x.sig.v0 = 1; } else { while ( 0 < shiftDist ) { x.sig = shortShiftRightJam128( x.sig, 1 ); --shiftDist; } } roundFloatXTo113( false, &x, roundingMode, exact ); x.sig = shortShiftRightJam128( x.sig, 7 ); z = x.sig.v0; if ( (shiftDist < 0) || x.sig.v64 || (x.sign && z) ) { slowfloat_exceptionFlags = savedExceptionFlags | softfloat_flag_invalid; return x.sign ? 0 : UINT64_C( 0xFFFFFFFFFFFFFFFF ); } return z; } static void i32ToFloatX( int_fast32_t a, struct floatX *xPtr ) { bool sign; uint_fast64_t sig64; int_fast32_t exp; xPtr->isNaN = false; xPtr->isInf = false; sign = (a < 0); xPtr->sign = sign; sig64 = sign ? -(uint64_t) a : a; if ( a ) { xPtr->isZero = false; exp = 31; sig64 <<= 24; while ( sig64 < UINT64_C( 0x0080000000000000 ) ) { --exp; sig64 <<= 1; } xPtr->exp = exp; } else { xPtr->isZero = true; } xPtr->sig.v64 = sig64; xPtr->sig.v0 = 0; } static int_fast32_t floatXToI32( const struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { uint_fast8_t savedExceptionFlags; struct floatX x; int_fast32_t shiftDist; union { uint32_t ui; int32_t i; } uZ; if ( xPtr->isInf || xPtr->isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; return (xPtr->isInf && xPtr->sign) ? -0x7FFFFFFF - 1 : 0x7FFFFFFF; } if ( xPtr->isZero ) return 0; savedExceptionFlags = slowfloat_exceptionFlags; x = *xPtr; shiftDist = 52 - x.exp; if ( 56 < shiftDist ) { x.sig.v64 = 0; x.sig.v0 = 1; } else { while ( 0 < shiftDist ) { x.sig = shortShiftRightJam128( x.sig, 1 ); --shiftDist; } } roundFloatXTo53( false, &x, roundingMode, exact ); x.sig = shortShiftRightJam128( x.sig, 3 ); uZ.ui = x.sig.v64; if ( x.sign ) uZ.ui = -uZ.ui; if ( (shiftDist < 0) || x.sig.v64>>32 || ((uZ.i != 0) && (x.sign != (uZ.i < 0))) ) { slowfloat_exceptionFlags = savedExceptionFlags | softfloat_flag_invalid; return x.sign ? -0x7FFFFFFF - 1 : 0x7FFFFFFF; } return uZ.i; } static void i64ToFloatX( int_fast64_t a, struct floatX *xPtr ) { bool sign; struct uint128 sig; int_fast32_t exp; xPtr->isNaN = false; xPtr->isInf = false; sign = (a < 0); xPtr->sign = sign; sig.v64 = 0; sig.v0 = sign ? -(uint_fast64_t) a : a; if ( a ) { xPtr->isZero = false; exp = 63; sig = shortShiftLeft128( sig, 56 ); while ( sig.v64 < UINT64_C( 0x0080000000000000 ) ) { --exp; sig = shortShiftLeft128( sig, 1 ); } xPtr->exp = exp; } else { xPtr->isZero = true; } xPtr->sig = sig; } static int_fast64_t floatXToI64( const struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { uint_fast8_t savedExceptionFlags; struct floatX x; int_fast32_t shiftDist; union { uint64_t ui; int64_t i; } uZ; if ( xPtr->isInf || xPtr->isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; return (xPtr->isInf && xPtr->sign) ? -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1 : INT64_C( 0x7FFFFFFFFFFFFFFF ); } if ( xPtr->isZero ) return 0; savedExceptionFlags = slowfloat_exceptionFlags; x = *xPtr; shiftDist = 112 - x.exp; if ( 116 < shiftDist ) { x.sig.v64 = 0; x.sig.v0 = 1; } else { while ( 0 < shiftDist ) { x.sig = shortShiftRightJam128( x.sig, 1 ); --shiftDist; } } roundFloatXTo113( false, &x, roundingMode, exact ); x.sig = shortShiftRightJam128( x.sig, 7 ); uZ.ui = x.sig.v0; if ( x.sign ) uZ.ui = -uZ.ui; if ( (shiftDist < 0) || x.sig.v64 || ((uZ.i != 0) && (x.sign != (uZ.i < 0))) ) { slowfloat_exceptionFlags = savedExceptionFlags | softfloat_flag_invalid; return x.sign ? -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1 : INT64_C( 0x7FFFFFFFFFFFFFFF ); } return uZ.i; } #ifdef FLOAT16 static void f16ToFloatX( float16_t a, struct floatX *xPtr ) { union ui16_f16 uA; uint_fast16_t uiA; int_fast8_t exp; uint_fast64_t sig64; uA.f = a; uiA = uA.ui; xPtr->isNaN = false; xPtr->isInf = false; xPtr->isZero = false; xPtr->sign = ((uiA & 0x8000) != 0); exp = uiA>>10 & 0x1F; sig64 = uiA & 0x03FF; sig64 <<= 45; if ( exp == 0x1F ) { if ( sig64 ) { xPtr->isNaN = true; } else { xPtr->isInf = true; } } else if ( ! exp ) { if ( ! sig64 ) { xPtr->isZero = true; } else { exp = 1 - 0xF; do { --exp; sig64 <<= 1; } while ( sig64 < UINT64_C( 0x0080000000000000 ) ); xPtr->exp = exp; } } else { xPtr->exp = exp - 0xF; sig64 |= UINT64_C( 0x0080000000000000 ); } xPtr->sig.v64 = sig64; xPtr->sig.v0 = 0; } static float16_t floatXToF16( const struct floatX *xPtr ) { uint_fast16_t uiZ; struct floatX x, savedX; bool isTiny; int_fast32_t exp; union ui16_f16 uZ; if ( xPtr->isNaN ) { uiZ = 0xFFFF; goto uiZ; } if ( xPtr->isInf ) { uiZ = xPtr->sign ? 0xFC00 : 0x7C00; goto uiZ; } if ( xPtr->isZero ) { uiZ = xPtr->sign ? 0x8000 : 0; goto uiZ; } x = *xPtr; while ( UINT64_C( 0x0100000000000000 ) <= x.sig.v64 ) { ++x.exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } while ( x.sig.v64 < UINT64_C( 0x0080000000000000 ) ) { --x.exp; x.sig = shortShiftLeft128( x.sig, 1 ); } savedX = x; isTiny = (slowfloat_detectTininess == softfloat_tininess_beforeRounding) && (x.exp + 0xF <= 0); roundFloatXTo11( isTiny, &x, slowfloat_roundingMode, true ); exp = x.exp + 0xF; if ( 0x1F <= exp ) { slowfloat_exceptionFlags |= softfloat_flag_overflow | softfloat_flag_inexact; if ( x.sign ) { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_min: case softfloat_round_near_maxMag: uiZ = 0xFC00; break; case softfloat_round_minMag: case softfloat_round_max: uiZ = 0xFBFF; break; } } else { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_max: case softfloat_round_near_maxMag: uiZ = 0x7C00; break; case softfloat_round_minMag: case softfloat_round_min: uiZ = 0x7BFF; break; } } goto uiZ; } if ( exp <= 0 ) { isTiny = true; x = savedX; exp = x.exp + 0xF; if ( exp < -14 ) { x.sig.v0 = (x.sig.v64 != 0) || (x.sig.v0 != 0); x.sig.v64 = 0; } else { while ( exp <= 0 ) { ++exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } } roundFloatXTo11( isTiny, &x, slowfloat_roundingMode, true ); exp = (UINT64_C( 0x0080000000000000 ) <= x.sig.v64) ? 1 : 0; } uiZ = (uint_fast16_t) exp<<10; if ( x.sign ) uiZ |= 0x8000; uiZ |= x.sig.v64>>45 & 0x03FF; uiZ: uZ.ui = uiZ; return uZ.f; } #endif static void f32ToFloatX( float32_t a, struct floatX *xPtr ) { union ui32_f32 uA; uint_fast32_t uiA; int_fast16_t exp; uint_fast64_t sig64; uA.f = a; uiA = uA.ui; xPtr->isNaN = false; xPtr->isInf = false; xPtr->isZero = false; xPtr->sign = ((uiA & 0x80000000) != 0); exp = uiA>>23 & 0xFF; sig64 = uiA & 0x007FFFFF; sig64 <<= 32; if ( exp == 0xFF ) { if ( sig64 ) { xPtr->isNaN = true; } else { xPtr->isInf = true; } } else if ( ! exp ) { if ( ! sig64 ) { xPtr->isZero = true; } else { exp = 1 - 0x7F; do { --exp; sig64 <<= 1; } while ( sig64 < UINT64_C( 0x0080000000000000 ) ); xPtr->exp = exp; } } else { xPtr->exp = exp - 0x7F; sig64 |= UINT64_C( 0x0080000000000000 ); } xPtr->sig.v64 = sig64; xPtr->sig.v0 = 0; } static float32_t floatXToF32( const struct floatX *xPtr ) { uint_fast32_t uiZ; struct floatX x, savedX; bool isTiny; int_fast32_t exp; union ui32_f32 uZ; if ( xPtr->isNaN ) { uiZ = 0xFFFFFFFF; goto uiZ; } if ( xPtr->isInf ) { uiZ = xPtr->sign ? 0xFF800000 : 0x7F800000; goto uiZ; } if ( xPtr->isZero ) { uiZ = xPtr->sign ? 0x80000000 : 0; goto uiZ; } x = *xPtr; while ( UINT64_C( 0x0100000000000000 ) <= x.sig.v64 ) { ++x.exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } while ( x.sig.v64 < UINT64_C( 0x0080000000000000 ) ) { --x.exp; x.sig = shortShiftLeft128( x.sig, 1 ); } savedX = x; isTiny = (slowfloat_detectTininess == softfloat_tininess_beforeRounding) && (x.exp + 0x7F <= 0); roundFloatXTo24( isTiny, &x, slowfloat_roundingMode, true ); exp = x.exp + 0x7F; if ( 0xFF <= exp ) { slowfloat_exceptionFlags |= softfloat_flag_overflow | softfloat_flag_inexact; if ( x.sign ) { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_min: case softfloat_round_near_maxMag: uiZ = 0xFF800000; break; case softfloat_round_minMag: case softfloat_round_max: uiZ = 0xFF7FFFFF; break; } } else { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_max: case softfloat_round_near_maxMag: uiZ = 0x7F800000; break; case softfloat_round_minMag: case softfloat_round_min: uiZ = 0x7F7FFFFF; break; } } goto uiZ; } if ( exp <= 0 ) { isTiny = true; x = savedX; exp = x.exp + 0x7F; if ( exp < -27 ) { x.sig.v0 = (x.sig.v64 != 0) || (x.sig.v0 != 0); x.sig.v64 = 0; } else { while ( exp <= 0 ) { ++exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } } roundFloatXTo24( isTiny, &x, slowfloat_roundingMode, true ); exp = (UINT64_C( 0x0080000000000000 ) <= x.sig.v64) ? 1 : 0; } uiZ = (uint_fast32_t) exp<<23; if ( x.sign ) uiZ |= 0x80000000; uiZ |= x.sig.v64>>32 & 0x007FFFFF; uiZ: uZ.ui = uiZ; return uZ.f; } static void f64ToFloatX( float64_t a, struct floatX *xPtr ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t sig64; uA.f = a; uiA = uA.ui; xPtr->isNaN = false; xPtr->isInf = false; xPtr->isZero = false; xPtr->sign = ((uiA & UINT64_C( 0x8000000000000000 )) != 0); exp = uiA>>52 & 0x7FF; sig64 = uiA & UINT64_C( 0x000FFFFFFFFFFFFF ); if ( exp == 0x7FF ) { if ( sig64 ) { xPtr->isNaN = true; } else { xPtr->isInf = true; } } else if ( ! exp ) { if ( ! sig64 ) { xPtr->isZero = true; } else { exp = 1 - 0x3FF; do { --exp; sig64 <<= 1; } while ( sig64 < UINT64_C( 0x0010000000000000 ) ); xPtr->exp = exp; } } else { xPtr->exp = exp - 0x3FF; sig64 |= UINT64_C( 0x0010000000000000 ); } xPtr->sig.v64 = sig64<<3; xPtr->sig.v0 = 0; } static float64_t floatXToF64( const struct floatX *xPtr ) { uint_fast64_t uiZ; struct floatX x, savedX; bool isTiny; int_fast32_t exp; union ui64_f64 uZ; if ( xPtr->isNaN ) { uiZ = UINT64_C( 0xFFFFFFFFFFFFFFFF ); goto uiZ; } if ( xPtr->isInf ) { uiZ = xPtr->sign ? UINT64_C( 0xFFF0000000000000 ) : UINT64_C( 0x7FF0000000000000 ); goto uiZ; } if ( xPtr->isZero ) { uiZ = xPtr->sign ? UINT64_C( 0x8000000000000000 ) : 0; goto uiZ; } x = *xPtr; while ( UINT64_C( 0x0100000000000000 ) <= x.sig.v64 ) { ++x.exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } while ( x.sig.v64 < UINT64_C( 0x0080000000000000 ) ) { --x.exp; x.sig = shortShiftLeft128( x.sig, 1 ); } savedX = x; isTiny = (slowfloat_detectTininess == softfloat_tininess_beforeRounding) && (x.exp + 0x3FF <= 0); roundFloatXTo53( isTiny, &x, slowfloat_roundingMode, true ); exp = x.exp + 0x3FF; if ( 0x7FF <= exp ) { slowfloat_exceptionFlags |= softfloat_flag_overflow | softfloat_flag_inexact; if ( x.sign ) { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_min: case softfloat_round_near_maxMag: uiZ = UINT64_C( 0xFFF0000000000000 ); break; case softfloat_round_minMag: case softfloat_round_max: uiZ = UINT64_C( 0xFFEFFFFFFFFFFFFF ); break; } } else { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_max: case softfloat_round_near_maxMag: uiZ = UINT64_C( 0x7FF0000000000000 ); break; case softfloat_round_minMag: case softfloat_round_min: uiZ = UINT64_C( 0x7FEFFFFFFFFFFFFF ); break; } } goto uiZ; } if ( exp <= 0 ) { isTiny = true; x = savedX; exp = x.exp + 0x3FF; if ( exp < -56 ) { x.sig.v0 = (x.sig.v64 != 0) || (x.sig.v0 != 0); x.sig.v64 = 0; } else { while ( exp <= 0 ) { ++exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } } roundFloatXTo53( isTiny, &x, slowfloat_roundingMode, true ); exp = (UINT64_C( 0x0080000000000000 ) <= x.sig.v64) ? 1 : 0; } uiZ = (uint_fast64_t) exp<<52; if ( x.sign ) uiZ |= UINT64_C( 0x8000000000000000 ); uiZ |= x.sig.v64>>3 & UINT64_C( 0x000FFFFFFFFFFFFF ); uiZ: uZ.ui = uiZ; return uZ.f; } #ifdef EXTFLOAT80 static void extF80MToFloatX( const extFloat80_t *aPtr, struct floatX *xPtr ) { const struct extFloat80M *aSPtr; uint_fast16_t uiA64; int_fast32_t exp; struct uint128 sig; aSPtr = (const struct extFloat80M *) aPtr; xPtr->isNaN = false; xPtr->isInf = false; xPtr->isZero = false; uiA64 = aSPtr->signExp; xPtr->sign = ((uiA64 & 0x8000) != 0); exp = uiA64 & 0x7FFF; sig.v64 = 0; sig.v0 = aSPtr->signif; if ( exp == 0x7FFF ) { if ( sig.v0 & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { xPtr->isNaN = true; } else { xPtr->isInf = true; } } else { if ( ! exp ) ++exp; exp -= 0x3FFF; if ( ! (sig.v0 & UINT64_C( 0x8000000000000000 )) ) { if ( ! sig.v0 ) { xPtr->isZero = true; } else { do { --exp; sig.v0 <<= 1; } while ( sig.v0 < UINT64_C( 0x8000000000000000 ) ); } } xPtr->exp = exp; } xPtr->sig = shortShiftLeft128( sig, 56 ); } static void floatXToExtF80M( const struct floatX *xPtr, extFloat80_t *zPtr ) { struct extFloat80M *zSPtr; struct floatX x, savedX; bool isTiny; int_fast32_t exp; uint_fast64_t uiZ0; uint_fast16_t uiZ64; zSPtr = (struct extFloat80M *) zPtr; if ( xPtr->isNaN ) { zSPtr->signExp = 0xFFFF; zSPtr->signif = UINT64_C( 0xFFFFFFFFFFFFFFFF ); return; } if ( xPtr->isInf ) { zSPtr->signExp = xPtr->sign ? 0xFFFF : 0x7FFF; zSPtr->signif = UINT64_C( 0x8000000000000000 ); return; } if ( xPtr->isZero ) { zSPtr->signExp = xPtr->sign ? 0x8000 : 0; zSPtr->signif = 0; return; } x = *xPtr; while ( UINT64_C( 0x0100000000000000 ) <= x.sig.v64 ) { ++x.exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } while ( x.sig.v64 < UINT64_C( 0x0080000000000000 ) ) { --x.exp; x.sig = shortShiftLeft128( x.sig, 1 ); } savedX = x; isTiny = (slowfloat_detectTininess == softfloat_tininess_beforeRounding) && (x.exp + 0x3FFF <= 0); switch ( slow_extF80_roundingPrecision ) { case 32: roundFloatXTo24( isTiny, &x, slowfloat_roundingMode, true ); break; case 64: roundFloatXTo53( isTiny, &x, slowfloat_roundingMode, true ); break; default: roundFloatXTo64( isTiny, &x, slowfloat_roundingMode, true ); break; } exp = x.exp + 0x3FFF; if ( 0x7FFF <= exp ) { slowfloat_exceptionFlags |= softfloat_flag_overflow | softfloat_flag_inexact; if ( x.sign ) { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_min: case softfloat_round_near_maxMag: zSPtr->signExp = 0xFFFF; zSPtr->signif = UINT64_C( 0x8000000000000000 ); break; case softfloat_round_minMag: case softfloat_round_max: switch ( slow_extF80_roundingPrecision ) { case 32: uiZ0 = UINT64_C( 0xFFFFFF0000000000 ); break; case 64: uiZ0 = UINT64_C( 0xFFFFFFFFFFFFF800 ); break; default: uiZ0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); break; } zSPtr->signExp = 0xFFFE; zSPtr->signif = uiZ0; break; } } else { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_max: case softfloat_round_near_maxMag: zSPtr->signExp = 0x7FFF; zSPtr->signif = UINT64_C( 0x8000000000000000 ); break; case softfloat_round_minMag: case softfloat_round_min: switch ( slow_extF80_roundingPrecision ) { case 32: uiZ0 = UINT64_C( 0xFFFFFF0000000000 ); break; case 64: uiZ0 = UINT64_C( 0xFFFFFFFFFFFFF800 ); break; default: uiZ0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); break; } zSPtr->signExp = 0x7FFE; zSPtr->signif = uiZ0; break; } } return; } if ( exp <= 0 ) { isTiny = true; x = savedX; exp = x.exp + 0x3FFF; if ( exp < -70 ) { x.sig.v0 = (x.sig.v64 != 0) || (x.sig.v0 != 0); x.sig.v64 = 0; } else { while ( exp <= 0 ) { ++exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } } switch ( slow_extF80_roundingPrecision ) { case 32: roundFloatXTo24( isTiny, &x, slowfloat_roundingMode, true ); break; case 64: roundFloatXTo53( isTiny, &x, slowfloat_roundingMode, true ); break; default: roundFloatXTo64( isTiny, &x, slowfloat_roundingMode, true ); break; } exp = (UINT64_C( 0x0080000000000000 ) <= x.sig.v64) ? 1 : 0; } uiZ64 = exp; if ( x.sign ) uiZ64 |= 0x8000; zSPtr->signExp = uiZ64; zSPtr->signif = shortShiftRightJam128( x.sig, 56 ).v0; } #endif #ifdef FLOAT128 static void f128MToFloatX( const float128_t *aPtr, struct floatX *xPtr ) { const struct uint128 *uiAPtr; uint_fast64_t uiA64; int_fast32_t exp; struct uint128 sig; uiAPtr = (const struct uint128 *) aPtr; xPtr->isNaN = false; xPtr->isInf = false; xPtr->isZero = false; uiA64 = uiAPtr->v64; xPtr->sign = ((uiA64 & UINT64_C( 0x8000000000000000 )) != 0); exp = uiA64>>48 & 0x7FFF; sig.v64 = uiA64 & UINT64_C( 0x0000FFFFFFFFFFFF ); sig.v0 = uiAPtr->v0; if ( exp == 0x7FFF ) { if ( sig.v64 || sig.v0 ) { xPtr->isNaN = true; } else { xPtr->isInf = true; } } else if ( ! exp ) { if ( ! sig.v64 && ! sig.v0 ) { xPtr->isZero = true; } else { exp = 1 - 0x3FFF; do { --exp; sig = shortShiftLeft128( sig, 1 ); } while ( sig.v64 < UINT64_C( 0x0001000000000000 ) ); xPtr->exp = exp; } } else { xPtr->exp = exp - 0x3FFF; sig.v64 |= UINT64_C( 0x0001000000000000 ); } xPtr->sig = shortShiftLeft128( sig, 7 ); } static void floatXToF128M( const struct floatX *xPtr, float128_t *zPtr ) { struct uint128 *uiZPtr; struct floatX x, savedX; bool isTiny; int_fast32_t exp; uint_fast64_t uiZ64; uiZPtr = (struct uint128 *) zPtr; if ( xPtr->isNaN ) { uiZPtr->v64 = uiZPtr->v0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); return; } if ( xPtr->isInf ) { uiZPtr->v64 = xPtr->sign ? UINT64_C( 0xFFFF000000000000 ) : UINT64_C( 0x7FFF000000000000 ); uiZPtr->v0 = 0; return; } if ( xPtr->isZero ) { uiZPtr->v64 = xPtr->sign ? UINT64_C( 0x8000000000000000 ) : 0; uiZPtr->v0 = 0; return; } x = *xPtr; while ( UINT64_C( 0x0100000000000000 ) <= x.sig.v64 ) { ++x.exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } while ( x.sig.v64 < UINT64_C( 0x0080000000000000 ) ) { --x.exp; x.sig = shortShiftLeft128( x.sig, 1 ); } savedX = x; isTiny = (slowfloat_detectTininess == softfloat_tininess_beforeRounding) && (x.exp + 0x3FFF <= 0); roundFloatXTo113( isTiny, &x, slowfloat_roundingMode, true ); exp = x.exp + 0x3FFF; if ( 0x7FFF <= exp ) { slowfloat_exceptionFlags |= softfloat_flag_overflow | softfloat_flag_inexact; if ( x.sign ) { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_min: case softfloat_round_near_maxMag: uiZPtr->v64 = UINT64_C( 0xFFFF000000000000 ); uiZPtr->v0 = 0; break; case softfloat_round_minMag: case softfloat_round_max: uiZPtr->v64 = UINT64_C( 0xFFFEFFFFFFFFFFFF ); uiZPtr->v0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); break; } } else { switch ( slowfloat_roundingMode ) { case softfloat_round_near_even: case softfloat_round_max: case softfloat_round_near_maxMag: uiZPtr->v64 = UINT64_C( 0x7FFF000000000000 ); uiZPtr->v0 = 0; break; case softfloat_round_minMag: case softfloat_round_min: uiZPtr->v64 = UINT64_C( 0x7FFEFFFFFFFFFFFF ); uiZPtr->v0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); break; } } return; } if ( exp <= 0 ) { isTiny = true; x = savedX; exp = x.exp + 0x3FFF; if ( exp < -120 ) { x.sig.v0 = (x.sig.v64 != 0) || (x.sig.v0 != 0); x.sig.v64 = 0; } else { while ( exp <= 0 ) { ++exp; x.sig = shortShiftRightJam128( x.sig, 1 ); } } roundFloatXTo113( isTiny, &x, slowfloat_roundingMode, true ); exp = (UINT64_C( 0x0080000000000000 ) <= x.sig.v64) ? 1 : 0; } uiZ64 = (uint_fast64_t) exp<<48; if ( x.sign ) uiZ64 |= UINT64_C( 0x8000000000000000 ); x.sig = shortShiftRightJam128( x.sig, 7 ); uiZPtr->v64 = uiZ64 | x.sig.v64 & UINT64_C( 0x0000FFFFFFFFFFFF ); uiZPtr->v0 = x.sig.v0; } #endif static void floatXInvalid( struct floatX *xPtr ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; *xPtr = floatXNaN; } static void floatXRoundToInt( struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) { int_fast32_t exp, shiftDist; struct uint128 sig; if ( xPtr->isNaN || xPtr->isInf ) return; exp = xPtr->exp; shiftDist = 112 - exp; if ( shiftDist <= 0 ) return; if ( 119 < shiftDist ) { xPtr->exp = 112; xPtr->sig.v64 = 0; xPtr->sig.v0 = ! xPtr->isZero; } else { sig = xPtr->sig; while ( 0 < shiftDist ) { ++exp; sig = shortShiftRightJam128( sig, 1 ); --shiftDist; } xPtr->exp = exp; xPtr->sig = sig; } roundFloatXTo113( false, xPtr, roundingMode, exact ); if ( ! xPtr->sig.v64 && ! xPtr->sig.v0 ) xPtr->isZero = true; } static void floatXAdd( struct floatX *xPtr, const struct floatX *yPtr ) { int_fast32_t expX, expY, expDiff; struct uint128 sigY; if ( xPtr->isNaN ) return; if ( yPtr->isNaN ) goto copyY; if ( xPtr->isInf && yPtr->isInf ) { if ( xPtr->sign != yPtr->sign ) floatXInvalid( xPtr ); return; } if ( xPtr->isInf ) return; if ( yPtr->isInf ) goto copyY; if ( xPtr->isZero && yPtr->isZero ) { if ( xPtr->sign == yPtr->sign ) return; goto completeCancellation; } expX = xPtr->exp; expY = yPtr->exp; if ( (xPtr->sign != yPtr->sign) && (expX == expY) && eq128( xPtr->sig, yPtr->sig ) ) { completeCancellation: if (slowfloat_roundingMode == softfloat_round_min) { *xPtr = floatXNegativeZero; } else { *xPtr = floatXPositiveZero; } return; } if ( xPtr->isZero ) goto copyY; if ( yPtr->isZero ) return; expDiff = expX - expY; if ( expDiff < 0 ) { xPtr->exp = expY; if ( expDiff < -120 ) { xPtr->sig.v64 = 0; xPtr->sig.v0 = 1; } else { while ( expDiff < 0 ) { ++expDiff; xPtr->sig = shortShiftRightJam128( xPtr->sig, 1 ); } } if ( xPtr->sign != yPtr->sign ) xPtr->sig = neg128( xPtr->sig ); xPtr->sign = yPtr->sign; xPtr->sig = add128( xPtr->sig, yPtr->sig ); } else { sigY = yPtr->sig; if ( 120 < expDiff ) { sigY.v64 = 0; sigY.v0 = 1; } else { while ( 0 < expDiff ) { --expDiff; sigY = shortShiftRightJam128( sigY, 1 ); } } if ( xPtr->sign != yPtr->sign ) sigY = neg128( sigY ); xPtr->sig = add128( xPtr->sig, sigY ); } if ( xPtr->sig.v64 & UINT64_C( 0x8000000000000000 ) ) { xPtr->sign = ! xPtr->sign; xPtr->sig = neg128( xPtr->sig ); } return; copyY: *xPtr = *yPtr; } static void floatXMul( struct floatX *xPtr, const struct floatX *yPtr ) { struct uint128 sig; int bitNum; if ( xPtr->isNaN ) return; if ( yPtr->isNaN ) { xPtr->isNaN = true; xPtr->isInf = false; xPtr->isZero = false; xPtr->sign = yPtr->sign; return; } if ( yPtr->sign ) xPtr->sign = ! xPtr->sign; if ( xPtr->isInf ) { if ( yPtr->isZero ) floatXInvalid( xPtr ); return; } if ( yPtr->isInf ) { if ( xPtr->isZero ) { floatXInvalid( xPtr ); return; } xPtr->isInf = true; return; } if ( xPtr->isZero || yPtr->isZero ) { if ( xPtr->sign ) { *xPtr = floatXNegativeZero; } else { *xPtr = floatXPositiveZero; } return; } xPtr->exp += yPtr->exp; sig.v64 = 0; sig.v0 = 0; for ( bitNum = 0; bitNum < 120; ++bitNum ) { sig = shortShiftRightJam128( sig, 1 ); if ( xPtr->sig.v0 & 1 ) sig = add128( sig, yPtr->sig ); xPtr->sig = shortShiftRight128( xPtr->sig, 1 ); } if ( UINT64_C( 0x0100000000000000 ) <= sig.v64 ) { ++xPtr->exp; sig = shortShiftRightJam128( sig, 1 ); } xPtr->sig = sig; } static void floatXDiv( struct floatX *xPtr, const struct floatX *yPtr ) { struct uint128 sig, negSigY; int bitNum; if ( xPtr->isNaN ) return; if ( yPtr->isNaN ) { xPtr->isNaN = true; xPtr->isInf = false; xPtr->isZero = false; xPtr->sign = yPtr->sign; return; } if ( yPtr->sign ) xPtr->sign = ! xPtr->sign; if ( xPtr->isInf ) { if ( yPtr->isInf ) floatXInvalid( xPtr ); return; } if ( yPtr->isZero ) { if ( xPtr->isZero ) { floatXInvalid( xPtr ); return; } slowfloat_exceptionFlags |= softfloat_flag_infinite; xPtr->isInf = true; return; } if ( xPtr->isZero || yPtr->isInf ) { if ( xPtr->sign ) { *xPtr = floatXNegativeZero; } else { *xPtr = floatXPositiveZero; } return; } xPtr->exp -= yPtr->exp + 1; sig.v64 = 0; sig.v0 = 0; negSigY = neg128( yPtr->sig ); for ( bitNum = 0; bitNum < 120; ++bitNum ) { if ( le128( yPtr->sig, xPtr->sig ) ) { sig.v0 |= 1; xPtr->sig = add128( xPtr->sig, negSigY ); } xPtr->sig = shortShiftLeft128( xPtr->sig, 1 ); sig = shortShiftLeft128( sig, 1 ); } if ( xPtr->sig.v64 || xPtr->sig.v0 ) sig.v0 |= 1; xPtr->sig = sig; } static void floatXRem( struct floatX *xPtr, const struct floatX *yPtr ) { int_fast32_t expX, expY; struct uint128 sigY, negSigY; bool lastQuotientBit; struct uint128 savedSigX; if ( xPtr->isNaN ) return; if ( yPtr->isNaN ) { xPtr->isNaN = true; xPtr->isInf = false; xPtr->isZero = false; xPtr->sign = yPtr->sign; return; } if ( xPtr->isInf || yPtr->isZero ) { floatXInvalid( xPtr ); return; } if ( xPtr->isZero || yPtr->isInf ) return; expX = xPtr->exp; expY = yPtr->exp - 1; if ( expX < expY ) return; sigY = shortShiftLeft128( yPtr->sig, 1 ); negSigY = neg128( sigY ); while ( expY < expX ) { --expX; if ( le128( sigY, xPtr->sig ) ) { xPtr->sig = add128( xPtr->sig, negSigY ); } xPtr->sig = shortShiftLeft128( xPtr->sig, 1 ); } xPtr->exp = expX; lastQuotientBit = le128( sigY, xPtr->sig ); if ( lastQuotientBit ) xPtr->sig = add128( xPtr->sig, negSigY ); savedSigX = xPtr->sig; xPtr->sig = neg128( add128( xPtr->sig, negSigY ) ); if ( lt128( xPtr->sig, savedSigX ) ) { xPtr->sign = ! xPtr->sign; } else if ( lt128( savedSigX, xPtr->sig ) ) { goto restoreSavedSigX; } else { if ( lastQuotientBit ) { xPtr->sign = ! xPtr->sign; } else { restoreSavedSigX: xPtr->sig = savedSigX; } } if ( ! xPtr->sig.v64 && ! xPtr->sig.v0 ) xPtr->isZero = true; } static void floatXSqrt( struct floatX *xPtr ) { struct uint128 sig, bitSig; int bitNum; struct uint128 savedSigX; if ( xPtr->isNaN || xPtr->isZero ) return; if ( xPtr->sign ) { floatXInvalid( xPtr ); return; } if ( xPtr->isInf ) return; if ( ! (xPtr->exp & 1) ) xPtr->sig = shortShiftRightJam128( xPtr->sig, 1 ); xPtr->exp >>= 1; sig.v64 = 0; sig.v0 = 0; bitSig.v64 = UINT64_C( 0x0080000000000000 ); bitSig.v0 = 0; for ( bitNum = 0; bitNum < 120; ++bitNum ) { savedSigX = xPtr->sig; xPtr->sig = add128( xPtr->sig, neg128( sig ) ); xPtr->sig = shortShiftLeft128( xPtr->sig, 1 ); xPtr->sig = add128( xPtr->sig, neg128( bitSig ) ); if ( xPtr->sig.v64 & UINT64_C( 0x8000000000000000 ) ) { xPtr->sig = shortShiftLeft128( savedSigX, 1 ); } else { sig.v64 |= bitSig.v64; sig.v0 |= bitSig.v0; } bitSig = shortShiftRightJam128( bitSig, 1 ); } if ( xPtr->sig.v64 || xPtr->sig.v0 ) sig.v0 |= 1; xPtr->sig = sig; } static bool floatXEq( const struct floatX *xPtr, const struct floatX *yPtr ) { if ( xPtr->isNaN || yPtr->isNaN ) return false; if ( xPtr->isZero && yPtr->isZero ) return true; if ( xPtr->sign != yPtr->sign ) return false; if ( xPtr->isInf || yPtr->isInf ) return xPtr->isInf && yPtr->isInf; return ( xPtr->exp == yPtr->exp ) && eq128( xPtr->sig, yPtr->sig ); } static bool floatXLe( const struct floatX *xPtr, const struct floatX *yPtr ) { if ( xPtr->isNaN || yPtr->isNaN ) return false; if ( xPtr->isZero && yPtr->isZero ) return true; if ( xPtr->sign != yPtr->sign ) return xPtr->sign; if ( xPtr->sign ) { if ( xPtr->isInf || yPtr->isZero ) return true; if ( yPtr->isInf || xPtr->isZero ) return false; if ( yPtr->exp < xPtr->exp ) return true; if ( xPtr->exp < yPtr->exp ) return false; return le128( yPtr->sig, xPtr->sig ); } else { if ( yPtr->isInf || xPtr->isZero ) return true; if ( xPtr->isInf || yPtr->isZero ) return false; if ( xPtr->exp < yPtr->exp ) return true; if ( yPtr->exp < xPtr->exp ) return false; return le128( xPtr->sig, yPtr->sig ); } } static bool floatXLt( const struct floatX *xPtr, const struct floatX *yPtr ) { if ( xPtr->isNaN || yPtr->isNaN ) return false; if ( xPtr->isZero && yPtr->isZero ) return false; if ( xPtr->sign != yPtr->sign ) return xPtr->sign; if ( xPtr->isInf && yPtr->isInf ) return false; if ( xPtr->sign ) { if ( xPtr->isInf || yPtr->isZero ) return true; if ( yPtr->isInf || xPtr->isZero ) return false; if ( yPtr->exp < xPtr->exp ) return true; if ( xPtr->exp < yPtr->exp ) return false; return lt128( yPtr->sig, xPtr->sig ); } else { if ( yPtr->isInf || xPtr->isZero ) return true; if ( xPtr->isInf || yPtr->isZero ) return false; if ( xPtr->exp < yPtr->exp ) return true; if ( yPtr->exp < xPtr->exp ) return false; return lt128( xPtr->sig, yPtr->sig ); } } /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #if defined EXTFLOAT80 || defined FLOAT128 #ifdef LITTLEENDIAN struct uint256 { uint64_t v0, v64, v128, v192; }; #else struct uint256 { uint64_t v192, v128, v64, v0; }; #endif static bool eq256M( const struct uint256 *aPtr, const struct uint256 *bPtr ) { return (aPtr->v192 == bPtr->v192) && (aPtr->v128 == bPtr->v128) && (aPtr->v64 == bPtr->v64) && (aPtr->v0 == bPtr->v0); } static void shiftLeft1256M( struct uint256 *ptr ) { uint64_t dword1, dword2; dword1 = ptr->v128; ptr->v192 = ptr->v192<<1 | dword1>>63; dword2 = ptr->v64; ptr->v128 = dword1<<1 | dword2>>63; dword1 = ptr->v0; ptr->v64 = dword2<<1 | dword1>>63; ptr->v0 = dword1<<1; } static void shiftRight1256M( struct uint256 *ptr ) { uint64_t dword1, dword2; dword1 = ptr->v64; ptr->v0 = dword1<<63 | ptr->v0>>1; dword2 = ptr->v128; ptr->v64 = dword2<<63 | dword1>>1; dword1 = ptr->v192; ptr->v128 = dword1<<63 | dword2>>1; ptr->v192 = dword1>>1; } static void shiftRight1Jam256M( struct uint256 *ptr ) { int extra; extra = ptr->v0 & 1; shiftRight1256M( ptr ); ptr->v0 |= extra; } static void neg256M( struct uint256 *ptr ) { uint64_t v64, v0, v128; v64 = ptr->v64; v0 = ptr->v0; if ( v64 | v0 ) { ptr->v192 = ~ptr->v192; ptr->v128 = ~ptr->v128; if ( v0 ) { ptr->v64 = ~v64; ptr->v0 = -v0; } else { ptr->v64 = -v64; } } else { v128 = ptr->v128; if ( v128 ) { ptr->v192 = ~ptr->v192; ptr->v128 = -v128; } else { ptr->v192 = -ptr->v192; } } } static void add256M( struct uint256 *aPtr, const struct uint256 *bPtr ) { uint64_t dwordA, dwordZ; unsigned int carry1, carry2; dwordA = aPtr->v0; dwordZ = dwordA + bPtr->v0; carry1 = (dwordZ < dwordA); aPtr->v0 = dwordZ; dwordA = aPtr->v64; dwordZ = dwordA + bPtr->v64; carry2 = (dwordZ < dwordA); dwordZ += carry1; carry2 += (dwordZ < carry1); aPtr->v64 = dwordZ; dwordA = aPtr->v128; dwordZ = dwordA + bPtr->v128; carry1 = (dwordZ < dwordA); dwordZ += carry2; carry1 += (dwordZ < carry2); aPtr->v128 = dwordZ; aPtr->v192 = aPtr->v192 + bPtr->v192 + carry1; } struct floatX256 { bool isNaN; bool isInf; bool isZero; bool sign; int_fast32_t exp; struct uint256 sig; }; static const struct floatX256 floatX256NaN = { true, false, false, false, 0, { 0, 0, 0, 0 } }; static const struct floatX256 floatX256PositiveZero = { false, false, true, false, 0, { 0, 0, 0, 0 } }; static const struct floatX256 floatX256NegativeZero = { false, false, true, true, 0, { 0, 0, 0, 0 } }; #ifdef FLOAT128 static void f128MToFloatX256( const float128_t *aPtr, struct floatX256 *xPtr ) { struct floatX x; f128MToFloatX( aPtr, &x ); xPtr->isNaN = x.isNaN; xPtr->isInf = x.isInf; xPtr->isZero = x.isZero; xPtr->sign = x.sign; xPtr->exp = x.exp; xPtr->sig.v192 = x.sig.v64; xPtr->sig.v128 = x.sig.v0; xPtr->sig.v64 = 0; xPtr->sig.v0 = 0; } static void floatX256ToF128M( const struct floatX256 *xPtr, float128_t *zPtr ) { struct floatX x; int_fast32_t expZ; struct uint256 sig; x.isNaN = xPtr->isNaN; x.isInf = xPtr->isInf; x.isZero = xPtr->isZero; x.sign = xPtr->sign; if ( ! (x.isNaN | x.isInf | x.isZero) ) { expZ = xPtr->exp; sig = xPtr->sig; while ( ! sig.v192 ) { expZ -= 64; sig.v192 = sig.v128; sig.v128 = sig.v64; sig.v64 = sig.v0; sig.v0 = 0; } while ( sig.v192 < UINT64_C( 0x0100000000000000 ) ) { --expZ; shiftLeft1256M( &sig ); } x.exp = expZ; x.sig.v64 = sig.v192; x.sig.v0 = sig.v128 | ((sig.v64 | sig.v0) != 0); } floatXToF128M( &x, zPtr ); } #endif static void floatX256Invalid( struct floatX256 *xPtr ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; *xPtr = floatX256NaN; } static void floatX256Add( struct floatX256 *xPtr, const struct floatX256 *yPtr ) { int_fast32_t expX, expY, expDiff; struct uint256 sigY; if ( xPtr->isNaN ) return; if ( yPtr->isNaN ) goto copyY; if ( xPtr->isInf && yPtr->isInf ) { if ( xPtr->sign != yPtr->sign ) floatX256Invalid( xPtr ); return; } if ( xPtr->isInf ) return; if ( yPtr->isInf ) goto copyY; if ( xPtr->isZero && yPtr->isZero ) { if ( xPtr->sign == yPtr->sign ) return; goto completeCancellation; } expX = xPtr->exp; expY = yPtr->exp; if ( (xPtr->sign != yPtr->sign) && (expX == expY) && eq256M( &xPtr->sig, &yPtr->sig ) ) { completeCancellation: if (slowfloat_roundingMode == softfloat_round_min) { *xPtr = floatX256NegativeZero; } else { *xPtr = floatX256PositiveZero; } return; } if ( xPtr->isZero ) goto copyY; if ( yPtr->isZero ) return; expDiff = expX - expY; if ( expDiff < 0 ) { xPtr->exp = expY; if ( expDiff < -248 ) { xPtr->sig.v192 = 0; xPtr->sig.v128 = 0; xPtr->sig.v64 = 0; xPtr->sig.v0 = 1; } else { while ( expDiff < 0 ) { ++expDiff; shiftRight1Jam256M( &xPtr->sig ); } } if ( xPtr->sign != yPtr->sign ) neg256M( &xPtr->sig ); xPtr->sign = yPtr->sign; add256M( &xPtr->sig, &yPtr->sig ); } else { sigY = yPtr->sig; if ( 248 < expDiff ) { sigY.v192 = 0; sigY.v128 = 0; sigY.v64 = 0; sigY.v0 = 1; } else { while ( 0 < expDiff ) { --expDiff; shiftRight1Jam256M( &sigY ); } } if ( xPtr->sign != yPtr->sign ) neg256M( &sigY ); add256M( &xPtr->sig, &sigY ); } if ( xPtr->sig.v192 & UINT64_C( 0x8000000000000000 ) ) { xPtr->sign = ! xPtr->sign; neg256M( &xPtr->sig ); } return; copyY: *xPtr = *yPtr; } static void floatX256Mul( struct floatX256 *xPtr, const struct floatX256 *yPtr ) { struct uint256 sig; int bitNum; if ( xPtr->isNaN ) return; if ( yPtr->isNaN ) { xPtr->isNaN = true; xPtr->isInf = false; xPtr->isZero = false; xPtr->sign = yPtr->sign; return; } if ( yPtr->sign ) xPtr->sign = ! xPtr->sign; if ( xPtr->isInf ) { if ( yPtr->isZero ) floatX256Invalid( xPtr ); return; } if ( yPtr->isInf ) { if ( xPtr->isZero ) { floatX256Invalid( xPtr ); return; } xPtr->isInf = true; return; } if ( xPtr->isZero || yPtr->isZero ) { if ( xPtr->sign ) { *xPtr = floatX256NegativeZero; } else { *xPtr = floatX256PositiveZero; } return; } xPtr->exp += yPtr->exp; sig.v192 = 0; sig.v128 = 0; sig.v64 = 0; sig.v0 = 0; for ( bitNum = 0; bitNum < 248; ++bitNum ) { shiftRight1Jam256M( &sig ); if ( xPtr->sig.v0 & 1 ) add256M( &sig, &yPtr->sig ); shiftRight1256M( &xPtr->sig ); } if ( UINT64_C( 0x0100000000000000 ) <= sig.v192 ) { ++xPtr->exp; shiftRight1Jam256M( &sig ); } xPtr->sig = sig; } #endif /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #ifdef FLOAT16 float16_t slow_ui32_to_f16( uint32_t a ) { struct floatX x; ui32ToFloatX( a, &x ); return floatXToF16( &x ); } #endif float32_t slow_ui32_to_f32( uint32_t a ) { struct floatX x; ui32ToFloatX( a, &x ); return floatXToF32( &x ); } float64_t slow_ui32_to_f64( uint32_t a ) { struct floatX x; ui32ToFloatX( a, &x ); return floatXToF64( &x ); } #ifdef EXTFLOAT80 void slow_ui32_to_extF80M( uint32_t a, extFloat80_t *zPtr ) { struct floatX x; ui32ToFloatX( a, &x ); floatXToExtF80M( &x, zPtr ); } #endif #ifdef FLOAT128 void slow_ui32_to_f128M( uint32_t a, float128_t *zPtr ) { struct floatX x; ui32ToFloatX( a, &x ); floatXToF128M( &x, zPtr ); } #endif #ifdef FLOAT16 float16_t slow_ui64_to_f16( uint64_t a ) { struct floatX x; ui64ToFloatX( a, &x ); return floatXToF16( &x ); } #endif float32_t slow_ui64_to_f32( uint64_t a ) { struct floatX x; ui64ToFloatX( a, &x ); return floatXToF32( &x ); } float64_t slow_ui64_to_f64( uint64_t a ) { struct floatX x; ui64ToFloatX( a, &x ); return floatXToF64( &x ); } #ifdef EXTFLOAT80 void slow_ui64_to_extF80M( uint64_t a, extFloat80_t *zPtr ) { struct floatX x; ui64ToFloatX( a, &x ); floatXToExtF80M( &x, zPtr ); } #endif #ifdef FLOAT128 void slow_ui64_to_f128M( uint64_t a, float128_t *zPtr ) { struct floatX x; ui64ToFloatX( a, &x ); floatXToF128M( &x, zPtr ); } #endif #ifdef FLOAT16 float16_t slow_i32_to_f16( int32_t a ) { struct floatX x; i32ToFloatX( a, &x ); return floatXToF16( &x ); } #endif float32_t slow_i32_to_f32( int32_t a ) { struct floatX x; i32ToFloatX( a, &x ); return floatXToF32( &x ); } float64_t slow_i32_to_f64( int32_t a ) { struct floatX x; i32ToFloatX( a, &x ); return floatXToF64( &x ); } #ifdef EXTFLOAT80 void slow_i32_to_extF80M( int32_t a, extFloat80_t *zPtr ) { struct floatX x; i32ToFloatX( a, &x ); floatXToExtF80M( &x, zPtr ); } #endif #ifdef FLOAT128 void slow_i32_to_f128M( int32_t a, float128_t *zPtr ) { struct floatX x; i32ToFloatX( a, &x ); floatXToF128M( &x, zPtr ); } #endif #ifdef FLOAT16 float16_t slow_i64_to_f16( int64_t a ) { struct floatX x; i64ToFloatX( a, &x ); return floatXToF16( &x ); } #endif float32_t slow_i64_to_f32( int64_t a ) { struct floatX x; i64ToFloatX( a, &x ); return floatXToF32( &x ); } float64_t slow_i64_to_f64( int64_t a ) { struct floatX x; i64ToFloatX( a, &x ); return floatXToF64( &x ); } #ifdef EXTFLOAT80 void slow_i64_to_extF80M( int64_t a, extFloat80_t *zPtr ) { struct floatX x; i64ToFloatX( a, &x ); floatXToExtF80M( &x, zPtr ); } #endif #ifdef FLOAT128 void slow_i64_to_f128M( int64_t a, float128_t *zPtr ) { struct floatX x; i64ToFloatX( a, &x ); floatXToF128M( &x, zPtr ); } #endif #ifdef FLOAT16 uint_fast32_t slow_f16_to_ui32( float16_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToUI32( &x, roundingMode, exact ); } uint_fast64_t slow_f16_to_ui64( float16_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToUI64( &x, roundingMode, exact ); } int_fast32_t slow_f16_to_i32( float16_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToI32( &x, roundingMode, exact ); } int_fast64_t slow_f16_to_i64( float16_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToI64( &x, roundingMode, exact ); } uint_fast32_t slow_f16_to_ui32_r_minMag( float16_t a, bool exact ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToUI32( &x, softfloat_round_minMag, exact ); } uint_fast64_t slow_f16_to_ui64_r_minMag( float16_t a, bool exact ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToUI64( &x, softfloat_round_minMag, exact ); } int_fast32_t slow_f16_to_i32_r_minMag( float16_t a, bool exact ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToI32( &x, softfloat_round_minMag, exact ); } int_fast64_t slow_f16_to_i64_r_minMag( float16_t a, bool exact ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToI64( &x, softfloat_round_minMag, exact ); } float32_t slow_f16_to_f32( float16_t a ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToF32( &x ); } float64_t slow_f16_to_f64( float16_t a ) { struct floatX x; f16ToFloatX( a, &x ); return floatXToF64( &x ); } #ifdef EXTFLOAT80 void slow_f16_to_extF80M( float16_t a, extFloat80_t *zPtr ) { struct floatX x; f16ToFloatX( a, &x ); floatXToExtF80M( &x, zPtr ); } #endif #ifdef FLOAT128 void slow_f16_to_f128M( float16_t a, float128_t *zPtr ) { struct floatX x; f16ToFloatX( a, &x ); floatXToF128M( &x, zPtr ); } #endif float16_t slow_f16_roundToInt( float16_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f16ToFloatX( a, &x ); floatXRoundToInt( &x, roundingMode, exact ); return floatXToF16( &x ); } float16_t slow_f16_add( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); floatXAdd( &x, &y ); return floatXToF16( &x ); } float16_t slow_f16_sub( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); y.sign = ! y.sign; floatXAdd( &x, &y ); return floatXToF16( &x ); } float16_t slow_f16_mul( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); floatXMul( &x, &y ); return floatXToF16( &x ); } float16_t slow_f16_mulAdd( float16_t a, float16_t b, float16_t c ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); floatXMul( &x, &y ); f16ToFloatX( c, &y ); floatXAdd( &x, &y ); return floatXToF16( &x ); } float16_t slow_f16_div( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); floatXDiv( &x, &y ); return floatXToF16( &x ); } float16_t slow_f16_rem( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); floatXRem( &x, &y ); return floatXToF16( &x ); } float16_t slow_f16_sqrt( float16_t a ) { struct floatX x; f16ToFloatX( a, &x ); floatXSqrt( &x ); return floatXToF16( &x ); } bool slow_f16_eq( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); return floatXEq( &x, &y ); } bool slow_f16_le( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLe( &x, &y ); } bool slow_f16_lt( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLt( &x, &y ); } bool slow_f16_eq_signaling( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXEq( &x, &y ); } bool slow_f16_le_quiet( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); return floatXLe( &x, &y ); } bool slow_f16_lt_quiet( float16_t a, float16_t b ) { struct floatX x, y; f16ToFloatX( a, &x ); f16ToFloatX( b, &y ); return floatXLt( &x, &y ); } #endif uint_fast32_t slow_f32_to_ui32( float32_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToUI32( &x, roundingMode, exact ); } uint_fast64_t slow_f32_to_ui64( float32_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToUI64( &x, roundingMode, exact ); } int_fast32_t slow_f32_to_i32( float32_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToI32( &x, roundingMode, exact ); } int_fast64_t slow_f32_to_i64( float32_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToI64( &x, roundingMode, exact ); } uint_fast32_t slow_f32_to_ui32_r_minMag( float32_t a, bool exact ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToUI32( &x, softfloat_round_minMag, exact ); } uint_fast64_t slow_f32_to_ui64_r_minMag( float32_t a, bool exact ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToUI64( &x, softfloat_round_minMag, exact ); } int_fast32_t slow_f32_to_i32_r_minMag( float32_t a, bool exact ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToI32( &x, softfloat_round_minMag, exact ); } int_fast64_t slow_f32_to_i64_r_minMag( float32_t a, bool exact ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToI64( &x, softfloat_round_minMag, exact ); } #ifdef FLOAT16 float16_t slow_f32_to_f16( float32_t a ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToF16( &x ); } #endif float64_t slow_f32_to_f64( float32_t a ) { struct floatX x; f32ToFloatX( a, &x ); return floatXToF64( &x ); } #ifdef EXTFLOAT80 void slow_f32_to_extF80M( float32_t a, extFloat80_t *zPtr ) { struct floatX x; f32ToFloatX( a, &x ); floatXToExtF80M( &x, zPtr ); } #endif #ifdef FLOAT128 void slow_f32_to_f128M( float32_t a, float128_t *zPtr ) { struct floatX x; f32ToFloatX( a, &x ); floatXToF128M( &x, zPtr ); } #endif float32_t slow_f32_roundToInt( float32_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f32ToFloatX( a, &x ); floatXRoundToInt( &x, roundingMode, exact ); return floatXToF32( &x ); } float32_t slow_f32_add( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); floatXAdd( &x, &y ); return floatXToF32( &x ); } float32_t slow_f32_sub( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); y.sign = ! y.sign; floatXAdd( &x, &y ); return floatXToF32( &x ); } float32_t slow_f32_mul( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); floatXMul( &x, &y ); return floatXToF32( &x ); } float32_t slow_f32_mulAdd( float32_t a, float32_t b, float32_t c ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); floatXMul( &x, &y ); f32ToFloatX( c, &y ); floatXAdd( &x, &y ); return floatXToF32( &x ); } float32_t slow_f32_div( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); floatXDiv( &x, &y ); return floatXToF32( &x ); } float32_t slow_f32_rem( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); floatXRem( &x, &y ); return floatXToF32( &x ); } float32_t slow_f32_sqrt( float32_t a ) { struct floatX x; f32ToFloatX( a, &x ); floatXSqrt( &x ); return floatXToF32( &x ); } bool slow_f32_eq( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); return floatXEq( &x, &y ); } bool slow_f32_le( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLe( &x, &y ); } bool slow_f32_lt( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLt( &x, &y ); } bool slow_f32_eq_signaling( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXEq( &x, &y ); } bool slow_f32_le_quiet( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); return floatXLe( &x, &y ); } bool slow_f32_lt_quiet( float32_t a, float32_t b ) { struct floatX x, y; f32ToFloatX( a, &x ); f32ToFloatX( b, &y ); return floatXLt( &x, &y ); } uint_fast32_t slow_f64_to_ui32( float64_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToUI32( &x, roundingMode, exact ); } uint_fast64_t slow_f64_to_ui64( float64_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToUI64( &x, roundingMode, exact ); } int_fast32_t slow_f64_to_i32( float64_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToI32( &x, roundingMode, exact ); } int_fast64_t slow_f64_to_i64( float64_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToI64( &x, roundingMode, exact ); } uint_fast32_t slow_f64_to_ui32_r_minMag( float64_t a, bool exact ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToUI32( &x, softfloat_round_minMag, exact ); } uint_fast64_t slow_f64_to_ui64_r_minMag( float64_t a, bool exact ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToUI64( &x, softfloat_round_minMag, exact ); } int_fast32_t slow_f64_to_i32_r_minMag( float64_t a, bool exact ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToI32( &x, softfloat_round_minMag, exact ); } int_fast64_t slow_f64_to_i64_r_minMag( float64_t a, bool exact ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToI64( &x, softfloat_round_minMag, exact ); } #ifdef FLOAT16 float16_t slow_f64_to_f16( float64_t a ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToF16( &x ); } #endif float32_t slow_f64_to_f32( float64_t a ) { struct floatX x; f64ToFloatX( a, &x ); return floatXToF32( &x ); } #ifdef EXTFLOAT80 void slow_f64_to_extF80M( float64_t a, extFloat80_t *zPtr ) { struct floatX x; f64ToFloatX( a, &x ); floatXToExtF80M( &x, zPtr ); } #endif #ifdef FLOAT128 void slow_f64_to_f128M( float64_t a, float128_t *zPtr ) { struct floatX x; f64ToFloatX( a, &x ); floatXToF128M( &x, zPtr ); } #endif float64_t slow_f64_roundToInt( float64_t a, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f64ToFloatX( a, &x ); floatXRoundToInt( &x, roundingMode, exact ); return floatXToF64( &x ); } float64_t slow_f64_add( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); floatXAdd( &x, &y ); return floatXToF64( &x ); } float64_t slow_f64_sub( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); y.sign = ! y.sign; floatXAdd( &x, &y ); return floatXToF64( &x ); } float64_t slow_f64_mul( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); floatXMul( &x, &y ); return floatXToF64( &x ); } float64_t slow_f64_mulAdd( float64_t a, float64_t b, float64_t c ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); floatXMul( &x, &y ); f64ToFloatX( c, &y ); floatXAdd( &x, &y ); return floatXToF64( &x ); } float64_t slow_f64_div( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); floatXDiv( &x, &y ); return floatXToF64( &x ); } float64_t slow_f64_rem( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); floatXRem( &x, &y ); return floatXToF64( &x ); } float64_t slow_f64_sqrt( float64_t a ) { struct floatX x; f64ToFloatX( a, &x ); floatXSqrt( &x ); return floatXToF64( &x ); } bool slow_f64_eq( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); return floatXEq( &x, &y ); } bool slow_f64_le( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLe( &x, &y ); } bool slow_f64_lt( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLt( &x, &y ); } bool slow_f64_eq_signaling( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXEq( &x, &y ); } bool slow_f64_le_quiet( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); return floatXLe( &x, &y ); } bool slow_f64_lt_quiet( float64_t a, float64_t b ) { struct floatX x, y; f64ToFloatX( a, &x ); f64ToFloatX( b, &y ); return floatXLt( &x, &y ); } #ifdef EXTFLOAT80 uint_fast32_t slow_extF80M_to_ui32( const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToUI32( &x, roundingMode, exact ); } uint_fast64_t slow_extF80M_to_ui64( const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToUI64( &x, roundingMode, exact ); } int_fast32_t slow_extF80M_to_i32( const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToI32( &x, roundingMode, exact ); } int_fast64_t slow_extF80M_to_i64( const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToI64( &x, roundingMode, exact ); } uint_fast32_t slow_extF80M_to_ui32_r_minMag( const extFloat80_t *aPtr, bool exact ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToUI32( &x, softfloat_round_minMag, exact ); } uint_fast64_t slow_extF80M_to_ui64_r_minMag( const extFloat80_t *aPtr, bool exact ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToUI64( &x, softfloat_round_minMag, exact ); } int_fast32_t slow_extF80M_to_i32_r_minMag( const extFloat80_t *aPtr, bool exact ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToI32( &x, softfloat_round_minMag, exact ); } int_fast64_t slow_extF80M_to_i64_r_minMag( const extFloat80_t *aPtr, bool exact ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToI64( &x, softfloat_round_minMag, exact ); } #ifdef FLOAT16 float16_t slow_extF80M_to_f16( const extFloat80_t *aPtr ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToF16( &x ); } #endif float32_t slow_extF80M_to_f32( const extFloat80_t *aPtr ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToF32( &x ); } float64_t slow_extF80M_to_f64( const extFloat80_t *aPtr ) { struct floatX x; extF80MToFloatX( aPtr, &x ); return floatXToF64( &x ); } #ifdef FLOAT128 void slow_extF80M_to_f128M( const extFloat80_t *aPtr, float128_t *zPtr ) { struct floatX x; extF80MToFloatX( aPtr, &x ); floatXToF128M( &x, zPtr ); } #endif void slow_extF80M_roundToInt( const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact, extFloat80_t *zPtr ) { struct floatX x; extF80MToFloatX( aPtr, &x ); floatXRoundToInt( &x, roundingMode, exact ); floatXToExtF80M( &x, zPtr ); } void slow_extF80M_add( const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); floatXAdd( &x, &y ); floatXToExtF80M( &x, zPtr ); } void slow_extF80M_sub( const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); y.sign = ! y.sign; floatXAdd( &x, &y ); floatXToExtF80M( &x, zPtr ); } void slow_extF80M_mul( const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); floatXMul( &x, &y ); floatXToExtF80M( &x, zPtr ); } void slow_extF80M_div( const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); floatXDiv( &x, &y ); floatXToExtF80M( &x, zPtr ); } void slow_extF80M_rem( const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); floatXRem( &x, &y ); floatXToExtF80M( &x, zPtr ); } void slow_extF80M_sqrt( const extFloat80_t *aPtr, extFloat80_t *zPtr ) { struct floatX x; extF80MToFloatX( aPtr, &x ); floatXSqrt( &x ); floatXToExtF80M( &x, zPtr ); } bool slow_extF80M_eq( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); return floatXEq( &x, &y ); } bool slow_extF80M_le( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLe( &x, &y ); } bool slow_extF80M_lt( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLt( &x, &y ); } bool slow_extF80M_eq_signaling( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXEq( &x, &y ); } bool slow_extF80M_le_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); return floatXLe( &x, &y ); } bool slow_extF80M_lt_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) { struct floatX x, y; extF80MToFloatX( aPtr, &x ); extF80MToFloatX( bPtr, &y ); return floatXLt( &x, &y ); } #endif #ifdef FLOAT128 uint_fast32_t slow_f128M_to_ui32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToUI32( &x, roundingMode, exact ); } uint_fast64_t slow_f128M_to_ui64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToUI64( &x, roundingMode, exact ); } int_fast32_t slow_f128M_to_i32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToI32( &x, roundingMode, exact ); } int_fast64_t slow_f128M_to_i64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToI64( &x, roundingMode, exact ); } uint_fast32_t slow_f128M_to_ui32_r_minMag( const float128_t *aPtr, bool exact ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToUI32( &x, softfloat_round_minMag, exact ); } uint_fast64_t slow_f128M_to_ui64_r_minMag( const float128_t *aPtr, bool exact ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToUI64( &x, softfloat_round_minMag, exact ); } int_fast32_t slow_f128M_to_i32_r_minMag( const float128_t *aPtr, bool exact ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToI32( &x, softfloat_round_minMag, exact ); } int_fast64_t slow_f128M_to_i64_r_minMag( const float128_t *aPtr, bool exact ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToI64( &x, softfloat_round_minMag, exact ); } #ifdef FLOAT16 float16_t slow_f128M_to_f16( const float128_t *aPtr ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToF16( &x ); } #endif float32_t slow_f128M_to_f32( const float128_t *aPtr ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToF32( &x ); } float64_t slow_f128M_to_f64( const float128_t *aPtr ) { struct floatX x; f128MToFloatX( aPtr, &x ); return floatXToF64( &x ); } #ifdef EXTFLOAT80 void slow_f128M_to_extF80M( const float128_t *aPtr, extFloat80_t *zPtr ) { struct floatX x; f128MToFloatX( aPtr, &x ); floatXToExtF80M( &x, zPtr ); } #endif void slow_f128M_roundToInt( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact, float128_t *zPtr ) { struct floatX x; f128MToFloatX( aPtr, &x ); floatXRoundToInt( &x, roundingMode, exact ); floatXToF128M( &x, zPtr ); } void slow_f128M_add( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); floatXAdd( &x, &y ); floatXToF128M( &x, zPtr ); } void slow_f128M_sub( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); y.sign = ! y.sign; floatXAdd( &x, &y ); floatXToF128M( &x, zPtr ); } void slow_f128M_mul( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); floatXMul( &x, &y ); floatXToF128M( &x, zPtr ); } void slow_f128M_mulAdd( const float128_t *aPtr, const float128_t *bPtr, const float128_t *cPtr, float128_t *zPtr ) { struct floatX256 x, y; f128MToFloatX256( aPtr, &x ); f128MToFloatX256( bPtr, &y ); floatX256Mul( &x, &y ); f128MToFloatX256( cPtr, &y ); floatX256Add( &x, &y ); floatX256ToF128M( &x, zPtr ); } void slow_f128M_div( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); floatXDiv( &x, &y ); floatXToF128M( &x, zPtr ); } void slow_f128M_rem( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); floatXRem( &x, &y ); floatXToF128M( &x, zPtr ); } void slow_f128M_sqrt( const float128_t *aPtr, float128_t *zPtr ) { struct floatX x; f128MToFloatX( aPtr, &x ); floatXSqrt( &x ); floatXToF128M( &x, zPtr ); } bool slow_f128M_eq( const float128_t *aPtr, const float128_t *bPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); return floatXEq( &x, &y ); } bool slow_f128M_le( const float128_t *aPtr, const float128_t *bPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLe( &x, &y ); } bool slow_f128M_lt( const float128_t *aPtr, const float128_t *bPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXLt( &x, &y ); } bool slow_f128M_eq_signaling( const float128_t *aPtr, const float128_t *bPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); if ( x.isNaN || y.isNaN ) { slowfloat_exceptionFlags |= softfloat_flag_invalid; } return floatXEq( &x, &y ); } bool slow_f128M_le_quiet( const float128_t *aPtr, const float128_t *bPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); return floatXLe( &x, &y ); } bool slow_f128M_lt_quiet( const float128_t *aPtr, const float128_t *bPtr ) { struct floatX x, y; f128MToFloatX( aPtr, &x ); f128MToFloatX( bPtr, &y ); return floatXLt( &x, &y ); } #endif