1 
2 /*============================================================================
3 
4 This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
5 Package, Release 3e, by John R. Hauser.
6 
7 Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of
8 California.  All rights reserved.
9 
10 Redistribution and use in source and binary forms, with or without
11 modification, 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 
24 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
25 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
27 DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
28 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 ON 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
33 SOFTWARE, 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 
44 void
softfloat_mulAddF128M(const uint32_t * aWPtr,const uint32_t * bWPtr,const uint32_t * cWPtr,uint32_t * zWPtr,uint_fast8_t op)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