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;

}
Example #2
0
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;

}
Example #3
0
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;

}
Example #4
0
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;

}
Example #5
0
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;

}
Example #7
0
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;
    }

}
Example #8
0
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;

}
Example #9
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;

}
Example #11
0
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 );

}
Example #13
0
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;

}
Example #15
0
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;

}
Example #16
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 );

}
Example #17
0
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 );

}
Example #18
0
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;

}