void softfloat_shortShiftRightExtendM( uint_fast8_t size_words, const uint32_t *aPtr, uint_fast8_t count, uint32_t *zPtr ) { uint_fast8_t negCount; unsigned int indexA, lastIndexA; uint32_t partWordZ, wordA; negCount = -count; indexA = indexWordLo( size_words ); lastIndexA = indexWordHi( size_words ); zPtr += indexWordLo( size_words + 1 ); partWordZ = 0; for (;;) { wordA = aPtr[indexA]; *zPtr = wordA<<(negCount & 31) | partWordZ; zPtr += wordIncr; partWordZ = wordA>>count; if ( indexA == lastIndexA ) break; indexA += wordIncr; } *zPtr = partWordZ; }
void softfloat_shiftRightJamM( uint_fast8_t size_words, const uint32_t *aPtr, uint32_t count, uint32_t *zPtr ) { uint32_t wordJam, wordCount, *ptr; uint_fast8_t i, innerCount; wordJam = 0; wordCount = count>>5; if ( wordCount ) { if ( size_words < wordCount ) wordCount = size_words; ptr = (uint32_t *) (aPtr + indexMultiwordLo( size_words, wordCount )); i = wordCount; do { wordJam = *ptr++; if ( wordJam ) break; --i; } while ( i ); ptr = zPtr; } if ( wordCount < size_words ) { aPtr += indexMultiwordHiBut( size_words, wordCount ); innerCount = count & 31; if ( innerCount ) { softfloat_shortShiftRightJamM( size_words - wordCount, aPtr, innerCount, zPtr + indexMultiwordLoBut( size_words, wordCount ) ); if ( ! wordCount ) goto wordJam; } else { aPtr += indexWordLo( size_words - wordCount ); ptr = zPtr + indexWordLo( size_words ); for ( i = size_words - wordCount; i; --i ) { *ptr = *aPtr; aPtr += wordIncr; ptr += wordIncr; } } ptr = zPtr + indexMultiwordHi( size_words, wordCount ); } do { *ptr++ = 0; --wordCount; } while ( wordCount ); wordJam: if ( wordJam ) zPtr[indexWordLo( size_words )] |= 1; }
void softfloat_shiftRightJam256M( const uint64_t *aPtr, uint_fast32_t count, uint64_t *zPtr ) { uint64_t wordJam; uint_fast32_t wordCount; uint64_t *ptr; uint_fast8_t i, innerCount; wordJam = 0; wordCount = count>>6; if ( wordCount ) { if ( 4 < wordCount ) wordCount = 4; ptr = (uint64_t *) (aPtr + indexMultiwordLo( 4, wordCount )); i = wordCount; do { wordJam = *ptr++; if ( wordJam ) break; --i; } while ( i ); ptr = zPtr; } if ( wordCount < 4 ) { aPtr += indexMultiwordHiBut( 4, wordCount ); innerCount = count & 63; if ( innerCount ) { softfloat_shortShiftRightJamM( 4 - wordCount, aPtr, innerCount, zPtr + indexMultiwordLoBut( 4, wordCount ) ); if ( ! wordCount ) goto wordJam; } else { aPtr += indexWordLo( 4 - wordCount ); ptr = zPtr + indexWordLo( 4 ); for ( i = 4 - wordCount; i; --i ) { *ptr = *aPtr; aPtr += wordIncr; ptr += wordIncr; } } ptr = zPtr + indexMultiwordHi( 4, wordCount ); } do { *ptr++ = 0; --wordCount; } while ( wordCount ); wordJam: if ( wordJam ) zPtr[indexWordLo( 4 )] |= 1; }
uint_fast8_t softfloat_addCarryM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint_fast8_t carry, uint32_t *zPtr ) { unsigned int index, lastIndex; uint32_t wordA, wordZ; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); for (;;) { wordA = aPtr[index]; wordZ = wordA + bPtr[index] + carry; zPtr[index] = wordZ; carry = carry ? (wordZ <= wordA) : (wordZ < wordA); if ( index == lastIndex ) break; index += wordIncr; } return carry; }
void softfloat_subM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ) { unsigned int index, lastIndex; uint_fast8_t borrow; uint32_t wordA, wordB; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); borrow = 0; for (;;) { wordA = aPtr[index]; wordB = bPtr[index]; zPtr[index] = wordA - wordB - borrow; if ( index == lastIndex ) break; borrow = borrow ? (wordA <= wordB) : (wordA < wordB); index += wordIncr; } }
void softfloat_shortShiftRightJamM( uint_fast8_t size_words, const uint32_t *aPtr, uint_fast8_t count, uint32_t *zPtr ) { uint_fast8_t negCount; unsigned int index, lastIndex; uint32_t partWordZ, wordA; negCount = -count; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); wordA = aPtr[index]; partWordZ = wordA>>count; if ( partWordZ<<count != wordA ) partWordZ |= 1; while ( index != lastIndex ) { wordA = aPtr[index + wordIncr]; zPtr[index] = wordA<<(negCount & 31) | partWordZ; index += wordIncr; partWordZ = wordA>>count; } zPtr[index] = partWordZ; }
void softfloat_sub1XM( uint_fast8_t size_words, uint32_t *zPtr ) { unsigned int index, lastIndex; uint32_t wordA; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); for (;;) { wordA = zPtr[index]; zPtr[index] = wordA - 1; if ( wordA || (index == lastIndex) ) break; index += wordIncr; } }
int_fast8_t softfloat_compare96M( const uint32_t *aPtr, const uint32_t *bPtr ) { unsigned int index, lastIndex; uint32_t wordA, wordB; index = indexWordHi( 3 ); lastIndex = indexWordLo( 3 ); for (;;) { wordA = aPtr[index]; wordB = bPtr[index]; if ( wordA != wordB ) return (wordA < wordB) ? -1 : 1; if ( index == lastIndex ) break; index -= wordIncr; } return 0; }
void softfloat_negXM( uint_fast8_t size_words, uint32_t *zPtr ) { unsigned int index, lastIndex; uint_fast8_t carry; uint32_t word; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); carry = 1; for (;;) { word = ~zPtr[index] + carry; zPtr[index] = word; if ( index == lastIndex ) break; index += wordIncr; if ( word ) carry = 0; } }
int_fast64_t softfloat_roundPackMToI64( bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint32_t sigExtra; bool doIncrement; uint64_t sig; union { uint64_t ui; int64_t i; } uZ; int64_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); sigExtra = extSigPtr[indexWordLo( 3 )]; doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; if ( ! (sigExtra & 0x7FFFFFFF) && roundNearEven ) sig &= ~1; } uZ.ui = sign ? -sig : sig; z = uZ.i; if ( z && ((z < 0) ^ sign) ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? i64_fromNegOverflow : i64_fromPosOverflow; }
void softfloat_add256M( const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ) { unsigned int index; uint_fast8_t carry; uint64_t wordA, wordZ; index = indexWordLo( 4 ); carry = 0; for (;;) { wordA = aPtr[index]; wordZ = wordA + bPtr[index] + carry; zPtr[index] = wordZ; if ( index == indexWordHi( 4 ) ) break; if ( wordZ != wordA ) carry = (wordZ < wordA); index += wordIncr; } }
uint_fast64_t softfloat_roundPackMToUI64( bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint32_t sigExtra; bool doIncrement; uint64_t sig; roundNearEven = (roundingMode == softfloat_round_near_even); sigExtra = extSigPtr[indexWordLo( 3 )]; doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; if ( ! (sigExtra & 0x7FFFFFFF) && roundNearEven ) sig &= ~1; } if ( sign && sig ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sig; invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return UINT64_C( 0xFFFFFFFFFFFFFFFF ); }
void softfloat_roundPackMToExtF80M( bool sign, int32_t exp, uint32_t *extSigPtr, uint_fast8_t roundingPrecision, struct extFloat80M *zSPtr ) { uint_fast8_t roundingMode; bool roundNearEven; uint64_t sig, roundIncrement, roundMask, roundBits; bool isTiny; uint32_t sigExtra; bool doIncrement; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; 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; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( extSigPtr[indexWordLo( 3 )] ) sig |= 1; 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 ); roundBits = sig & roundMask; if ( roundBits ) { if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); 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; goto packReturn; } if ( (0x7FFE < exp) || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) ) { goto overflow; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig = (sig & ~roundMask) | (roundMask + 1); goto packReturn; } #endif } sig += roundIncrement; if ( sig < roundIncrement ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } roundIncrement = roundMask + 1; if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { roundMask |= roundIncrement; } sig &= ~roundMask; goto packReturn; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ precision80: sigExtra = extSigPtr[indexWordLo( 3 )]; doIncrement = (0x80000000 <= 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 )); softfloat_shiftRightJam96M( extSigPtr, 1 - exp, extSigPtr ); exp = 0; sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; sigExtra = extSigPtr[indexWordLo( 3 )]; if ( sigExtra ) { if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= 1; goto packReturn; } #endif } doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( doIncrement ) { ++sig; sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); 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 ); if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) || (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ) { exp = 0x7FFF; sig = UINT64_C( 0x8000000000000000 ); } 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 ) { ++sig; if ( ! sig ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } else { sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ packReturn: zSPtr->signExp = packToExtF80UI64( sign, exp ); zSPtr->signif = sig; }
void f128M_roundToInt( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact, float128_t *zPtr ) { const uint32_t *aWPtr; uint32_t *zWPtr; uint32_t ui96; int32_t exp; uint32_t sigExtra; bool sign; uint_fast8_t bitPos; bool roundNear; unsigned int index, lastIndex; bool extra; uint32_t wordA, bit, wordZ; uint_fast8_t carry; uint32_t extrasMask; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ aWPtr = (const uint32_t *) aPtr; zWPtr = (uint32_t *) zPtr; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ ui96 = aWPtr[indexWordHi( 4 )]; exp = expF128UI96( ui96 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp < 0x3FFF ) { zWPtr[indexWord( 4, 2 )] = 0; zWPtr[indexWord( 4, 1 )] = 0; zWPtr[indexWord( 4, 0 )] = 0; sigExtra = aWPtr[indexWord( 4, 2 )]; if ( ! sigExtra ) { sigExtra = aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )]; } if ( ! sigExtra && ! (ui96 & 0x7FFFFFFF) ) goto ui96; if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; sign = signF128UI96( ui96 ); switch ( roundingMode ) { case softfloat_round_near_even: if ( ! fracF128UI96( ui96 ) && ! sigExtra ) break; case softfloat_round_near_maxMag: if ( exp == 0x3FFE ) goto mag1; break; case softfloat_round_min: if ( sign ) goto mag1; break; case softfloat_round_max: if ( ! sign ) goto mag1; break; } ui96 = packToF128UI96( sign, 0, 0 ); goto ui96; mag1: ui96 = packToF128UI96( sign, 0x3FFF, 0 ); goto ui96; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x406F <= exp ) { if ( (exp == 0x7FFF) && (fracF128UI96( ui96 ) || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )])) ) { softfloat_propagateNaNF128M( aWPtr, 0, zWPtr ); return; } zWPtr[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; zWPtr[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; zWPtr[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; goto ui96; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ bitPos = 0x406F - exp; roundNear = (roundingMode == softfloat_round_near_maxMag) || (roundingMode == softfloat_round_near_even); bitPos -= roundNear; index = indexWordLo( 4 ); lastIndex = indexWordHi( 4 ); extra = 0; for (;;) { wordA = aWPtr[index]; if ( bitPos < 32 ) break; if ( wordA ) extra = 1; zWPtr[index] = 0; index += wordIncr; bitPos -= 32; } bit = (uint32_t) 1<<bitPos; if ( roundNear ) { wordZ = wordA + bit; carry = (wordZ < wordA); bit <<= 1; extrasMask = bit - 1; if ( (roundingMode == softfloat_round_near_even) && ! extra && ! (wordZ & extrasMask) ) { if ( ! bit ) { zWPtr[index] = wordZ; index += wordIncr; wordZ = aWPtr[index] + carry; carry &= ! wordZ; zWPtr[index] = wordZ & ~1; goto propagateCarry; } wordZ &= ~bit; } } else { extrasMask = bit - 1; wordZ = wordA; carry = 0; if ( (roundingMode != softfloat_round_minMag) && (signF128UI96( ui96 ) ^ (roundingMode == softfloat_round_max)) ) { if ( extra || (wordA & extrasMask) ) { wordZ += bit; carry = (wordZ < wordA); } } } wordZ &= ~extrasMask; zWPtr[index] = wordZ; propagateCarry: while ( index != lastIndex ) { index += wordIncr; wordZ = aWPtr[index] + carry; zWPtr[index] = wordZ; carry &= ! wordZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exact && (softfloat_compare128M( aWPtr, zWPtr ) != 0) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ ui96: zWPtr[indexWordHi( 4 )] = ui96; }
void softfloat_mulAddF128M( const uint32_t *aWPtr, const uint32_t *bWPtr, const uint32_t *cWPtr, uint32_t *zWPtr, uint_fast8_t op ) { uint32_t uiA96; int32_t expA; uint32_t uiB96; int32_t expB; uint32_t uiC96; bool signC; int32_t expC; bool signProd, prodIsInfinite; uint32_t *ptr, uiZ96, sigA[4]; uint_fast8_t shiftCount; uint32_t sigX[5]; int32_t expProd; uint32_t sigProd[8], wordSig; bool doSub; uint_fast8_t (*addCarryMRoutinePtr)( uint_fast8_t, const uint32_t *, const uint32_t *, uint_fast8_t, uint32_t * ); int32_t expDiff; bool signZ; int32_t expZ; uint32_t *extSigPtr; uint_fast8_t carry; void (*roundPackRoutinePtr)( bool, int32_t, uint32_t *, uint32_t * ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiA96 = aWPtr[indexWordHi( 4 )]; expA = expF128UI96( uiA96 ); uiB96 = bWPtr[indexWordHi( 4 )]; expB = expF128UI96( uiB96 ); uiC96 = cWPtr[indexWordHi( 4 )]; signC = signF128UI96( uiC96 ) ^ (op == softfloat_mulAdd_subC); expC = expF128UI96( uiC96 ); signProd = signF128UI96( uiA96 ) ^ signF128UI96( uiB96 ) ^ (op == softfloat_mulAdd_subProd); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ prodIsInfinite = false; if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) { goto propagateNaN_ZC; } ptr = (uint32_t *) aWPtr; if ( ! (uint32_t) (uiA96<<1) ) goto possibleInvalidProd; if ( ! (uint32_t) (uiB96<<1) ) { ptr = (uint32_t *) bWPtr; possibleInvalidProd: if ( ! (ptr[indexWord( 4, 2 )] | ptr[indexWord( 4, 1 )] | ptr[indexWord( 4, 0 )]) ) { goto invalid; } } prodIsInfinite = true; } if ( expC == 0x7FFF ) { if ( fracF128UI96( uiC96 ) || (cWPtr[indexWord( 4, 2 )] | cWPtr[indexWord( 4, 1 )] | cWPtr[indexWord( 4, 0 )]) ) { zWPtr[indexWordHi( 4 )] = 0; goto propagateNaN_ZC; } if ( prodIsInfinite && (signProd != signC) ) goto invalid; goto copyC; } if ( prodIsInfinite ) { uiZ96 = packToF128UI96( signProd, 0x7FFF, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA ) { sigA[indexWordHi( 4 )] = fracF128UI96( uiA96 ) | 0x00010000; sigA[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; sigA[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; sigA[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; } else { expA = softfloat_shiftNormSigF128M( aWPtr, 0, sigA ); if ( expA == -128 ) goto zeroProd; } if ( expB ) { sigX[indexWordHi( 4 )] = fracF128UI96( uiB96 ) | 0x00010000; sigX[indexWord( 4, 2 )] = bWPtr[indexWord( 4, 2 )]; sigX[indexWord( 4, 1 )] = bWPtr[indexWord( 4, 1 )]; sigX[indexWord( 4, 0 )] = bWPtr[indexWord( 4, 0 )]; } else { expB = softfloat_shiftNormSigF128M( bWPtr, 0, sigX ); if ( expB == -128 ) goto zeroProd; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expProd = expA + expB - 0x3FF0; softfloat_mul128MTo256M( sigA, sigX, sigProd ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ wordSig = fracF128UI96( uiC96 ); if ( expC ) { --expC; wordSig |= 0x00010000; } sigX[indexWordHi( 5 )] = wordSig; sigX[indexWord( 5, 3 )] = cWPtr[indexWord( 4, 2 )]; sigX[indexWord( 5, 2 )] = cWPtr[indexWord( 4, 1 )]; sigX[indexWord( 5, 1 )] = cWPtr[indexWord( 4, 0 )]; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ doSub = (signProd != signC); addCarryMRoutinePtr = doSub ? softfloat_addComplCarryM : softfloat_addCarryM; expDiff = expProd - expC; if ( expDiff <= 0 ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ signZ = signC; expZ = expC; if ( sigProd[indexWord( 8, 2 )] || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )]) ) { sigProd[indexWord( 8, 3 )] |= 1; } extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )]; if ( expDiff ) { softfloat_shiftRightJam160M( extSigPtr, -expDiff, extSigPtr ); } carry = 0; if ( doSub ) { wordSig = extSigPtr[indexWordLo( 5 )]; extSigPtr[indexWordLo( 5 )] = -wordSig; carry = ! wordSig; } (*addCarryMRoutinePtr)( 4, &sigX[indexMultiwordHi( 5, 4 )], extSigPtr + indexMultiwordHi( 5, 4 ), carry, extSigPtr + indexMultiwordHi( 5, 4 ) ); wordSig = extSigPtr[indexWordHi( 5 )]; if ( ! expZ ) { if ( wordSig & 0x80000000 ) { signZ = ! signZ; softfloat_negX160M( extSigPtr ); wordSig = extSigPtr[indexWordHi( 5 )]; } goto checkCancellation; } if ( wordSig < 0x00010000 ) { --expZ; softfloat_add160M( extSigPtr, extSigPtr, extSigPtr ); goto roundPack; } goto extSigReady_noCancellation; } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ signZ = signProd; expZ = expProd; sigX[indexWordLo( 5 )] = 0; expDiff -= 128; if ( 0 <= expDiff ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ if ( expDiff ) softfloat_shiftRightJam160M( sigX, expDiff, sigX ); wordSig = sigX[indexWordLo( 5 )]; carry = 0; if ( doSub ) { carry = ! wordSig; wordSig = -wordSig; } carry = (*addCarryMRoutinePtr)( 4, &sigProd[indexMultiwordLo( 8, 4 )], &sigX[indexMultiwordHi( 5, 4 )], carry, &sigProd[indexMultiwordLo( 8, 4 )] ); sigProd[indexWord( 8, 2 )] |= wordSig; ptr = &sigProd[indexWord( 8, 4 )]; } else { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ shiftCount = expDiff & 31; if ( shiftCount ) { softfloat_shortShiftRight160M( sigX, shiftCount, sigX ); } expDiff >>= 5; extSigPtr = &sigProd[indexMultiwordLo( 8, 5 )] - wordIncr + expDiff * -wordIncr; carry = (*addCarryMRoutinePtr)( 5, extSigPtr, sigX, doSub, extSigPtr ); if ( expDiff == -4 ) { /*------------------------------------------------------------ *------------------------------------------------------------*/ wordSig = sigProd[indexWordHi( 8 )]; if ( wordSig & 0x80000000 ) { signZ = ! signZ; softfloat_negX256M( sigProd ); wordSig = sigProd[indexWordHi( 8 )]; } /*------------------------------------------------------------ *------------------------------------------------------------*/ if ( wordSig ) goto expProdBigger_noWordShift; wordSig = sigProd[indexWord( 8, 6 )]; if ( 0x00040000 <= wordSig ) goto expProdBigger_noWordShift; expZ -= 32; extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )] - wordIncr; for (;;) { if ( wordSig ) break; wordSig = extSigPtr[indexWord( 5, 3 )]; if ( 0x00040000 <= wordSig ) break; expZ -= 32; extSigPtr -= wordIncr; if ( extSigPtr == &sigProd[indexMultiwordLo( 8, 5 )] ) { goto checkCancellation; } } /*------------------------------------------------------------ *------------------------------------------------------------*/ ptr = extSigPtr + indexWordLo( 5 ); do { ptr -= wordIncr; if ( *ptr ) { extSigPtr[indexWordLo( 5 )] |= 1; break; } } while ( ptr != &sigProd[indexWordLo( 8 )] ); wordSig = extSigPtr[indexWordHi( 5 )]; goto extSigReady; } ptr = extSigPtr + indexWordHi( 5 ) + wordIncr; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( carry != doSub ) { if ( doSub ) { do { wordSig = *ptr; *ptr = wordSig - 1; ptr += wordIncr; } while ( ! wordSig ); } else { do { wordSig = *ptr + 1; *ptr = wordSig; ptr += wordIncr; } while ( ! wordSig ); } } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ expProdBigger_noWordShift: if ( sigProd[indexWord( 8, 2 )] || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )]) ) { sigProd[indexWord( 8, 3 )] |= 1; } extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )]; wordSig = extSigPtr[indexWordHi( 5 )]; } extSigReady: roundPackRoutinePtr = softfloat_normRoundPackMToF128M; if ( wordSig < 0x00010000 ) goto doRoundPack; extSigReady_noCancellation: if ( 0x00020000 <= wordSig ) { ++expZ; softfloat_shortShiftRightJam160M( extSigPtr, 1, extSigPtr ); } roundPack: roundPackRoutinePtr = softfloat_roundPackMToF128M; doRoundPack: (*roundPackRoutinePtr)( signZ, expZ, extSigPtr, zWPtr ); return; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_invalidF128M( zWPtr ); propagateNaN_ZC: softfloat_propagateNaNF128M( zWPtr, cWPtr, zWPtr ); return; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zeroProd: if ( ! (uint32_t) (uiC96<<1) && (signProd != signC) && ! cWPtr[indexWord( 4, 2 )] && ! (cWPtr[indexWord( 4, 1 )] | cWPtr[indexWord( 4, 0 )]) ) { goto completeCancellation; } copyC: zWPtr[indexWordHi( 4 )] = uiC96; zWPtr[indexWord( 4, 2 )] = cWPtr[indexWord( 4, 2 )]; zWPtr[indexWord( 4, 1 )] = cWPtr[indexWord( 4, 1 )]; zWPtr[indexWord( 4, 0 )] = cWPtr[indexWord( 4, 0 )]; return; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ checkCancellation: if ( wordSig || (extSigPtr[indexWord( 5, 3 )] | extSigPtr[indexWord( 5, 2 )]) || (extSigPtr[indexWord( 5, 1 )] | extSigPtr[indexWord( 5, 0 )]) ) { goto extSigReady; } completeCancellation: uiZ96 = packToF128UI96( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); uiZ: zWPtr[indexWordHi( 4 )] = uiZ96; zWPtr[indexWord( 4, 2 )] = 0; zWPtr[indexWord( 4, 1 )] = 0; zWPtr[indexWord( 4, 0 )] = 0; }
void softfloat_addF128M( const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr, bool negateB ) { uint32_t uiA96; int32_t expA; uint32_t uiB96; int32_t expB; uint32_t uiZ96; bool signZ, signB; const uint32_t *tempPtr; uint32_t sig96A, sig96B; int32_t expDiff; uint_fast8_t (*addCarryMRoutinePtr)( uint_fast8_t, const uint32_t *, const uint32_t *, uint_fast8_t, uint32_t * ); uint32_t extSigZ[5], wordSigZ; uint_fast8_t carry; void (*roundPackRoutinePtr)( bool, int32_t, uint32_t *, uint32_t * ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiA96 = aWPtr[indexWordHi( 4 )]; expA = expF128UI96( uiA96 ); uiB96 = bWPtr[indexWordHi( 4 )]; expB = expF128UI96( uiB96 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) return; uiZ96 = uiA96; if ( expB == 0x7FFF ) { uiZ96 = uiB96 ^ packToF128UI96( negateB, 0, 0 ); if ( (expA == 0x7FFF) && (uiZ96 != uiA96) ) { softfloat_invalidF128M( zWPtr ); return; } } zWPtr[indexWordHi( 4 )] = uiZ96; zWPtr[indexWord( 4, 2 )] = 0; zWPtr[indexWord( 4, 1 )] = 0; zWPtr[indexWord( 4, 0 )] = 0; return; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ signZ = signF128UI96( uiA96 ); signB = signF128UI96( uiB96 ) ^ negateB; negateB = (signZ != signB); if ( (uint32_t) (uiA96<<1) < (uint32_t) (uiB96<<1) ) { signZ = signB; expA = expB; expB = expF128UI96( uiA96 ); tempPtr = aWPtr; aWPtr = bWPtr; bWPtr = tempPtr; uiA96 = uiB96; uiB96 = bWPtr[indexWordHi( 4 )]; } sig96A = fracF128UI96( uiA96 ); sig96B = fracF128UI96( uiB96 ); if ( expA ) { --expA; sig96A |= 0x00010000; if ( expB ) { --expB; sig96B |= 0x00010000; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ addCarryMRoutinePtr = negateB ? softfloat_addComplCarryM : softfloat_addCarryM; expDiff = expA - expB; if ( expDiff ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ extSigZ[indexWordHi( 5 )] = sig96B; extSigZ[indexWord( 5, 3 )] = bWPtr[indexWord( 4, 2 )]; extSigZ[indexWord( 5, 2 )] = bWPtr[indexWord( 4, 1 )]; extSigZ[indexWord( 5, 1 )] = bWPtr[indexWord( 4, 0 )]; extSigZ[indexWord( 5, 0 )] = 0; softfloat_shiftRightJam160M( extSigZ, expDiff, extSigZ ); sig96B = extSigZ[indexWordHi( 5 )]; carry = 0; if ( negateB ) { sig96B = ~sig96B; wordSigZ = extSigZ[indexWordLo( 5 )]; extSigZ[indexWordLo( 5 )] = -wordSigZ; carry = ! wordSigZ; } carry = (*addCarryMRoutinePtr)( 3, &aWPtr[indexMultiwordLo( 4, 3 )], &extSigZ[indexMultiword( 5, 3, 1 )], carry, &extSigZ[indexMultiword( 5, 3, 1 )] ); wordSigZ = sig96A + sig96B + carry; } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ extSigZ[indexWordLo( 5 )] = 0; carry = (*addCarryMRoutinePtr)( 3, &aWPtr[indexMultiwordLo( 4, 3 )], &bWPtr[indexMultiwordLo( 4, 3 )], negateB, &extSigZ[indexMultiword( 5, 3, 1 )] ); if ( negateB ) { wordSigZ = sig96A + ~sig96B + carry; if ( wordSigZ & 0x80000000 ) { signZ = ! signZ; carry = softfloat_addComplCarry96M( &bWPtr[indexMultiwordLo( 4, 3 )], &aWPtr[indexMultiwordLo( 4, 3 )], 1, &extSigZ[indexMultiword( 5, 3, 1 )] ); wordSigZ = sig96B + ~sig96A + carry; } else { if ( ! wordSigZ && ! extSigZ[indexWord( 5, 3 )] && ! ( extSigZ[indexWord( 5, 2 )] | extSigZ[indexWord( 5, 1 )] | extSigZ[indexWord( 5, 0 )] ) ) { signZ = (softfloat_roundingMode == softfloat_round_min); zWPtr[indexWordHi( 4 )] = packToF128UI96( signZ, 0, 0 ); zWPtr[indexWord( 4, 2 )] = 0; zWPtr[indexWord( 4, 1 )] = 0; zWPtr[indexWord( 4, 0 )] = 0; return; } } } else { wordSigZ = sig96A + sig96B + carry; } } extSigZ[indexWordHi( 5 )] = wordSigZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundPackRoutinePtr = softfloat_normRoundPackMToF128M; if ( 0x00010000 <= wordSigZ ) { if ( 0x00020000 <= wordSigZ ) { ++expA; softfloat_shortShiftRightJam160M( extSigZ, 1, extSigZ ); } roundPackRoutinePtr = softfloat_roundPackMToF128M; } (*roundPackRoutinePtr)( signZ, expA, extSigZ, zWPtr ); }
void softfloat_roundPackMToF128M( bool sign, int32_t exp, uint32_t *extSigPtr, uint32_t *zWPtr ) { uint_fast8_t roundingMode; bool roundNearEven; uint32_t sigExtra; bool doIncrement, isTiny; static const uint32_t maxSig[4] = INIT_UINTM4( 0x0001FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF ); uint32_t ui, uj; roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); sigExtra = extSigPtr[indexWordLo( 5 )]; doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( 0x7FFD <= (uint32_t) exp ) { if ( exp < 0 ) { isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < -1) || ! doIncrement || (softfloat_compare128M( extSigPtr + indexMultiwordHi( 5, 4 ), maxSig ) < 0); softfloat_shiftRightJam160M( extSigPtr, -exp, extSigPtr ); exp = 0; sigExtra = extSigPtr[indexWordLo( 5 )]; if ( isTiny && sigExtra ) { softfloat_raiseFlags( softfloat_flag_underflow ); } doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } } else if ( (0x7FFD < exp) || ((exp == 0x7FFD) && doIncrement && (softfloat_compare128M( extSigPtr + indexMultiwordHi( 5, 4 ), maxSig ) == 0)) ) { softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) || (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ) { ui = packToF128UI96( sign, 0x7FFF, 0 ); uj = 0; } else { ui = packToF128UI96( sign, 0x7FFE, 0x0000FFFF ); uj = 0xFFFFFFFF; } zWPtr[indexWordHi( 4 )] = ui; zWPtr[indexWord( 4, 2 )] = uj; zWPtr[indexWord( 4, 1 )] = uj; zWPtr[indexWord( 4, 0 )] = uj; return; } } if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact; uj = extSigPtr[indexWord( 5, 1 )]; if ( doIncrement ) { ++uj; if ( uj ) { if ( ! (sigExtra & 0x7FFFFFFF) && roundNearEven ) uj &= ~1; zWPtr[indexWord( 4, 2 )] = extSigPtr[indexWord( 5, 3 )]; zWPtr[indexWord( 4, 1 )] = extSigPtr[indexWord( 5, 2 )]; zWPtr[indexWord( 4, 0 )] = uj; ui = extSigPtr[indexWordHi( 5 )]; } else { zWPtr[indexWord( 4, 0 )] = uj; ui = extSigPtr[indexWord( 5, 2 )] + 1; zWPtr[indexWord( 4, 1 )] = ui; uj = extSigPtr[indexWord( 5, 3 )]; if ( ui ) { zWPtr[indexWord( 4, 2 )] = uj; ui = extSigPtr[indexWordHi( 5 )]; } else { ++uj; zWPtr[indexWord( 4, 2 )] = uj; ui = extSigPtr[indexWordHi( 5 )]; if ( ! uj ) ++ui; } } } else { zWPtr[indexWord( 4, 0 )] = uj; ui = extSigPtr[indexWord( 5, 2 )]; zWPtr[indexWord( 4, 1 )] = ui; uj |= ui; ui = extSigPtr[indexWord( 5, 3 )]; zWPtr[indexWord( 4, 2 )] = ui; uj |= ui; ui = extSigPtr[indexWordHi( 5 )]; uj |= ui; if ( ! uj ) exp = 0; } zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, exp, ui ); }
void extF80M_mul( const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) { const struct extFloat80M *aSPtr, *bSPtr; struct extFloat80M *zSPtr; uint_fast16_t uiA64; int32_t expA; uint_fast16_t uiB64; int32_t expB; bool signZ; uint_fast16_t exp, uiZ64; uint64_t uiZ0, sigA, sigB; int32_t expZ; uint32_t sigProd[4], *extSigZPtr; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ aSPtr = (const struct extFloat80M *) aPtr; bSPtr = (const struct extFloat80M *) bPtr; zSPtr = (struct extFloat80M *) zPtr; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiA64 = aSPtr->signExp; expA = expExtF80UI64( uiA64 ); uiB64 = bSPtr->signExp; expB = expExtF80UI64( uiB64 ); signZ = signExtF80UI64( uiA64 ) ^ signExtF80UI64( uiB64 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; if ( (! aSPtr->signif && (expA != 0x7FFF)) || (! bSPtr->signif && (expB != 0x7FFF)) ) { softfloat_invalidExtF80M( zSPtr ); return; } uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); uiZ0 = UINT64_C( 0x8000000000000000 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) expA = 1; sigA = aSPtr->signif; if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { if ( ! sigA ) goto zero; expA += softfloat_normExtF80SigM( &sigA ); } if ( ! expB ) expB = 1; sigB = bSPtr->signif; if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { if ( ! sigB ) goto zero; expB += softfloat_normExtF80SigM( &sigB ); } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FFE; softfloat_mul64To128M( sigA, sigB, sigProd ); if ( sigProd[indexWordLo( 4 )] ) sigProd[indexWord( 4, 1 )] |= 1; extSigZPtr = &sigProd[indexMultiwordHi( 4, 3 )]; if ( sigProd[indexWordHi( 4 )] < 0x80000000 ) { --expZ; softfloat_add96M( extSigZPtr, extSigZPtr, extSigZPtr ); } softfloat_roundPackMToExtF80M( signZ, expZ, extSigZPtr, extF80_roundingPrecision, zSPtr ); return; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ64 = packToExtF80UI64( signZ, 0 ); uiZ0 = 0; uiZ: zSPtr->signExp = uiZ64; zSPtr->signif = uiZ0; }