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 float16_t
softfloat_mulAddF16(uint_fast16_t uiA,uint_fast16_t uiB,uint_fast16_t uiC,uint_fast8_t op)45  softfloat_mulAddF16(
46      uint_fast16_t uiA, uint_fast16_t uiB, uint_fast16_t uiC, uint_fast8_t op )
47 {
48     bool signA;
49     int_fast8_t expA;
50     uint_fast16_t sigA;
51     bool signB;
52     int_fast8_t expB;
53     uint_fast16_t sigB;
54     bool signC;
55     int_fast8_t expC;
56     uint_fast16_t sigC;
57     bool signProd;
58     uint_fast16_t magBits, uiZ;
59     struct exp8_sig16 normExpSig;
60     int_fast8_t expProd;
61     uint_fast32_t sigProd;
62     bool signZ;
63     int_fast8_t expZ;
64     uint_fast16_t sigZ;
65     int_fast8_t expDiff;
66     uint_fast32_t sig32Z, sig32C;
67     int_fast8_t shiftDist;
68     union ui16_f16 uZ;
69 
70     /*------------------------------------------------------------------------
71     *------------------------------------------------------------------------*/
72     signA = signF16UI( uiA );
73     expA  = expF16UI( uiA );
74     sigA  = fracF16UI( uiA );
75     signB = signF16UI( uiB );
76     expB  = expF16UI( uiB );
77     sigB  = fracF16UI( uiB );
78     signC = signF16UI( uiC ) ^ (op == softfloat_mulAdd_subC);
79     expC  = expF16UI( uiC );
80     sigC  = fracF16UI( uiC );
81     signProd = signA ^ signB ^ (op == softfloat_mulAdd_subProd);
82     /*------------------------------------------------------------------------
83     *------------------------------------------------------------------------*/
84     if ( expA == 0x1F ) {
85         if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN_ABC;
86         magBits = expB | sigB;
87         goto infProdArg;
88     }
89     if ( expB == 0x1F ) {
90         if ( sigB ) goto propagateNaN_ABC;
91         magBits = expA | sigA;
92         goto infProdArg;
93     }
94     if ( expC == 0x1F ) {
95         if ( sigC ) {
96             uiZ = 0;
97             goto propagateNaN_ZC;
98         }
99         uiZ = uiC;
100         goto uiZ;
101     }
102     /*------------------------------------------------------------------------
103     *------------------------------------------------------------------------*/
104     if ( ! expA ) {
105         if ( ! sigA ) goto zeroProd;
106         normExpSig = softfloat_normSubnormalF16Sig( sigA );
107         expA = normExpSig.exp;
108         sigA = normExpSig.sig;
109     }
110     if ( ! expB ) {
111         if ( ! sigB ) goto zeroProd;
112         normExpSig = softfloat_normSubnormalF16Sig( sigB );
113         expB = normExpSig.exp;
114         sigB = normExpSig.sig;
115     }
116     /*------------------------------------------------------------------------
117     *------------------------------------------------------------------------*/
118     expProd = expA + expB - 0xE;
119     sigA = (sigA | 0x0400)<<4;
120     sigB = (sigB | 0x0400)<<4;
121     sigProd = (uint_fast32_t) sigA * sigB;
122     if ( sigProd < 0x20000000 ) {
123         --expProd;
124         sigProd <<= 1;
125     }
126     signZ = signProd;
127     if ( ! expC ) {
128         if ( ! sigC ) {
129             expZ = expProd - 1;
130             sigZ = sigProd>>15 | ((sigProd & 0x7FFF) != 0);
131             goto roundPack;
132         }
133         normExpSig = softfloat_normSubnormalF16Sig( sigC );
134         expC = normExpSig.exp;
135         sigC = normExpSig.sig;
136     }
137     sigC = (sigC | 0x0400)<<3;
138     /*------------------------------------------------------------------------
139     *------------------------------------------------------------------------*/
140     expDiff = expProd - expC;
141     if ( signProd == signC ) {
142         /*--------------------------------------------------------------------
143         *--------------------------------------------------------------------*/
144         if ( expDiff <= 0 ) {
145             expZ = expC;
146             sigZ = sigC + softfloat_shiftRightJam32( sigProd, 16 - expDiff );
147         } else {
148             expZ = expProd;
149             sig32Z =
150                 sigProd
151                     + softfloat_shiftRightJam32(
152                           (uint_fast32_t) sigC<<16, expDiff );
153             sigZ = sig32Z>>16 | ((sig32Z & 0xFFFF) != 0 );
154         }
155         if ( sigZ < 0x4000 ) {
156             --expZ;
157             sigZ <<= 1;
158         }
159     } else {
160         /*--------------------------------------------------------------------
161         *--------------------------------------------------------------------*/
162         sig32C = (uint_fast32_t) sigC<<16;
163         if ( expDiff < 0 ) {
164             signZ = signC;
165             expZ = expC;
166             sig32Z = sig32C - softfloat_shiftRightJam32( sigProd, -expDiff );
167         } else if ( ! expDiff ) {
168             expZ = expProd;
169             sig32Z = sigProd - sig32C;
170             if ( ! sig32Z ) goto completeCancellation;
171             if ( sig32Z & 0x80000000 ) {
172                 signZ = ! signZ;
173                 sig32Z = -sig32Z;
174             }
175         } else {
176             expZ = expProd;
177             sig32Z = sigProd - softfloat_shiftRightJam32( sig32C, expDiff );
178         }
179         shiftDist = softfloat_countLeadingZeros32( sig32Z ) - 1;
180         expZ -= shiftDist;
181         shiftDist -= 16;
182         if ( shiftDist < 0 ) {
183             sigZ =
184                 sig32Z>>(-shiftDist)
185                     | ((uint32_t) (sig32Z<<(shiftDist & 31)) != 0);
186         } else {
187             sigZ = (uint_fast16_t) sig32Z<<shiftDist;
188         }
189     }
190  roundPack:
191     return softfloat_roundPackToF16( signZ, expZ, sigZ );
192     /*------------------------------------------------------------------------
193     *------------------------------------------------------------------------*/
194  propagateNaN_ABC:
195     uiZ = softfloat_propagateNaNF16UI( uiA, uiB );
196     goto propagateNaN_ZC;
197     /*------------------------------------------------------------------------
198     *------------------------------------------------------------------------*/
199  infProdArg:
200     if ( magBits ) {
201         uiZ = packToF16UI( signProd, 0x1F, 0 );
202         if ( expC != 0x1F ) goto uiZ;
203         if ( sigC ) goto propagateNaN_ZC;
204         if ( signProd == signC ) goto uiZ;
205     }
206     softfloat_raiseFlags( softfloat_flag_invalid );
207     uiZ = defaultNaNF16UI;
208  propagateNaN_ZC:
209     uiZ = softfloat_propagateNaNF16UI( uiZ, uiC );
210     goto uiZ;
211     /*------------------------------------------------------------------------
212     *------------------------------------------------------------------------*/
213  zeroProd:
214     uiZ = uiC;
215     if ( ! (expC | sigC) && (signProd != signC) ) {
216  completeCancellation:
217         uiZ =
218             packToF16UI(
219                 (softfloat_roundingMode == softfloat_round_min), 0, 0 );
220     }
221  uiZ:
222     uZ.ui = uiZ;
223     return uZ.f;
224 
225 }
226 
227