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 The Regents of the University of California.
9 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 float32_t
softfloat_mulAddF32(uint_fast32_t uiA,uint_fast32_t uiB,uint_fast32_t uiC,uint_fast8_t op)46  softfloat_mulAddF32(
47      uint_fast32_t uiA, uint_fast32_t uiB, uint_fast32_t uiC, uint_fast8_t op )
48 {
49     bool signA;
50     int_fast16_t expA;
51     uint_fast32_t sigA;
52     bool signB;
53     int_fast16_t expB;
54     uint_fast32_t sigB;
55     bool signC;
56     int_fast16_t expC;
57     uint_fast32_t sigC;
58     bool signProd;
59     uint_fast32_t magBits, uiZ;
60     struct exp16_sig32 normExpSig;
61     int_fast16_t expProd;
62     uint_fast64_t sigProd;
63     bool signZ;
64     int_fast16_t expZ;
65     uint_fast32_t sigZ;
66     int_fast16_t expDiff;
67     uint_fast64_t sig64Z, sig64C;
68     int_fast8_t shiftCount;
69     union ui32_f32 uZ;
70 
71     signA = signF32UI( uiA );
72     expA  = expF32UI( uiA );
73     sigA  = fracF32UI( uiA );
74     signB = signF32UI( uiB );
75     expB  = expF32UI( uiB );
76     sigB  = fracF32UI( uiB );
77     signC = signF32UI( uiC ) ^ (op == softfloat_mulAdd_subC);
78     expC  = expF32UI( uiC );
79     sigC  = fracF32UI( uiC );
80     signProd = signA ^ signB ^ (op == softfloat_mulAdd_subProd);
81     if ( expA == 0xFF ) {
82         if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN_ABC;
83         magBits = expB | sigB;
84         goto infProdArg;
85     }
86     if ( expB == 0xFF ) {
87         if ( sigB ) goto propagateNaN_ABC;
88         magBits = expA | sigA;
89         goto infProdArg;
90     }
91     if ( expC == 0xFF ) {
92         if ( sigC ) {
93             uiZ = 0;
94             goto propagateNaN_ZC;
95         }
96         uiZ = uiC;
97         goto uiZ;
98     }
99     if ( ! expA ) {
100         if ( ! sigA ) goto zeroProd;
101         normExpSig = softfloat_normSubnormalF32Sig( sigA );
102         expA = normExpSig.exp;
103         sigA = normExpSig.sig;
104     }
105     if ( ! expB ) {
106         if ( ! sigB ) goto zeroProd;
107         normExpSig = softfloat_normSubnormalF32Sig( sigB );
108         expB = normExpSig.exp;
109         sigB = normExpSig.sig;
110     }
111     expProd = expA + expB - 0x7E;
112     sigA = (sigA | 0x00800000)<<7;
113     sigB = (sigB | 0x00800000)<<7;
114     sigProd = (uint_fast64_t) sigA * sigB;
115     if ( sigProd < UINT64_C( 0x2000000000000000 ) ) {
116         --expProd;
117         sigProd <<= 1;
118     }
119     signZ = signProd;
120     if ( ! expC ) {
121         if ( ! sigC ) {
122             expZ = expProd - 1;
123             sigZ = softfloat_shortShiftRightJam64( sigProd, 31 );
124             goto roundPack;
125         }
126         normExpSig = softfloat_normSubnormalF32Sig( sigC );
127         expC = normExpSig.exp;
128         sigC = normExpSig.sig;
129     }
130     sigC = (sigC | 0x00800000)<<6;
131     expDiff = expProd - expC;
132     if ( signProd == signC ) {
133         if ( expDiff <= 0 ) {
134             expZ = expC;
135             sigZ = sigC + softfloat_shiftRightJam64( sigProd, 32 - expDiff );
136         } else {
137             expZ = expProd;
138             sig64Z =
139                 sigProd
140                     + softfloat_shiftRightJam64(
141                           (uint_fast64_t) sigC<<32, expDiff );
142             sigZ = softfloat_shortShiftRightJam64( sig64Z, 32 );
143         }
144         if ( sigZ < 0x40000000 ) {
145             --expZ;
146             sigZ <<= 1;
147         }
148     } else {
149         sig64C = (uint_fast64_t) sigC<<32;
150         if ( expDiff < 0 ) {
151             signZ = signC;
152             expZ = expC;
153             sig64Z = sig64C - softfloat_shiftRightJam64( sigProd, -expDiff );
154         } else if ( ! expDiff ) {
155             expZ = expProd;
156             sig64Z = sigProd - sig64C;
157             if ( ! sig64Z ) goto completeCancellation;
158             if ( sig64Z & UINT64_C( 0x8000000000000000 ) ) {
159                 signZ ^= 1;
160                 sig64Z = -sig64Z;
161             }
162         } else {
163             expZ = expProd;
164             sig64Z = sigProd - softfloat_shiftRightJam64( sig64C, expDiff );
165         }
166         shiftCount = softfloat_countLeadingZeros64( sig64Z ) - 1;
167         expZ -= shiftCount;
168         shiftCount -= 32;
169         if ( shiftCount < 0 ) {
170             sigZ = softfloat_shortShiftRightJam64( sig64Z, -shiftCount );
171         } else {
172             sigZ = (uint_fast32_t) sig64Z<<shiftCount;
173         }
174     }
175  roundPack:
176     return softfloat_roundPackToF32( signZ, expZ, sigZ );
177  propagateNaN_ABC:
178     uiZ = softfloat_propagateNaNF32UI( uiA, uiB );
179     goto propagateNaN_ZC;
180  infProdArg:
181     if ( magBits ) {
182         uiZ = packToF32UI( signProd, 0xFF, 0 );
183         if ( expC != 0xFF ) goto uiZ;
184         if ( sigC ) goto propagateNaN_ZC;
185         if ( signProd == signC ) goto uiZ;
186     }
187  invalid:
188     softfloat_raiseFlags( softfloat_flag_invalid );
189     uiZ = defaultNaNF32UI;
190  propagateNaN_ZC:
191     uiZ = softfloat_propagateNaNF32UI( uiZ, uiC );
192     goto uiZ;
193  zeroProd:
194     uiZ = uiC;
195     if ( ! (expC | sigC) && (signProd != signC) ) {
196  completeCancellation:
197         uiZ =
198             packToF32UI( softfloat_roundingMode == softfloat_round_min, 0, 0 );
199     }
200  uiZ:
201     uZ.ui = uiZ;
202     return uZ.f;
203 
204 }
205 
206