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