1
2/*============================================================================
3
4This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
5Package, Release 3e, by John R. Hauser.
6
7Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of
8California.  All rights reserved.
9
10Redistribution and use in source and binary forms, with or without
11modification, are permitted provided that the following conditions are met:
12
13 1. Redistributions of source code must retain the above copyright notice,
14    this list of conditions, and the following disclaimer.
15
16 2. Redistributions in binary form must reproduce the above copyright notice,
17    this list of conditions, and the following disclaimer in the documentation
18    and/or other materials provided with the distribution.
19
20 3. Neither the name of the University nor the names of its contributors may
21    be used to endorse or promote products derived from this software without
22    specific prior written permission.
23
24THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
25EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
27DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
28DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35=============================================================================*/
36
37#include <stdbool.h>
38#include <stdint.h>
39#include "platform.h"
40#include "internals.h"
41#include "specialize.h"
42#include "softfloat.h"
43
44void
45 softfloat_mulAddF128M(
46     const uint32_t *aWPtr,
47     const uint32_t *bWPtr,
48     const uint32_t *cWPtr,
49     uint32_t *zWPtr,
50     uint_fast8_t op
51 )
52{
53    uint32_t uiA96;
54    int32_t expA;
55    uint32_t uiB96;
56    int32_t expB;
57    uint32_t uiC96;
58    bool signC;
59    int32_t expC;
60    bool signProd, prodIsInfinite;
61    uint32_t *ptr, uiZ96, sigA[4];
62    uint_fast8_t shiftDist;
63    uint32_t sigX[5];
64    int32_t expProd;
65    uint32_t sigProd[8], wordSig;
66    bool doSub;
67    uint_fast8_t
68     (*addCarryMRoutinePtr)(
69         uint_fast8_t,
70         const uint32_t *,
71         const uint32_t *,
72         uint_fast8_t,
73         uint32_t *
74     );
75    int32_t expDiff;
76    bool signZ;
77    int32_t expZ;
78    uint32_t *extSigPtr;
79    uint_fast8_t carry;
80    void (*roundPackRoutinePtr)( bool, int32_t, uint32_t *, uint32_t * );
81
82    /*------------------------------------------------------------------------
83    *------------------------------------------------------------------------*/
84    uiA96 = aWPtr[indexWordHi( 4 )];
85    expA = expF128UI96( uiA96 );
86    uiB96 = bWPtr[indexWordHi( 4 )];
87    expB = expF128UI96( uiB96 );
88    uiC96 = cWPtr[indexWordHi( 4 )];
89    signC = signF128UI96( uiC96 ) ^ (op == softfloat_mulAdd_subC);
90    expC = expF128UI96( uiC96 );
91    signProd =
92        signF128UI96( uiA96 ) ^ signF128UI96( uiB96 )
93            ^ (op == softfloat_mulAdd_subProd);
94    /*------------------------------------------------------------------------
95    *------------------------------------------------------------------------*/
96    prodIsInfinite = false;
97    if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) {
98        if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) {
99            goto propagateNaN_ZC;
100        }
101        ptr = (uint32_t *) aWPtr;
102        if ( ! (uint32_t) (uiA96<<1) ) goto possibleInvalidProd;
103        if ( ! (uint32_t) (uiB96<<1) ) {
104            ptr = (uint32_t *) bWPtr;
105     possibleInvalidProd:
106            if (
107                ! (ptr[indexWord( 4, 2 )] | ptr[indexWord( 4, 1 )]
108                       | ptr[indexWord( 4, 0 )])
109            ) {
110                goto invalid;
111            }
112        }
113        prodIsInfinite = true;
114    }
115    if ( expC == 0x7FFF ) {
116        if (
117            fracF128UI96( uiC96 )
118                || (cWPtr[indexWord( 4, 2 )] | cWPtr[indexWord( 4, 1 )]
119                        | cWPtr[indexWord( 4, 0 )])
120        ) {
121            zWPtr[indexWordHi( 4 )] = 0;
122            goto propagateNaN_ZC;
123        }
124        if ( prodIsInfinite && (signProd != signC) ) goto invalid;
125        goto copyC;
126    }
127    if ( prodIsInfinite ) {
128        uiZ96 = packToF128UI96( signProd, 0x7FFF, 0 );
129        goto uiZ;
130    }
131    /*------------------------------------------------------------------------
132    *------------------------------------------------------------------------*/
133    if ( expA ) {
134        sigA[indexWordHi( 4 )] = fracF128UI96( uiA96 ) | 0x00010000;
135        sigA[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )];
136        sigA[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )];
137        sigA[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )];
138    } else {
139        expA = softfloat_shiftNormSigF128M( aWPtr, 0, sigA );
140        if ( expA == -128 ) goto zeroProd;
141    }
142    if ( expB ) {
143        sigX[indexWordHi( 4 )] = fracF128UI96( uiB96 ) | 0x00010000;
144        sigX[indexWord( 4, 2 )] = bWPtr[indexWord( 4, 2 )];
145        sigX[indexWord( 4, 1 )] = bWPtr[indexWord( 4, 1 )];
146        sigX[indexWord( 4, 0 )] = bWPtr[indexWord( 4, 0 )];
147    } else {
148        expB = softfloat_shiftNormSigF128M( bWPtr, 0, sigX );
149        if ( expB == -128 ) goto zeroProd;
150    }
151    /*------------------------------------------------------------------------
152    *------------------------------------------------------------------------*/
153    expProd = expA + expB - 0x3FF0;
154    softfloat_mul128MTo256M( sigA, sigX, sigProd );
155    /*------------------------------------------------------------------------
156    *------------------------------------------------------------------------*/
157    wordSig = fracF128UI96( uiC96 );
158    if ( expC ) {
159        --expC;
160        wordSig |= 0x00010000;
161    }
162    sigX[indexWordHi( 5 )] = wordSig;
163    sigX[indexWord( 5, 3 )] = cWPtr[indexWord( 4, 2 )];
164    sigX[indexWord( 5, 2 )] = cWPtr[indexWord( 4, 1 )];
165    sigX[indexWord( 5, 1 )] = cWPtr[indexWord( 4, 0 )];
166    /*------------------------------------------------------------------------
167    *------------------------------------------------------------------------*/
168    doSub = (signProd != signC);
169    addCarryMRoutinePtr =
170        doSub ? softfloat_addComplCarryM : softfloat_addCarryM;
171    expDiff = expProd - expC;
172    if ( expDiff <= 0 ) {
173        /*--------------------------------------------------------------------
174        *--------------------------------------------------------------------*/
175        signZ = signC;
176        expZ = expC;
177        if (
178            sigProd[indexWord( 8, 2 )]
179                || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )])
180        ) {
181            sigProd[indexWord( 8, 3 )] |= 1;
182        }
183        extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )];
184        if ( expDiff ) {
185            softfloat_shiftRightJam160M( extSigPtr, -expDiff, extSigPtr );
186        }
187        carry = 0;
188        if ( doSub ) {
189            wordSig = extSigPtr[indexWordLo( 5 )];
190            extSigPtr[indexWordLo( 5 )] = -wordSig;
191            carry = ! wordSig;
192        }
193        (*addCarryMRoutinePtr)(
194            4,
195            &sigX[indexMultiwordHi( 5, 4 )],
196            extSigPtr + indexMultiwordHi( 5, 4 ),
197            carry,
198            extSigPtr + indexMultiwordHi( 5, 4 )
199        );
200        wordSig = extSigPtr[indexWordHi( 5 )];
201        if ( ! expZ ) {
202            if ( wordSig & 0x80000000 ) {
203                signZ = ! signZ;
204                softfloat_negX160M( extSigPtr );
205                wordSig = extSigPtr[indexWordHi( 5 )];
206            }
207            goto checkCancellation;
208        }
209        if ( wordSig < 0x00010000 ) {
210            --expZ;
211            softfloat_add160M( extSigPtr, extSigPtr, extSigPtr );
212            goto roundPack;
213        }
214        goto extSigReady_noCancellation;
215    } else {
216        /*--------------------------------------------------------------------
217        *--------------------------------------------------------------------*/
218        signZ = signProd;
219        expZ = expProd;
220        sigX[indexWordLo( 5 )] = 0;
221        expDiff -= 128;
222        if ( 0 <= expDiff ) {
223            /*----------------------------------------------------------------
224            *----------------------------------------------------------------*/
225            if ( expDiff ) softfloat_shiftRightJam160M( sigX, expDiff, sigX );
226            wordSig = sigX[indexWordLo( 5 )];
227            carry = 0;
228            if ( doSub ) {
229                carry = ! wordSig;
230                wordSig = -wordSig;
231            }
232            carry =
233                (*addCarryMRoutinePtr)(
234                    4,
235                    &sigProd[indexMultiwordLo( 8, 4 )],
236                    &sigX[indexMultiwordHi( 5, 4 )],
237                    carry,
238                    &sigProd[indexMultiwordLo( 8, 4 )]
239                );
240            sigProd[indexWord( 8, 2 )] |= wordSig;
241            ptr = &sigProd[indexWord( 8, 4 )];
242        } else {
243            /*----------------------------------------------------------------
244            *----------------------------------------------------------------*/
245            shiftDist = expDiff & 31;
246            if ( shiftDist ) {
247                softfloat_shortShiftRight160M( sigX, shiftDist, sigX );
248            }
249            expDiff >>= 5;
250            extSigPtr =
251                &sigProd[indexMultiwordLo( 8, 5 )] - wordIncr
252                    + expDiff * -wordIncr;
253            carry =
254                (*addCarryMRoutinePtr)( 5, extSigPtr, sigX, doSub, extSigPtr );
255            if ( expDiff == -4 ) {
256                /*------------------------------------------------------------
257                *------------------------------------------------------------*/
258                wordSig = sigProd[indexWordHi( 8 )];
259                if ( wordSig & 0x80000000 ) {
260                    signZ = ! signZ;
261                    softfloat_negX256M( sigProd );
262                    wordSig = sigProd[indexWordHi( 8 )];
263                }
264                /*------------------------------------------------------------
265                *------------------------------------------------------------*/
266                if ( wordSig ) goto expProdBigger_noWordShift;
267                wordSig = sigProd[indexWord( 8, 6 )];
268                if ( 0x00040000 <= wordSig ) goto expProdBigger_noWordShift;
269                expZ -= 32;
270                extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )] - wordIncr;
271                for (;;) {
272                    if ( wordSig ) break;
273                    wordSig = extSigPtr[indexWord( 5, 3 )];
274                    if ( 0x00040000 <= wordSig ) break;
275                    expZ -= 32;
276                    extSigPtr -= wordIncr;
277                    if ( extSigPtr == &sigProd[indexMultiwordLo( 8, 5 )] ) {
278                        goto checkCancellation;
279                    }
280                }
281                /*------------------------------------------------------------
282                *------------------------------------------------------------*/
283                ptr = extSigPtr + indexWordLo( 5 );
284                do {
285                    ptr -= wordIncr;
286                    if ( *ptr ) {
287                        extSigPtr[indexWordLo( 5 )] |= 1;
288                        break;
289                    }
290                } while ( ptr != &sigProd[indexWordLo( 8 )] );
291                wordSig = extSigPtr[indexWordHi( 5 )];
292                goto extSigReady;
293            }
294            ptr = extSigPtr + indexWordHi( 5 ) + wordIncr;
295        }
296        /*--------------------------------------------------------------------
297        *--------------------------------------------------------------------*/
298        if ( carry != doSub ) {
299            if ( doSub ) {
300                do {
301                    wordSig = *ptr;
302                    *ptr = wordSig - 1;
303                    ptr += wordIncr;
304                } while ( ! wordSig );
305            } else {
306                do {
307                    wordSig = *ptr + 1;
308                    *ptr = wordSig;
309                    ptr += wordIncr;
310                } while ( ! wordSig );
311            }
312        }
313        /*--------------------------------------------------------------------
314        *--------------------------------------------------------------------*/
315     expProdBigger_noWordShift:
316        if (
317            sigProd[indexWord( 8, 2 )]
318                || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )])
319        ) {
320            sigProd[indexWord( 8, 3 )] |= 1;
321        }
322        extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )];
323        wordSig = extSigPtr[indexWordHi( 5 )];
324    }
325 extSigReady:
326    roundPackRoutinePtr = softfloat_normRoundPackMToF128M;
327    if ( wordSig < 0x00010000 ) goto doRoundPack;
328 extSigReady_noCancellation:
329    if ( 0x00020000 <= wordSig ) {
330        ++expZ;
331        softfloat_shortShiftRightJam160M( extSigPtr, 1, extSigPtr );
332    }
333 roundPack:
334    roundPackRoutinePtr = softfloat_roundPackMToF128M;
335 doRoundPack:
336    (*roundPackRoutinePtr)( signZ, expZ, extSigPtr, zWPtr );
337    return;
338    /*------------------------------------------------------------------------
339    *------------------------------------------------------------------------*/
340 invalid:
341    softfloat_invalidF128M( zWPtr );
342 propagateNaN_ZC:
343    softfloat_propagateNaNF128M( zWPtr, cWPtr, zWPtr );
344    return;
345    /*------------------------------------------------------------------------
346    *------------------------------------------------------------------------*/
347 zeroProd:
348    if (
349        ! (uint32_t) (uiC96<<1) && (signProd != signC)
350            && ! cWPtr[indexWord( 4, 2 )]
351            && ! (cWPtr[indexWord( 4, 1 )] | cWPtr[indexWord( 4, 0 )])
352    ) {
353        goto completeCancellation;
354    }
355 copyC:
356    zWPtr[indexWordHi( 4 )] = uiC96;
357    zWPtr[indexWord( 4, 2 )] = cWPtr[indexWord( 4, 2 )];
358    zWPtr[indexWord( 4, 1 )] = cWPtr[indexWord( 4, 1 )];
359    zWPtr[indexWord( 4, 0 )] = cWPtr[indexWord( 4, 0 )];
360    return;
361    /*------------------------------------------------------------------------
362    *------------------------------------------------------------------------*/
363 checkCancellation:
364    if (
365        wordSig
366            || (extSigPtr[indexWord( 5, 3 )] | extSigPtr[indexWord( 5, 2 )])
367            || (extSigPtr[indexWord( 5, 1 )] | extSigPtr[indexWord( 5, 0 )])
368    ) {
369        goto extSigReady;
370    }
371 completeCancellation:
372    uiZ96 =
373        packToF128UI96(
374            (softfloat_roundingMode == softfloat_round_min), 0, 0 );
375 uiZ:
376    zWPtr[indexWordHi( 4 )] = uiZ96;
377    zWPtr[indexWord( 4, 2 )] = 0;
378    zWPtr[indexWord( 4, 1 )] = 0;
379    zWPtr[indexWord( 4, 0 )] = 0;
380
381}
382
383