01ba3b4c97c80b54928fce389e319387f87ae9cc
[riscv-isa-sim.git] / softfloat / s_mulAddF64.c
1
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include "platform.h"
5 #include "primitives.h"
6 #include "internals.h"
7 #include "specialize.h"
8 #include "softfloat.h"
9
10 float64_t
11 softfloat_mulAddF64(
12 int op, uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC )
13 {
14 bool signA;
15 int_fast16_t expA;
16 uint_fast64_t sigA;
17 bool signB;
18 int_fast16_t expB;
19 uint_fast64_t sigB;
20 bool signC;
21 int_fast16_t expC;
22 uint_fast64_t sigC;
23 bool signProd;
24 uint_fast64_t magBits, uiZ;
25 struct exp16_sig64 normExpSig;
26 int_fast16_t expProd;
27 struct uint128 sigProd;
28 bool signZ;
29 int_fast16_t expZ;
30 uint_fast64_t sigZ;
31 int_fast16_t expDiff;
32 struct uint128 sigC128, sigZ128;
33 int shiftCount;
34 union ui64_f64 uZ;
35
36 signA = signF64UI( uiA );
37 expA = expF64UI( uiA );
38 sigA = fracF64UI( uiA );
39 signB = signF64UI( uiB );
40 expB = expF64UI( uiB );
41 sigB = fracF64UI( uiB );
42 signC = signF64UI( uiC ) ^ ( op == softfloat_mulAdd_subC );
43 expC = expF64UI( uiC );
44 sigC = fracF64UI( uiC );
45 signProd = signA ^ signB ^ ( op == softfloat_mulAdd_subProd );
46 if ( expA == 0x7FF ) {
47 if ( sigA || ( ( expB == 0x7FF ) && sigB ) ) goto propagateNaN_ABC;
48 magBits = expB | sigB;
49 goto infProdArg;
50 }
51 if ( expB == 0x7FF ) {
52 if ( sigB ) goto propagateNaN_ABC;
53 magBits = expA | sigA;
54 goto infProdArg;
55 }
56 if ( expC == 0x7FF ) {
57 if ( sigC ) {
58 uiZ = 0;
59 goto propagateNaN_ZC;
60 }
61 uiZ = uiC;
62 goto uiZ;
63 }
64 if ( ! expA ) {
65 if ( ! sigA ) goto zeroProd;
66 normExpSig = softfloat_normSubnormalF64Sig( sigA );
67 expA = normExpSig.exp;
68 sigA = normExpSig.sig;
69 }
70 if ( ! expB ) {
71 if ( ! sigB ) goto zeroProd;
72 normExpSig = softfloat_normSubnormalF64Sig( sigB );
73 expB = normExpSig.exp;
74 sigB = normExpSig.sig;
75 }
76 expProd = expA + expB - 0x3FE;
77 sigA = ( sigA | UINT64_C( 0x0010000000000000 ) )<<10;
78 sigB = ( sigB | UINT64_C( 0x0010000000000000 ) )<<10;
79 sigProd = softfloat_mul64To128( sigA, sigB );
80 if ( sigProd.v64 < UINT64_C( 0x2000000000000000 ) ) {
81 --expProd;
82 sigProd = softfloat_shortShift128Left( sigProd.v64, sigProd.v0, 1 );
83 }
84 signZ = signProd;
85 if ( ! expC ) {
86 if ( ! sigC ) {
87 expZ = expProd - 1;
88 sigZ = sigProd.v64<<1 | ( sigProd.v0 != 0 );
89 goto roundPack;
90 }
91 normExpSig = softfloat_normSubnormalF64Sig( sigC );
92 expC = normExpSig.exp;
93 sigC = normExpSig.sig;
94 }
95 sigC = ( sigC | UINT64_C( 0x0010000000000000 ) )<<9;
96 expDiff = expProd - expC;
97 if ( signProd == signC ) {
98 if ( expDiff <= 0 ) {
99 expZ = expC;
100 if ( expDiff ) {
101 sigProd.v64 =
102 softfloat_shift64RightJam( sigProd.v64, - expDiff );
103 }
104 sigZ = ( sigC + sigProd.v64 ) | ( sigProd.v0 != 0 );
105 } else {
106 expZ = expProd;
107 sigC128 = softfloat_shift128RightJam( sigC, 0, expDiff );
108 sigZ128 =
109 softfloat_add128(
110 sigProd.v64, sigProd.v0, sigC128.v64, sigC128.v0 );
111 sigZ = sigZ128.v64 | ( sigZ128.v0 != 0 );
112 }
113 if ( sigZ < UINT64_C( 0x4000000000000000 ) ) {
114 --expZ;
115 sigZ <<= 1;
116 }
117 } else {
118 /*** OPTIMIZE BETTER? ***/
119 if ( expDiff < 0 ) {
120 signZ = signC;
121 expZ = expC;
122 sigProd =
123 softfloat_shift128RightJam(
124 sigProd.v64, sigProd.v0, - expDiff );
125 sigZ128 = softfloat_sub128( sigC, 0, sigProd.v64, sigProd.v0 );
126 } else if ( ! expDiff ) {
127 expZ = expProd;
128 sigZ128 = softfloat_sub128( sigProd.v64, sigProd.v0, sigC, 0 );
129 if ( ! ( sigZ128.v64 | sigZ128.v0 ) ) goto completeCancellation;
130 if ( sigZ128.v64 & UINT64_C( 0x8000000000000000 ) ) {
131 signZ ^= 1;
132 sigZ128 = softfloat_sub128( 0, 0, sigZ128.v64, sigZ128.v0 );
133 }
134 } else {
135 expZ = expProd;
136 sigC128 = softfloat_shift128RightJam( sigC, 0, expDiff );
137 sigZ128 =
138 softfloat_sub128(
139 sigProd.v64, sigProd.v0, sigC128.v64, sigC128.v0 );
140 }
141 if ( ! sigZ128.v64 ) {
142 expZ -= 64;
143 sigZ128.v64 = sigZ128.v0;
144 sigZ128.v0 = 0;
145 }
146 shiftCount = softfloat_countLeadingZeros64( sigZ128.v64 ) - 1;
147 expZ -= shiftCount;
148 if ( shiftCount < 0 ) {
149 sigZ = softfloat_shortShift64RightJam( sigZ128.v64, - shiftCount );
150 } else {
151 sigZ128 =
152 softfloat_shortShift128Left(
153 sigZ128.v64, sigZ128.v0, shiftCount );
154 sigZ = sigZ128.v64;
155 }
156 sigZ |= ( sigZ128.v0 != 0 );
157 }
158 roundPack:
159 return softfloat_roundPackToF64( signZ, expZ, sigZ );
160 propagateNaN_ABC:
161 uiZ = softfloat_propagateNaNF64UI( uiA, uiB );
162 goto propagateNaN_ZC;
163 infProdArg:
164 if ( magBits ) {
165 uiZ = packToF64UI( signProd, 0x7FF, 0 );
166 if ( expC != 0x7FF ) goto uiZ;
167 if ( sigC ) goto propagateNaN_ZC;
168 if ( signProd == signC ) goto uiZ;
169 }
170 invalid:
171 softfloat_raiseFlags( softfloat_flag_invalid );
172 uiZ = defaultNaNF64UI;
173 propagateNaN_ZC:
174 uiZ = softfloat_propagateNaNF64UI( uiZ, uiC );
175 goto uiZ;
176 zeroProd:
177 uiZ = uiC;
178 if ( ! ( expC | sigC ) && ( signProd != signC ) ) {
179 completeCancellation:
180 uiZ =
181 packToF64UI( softfloat_roundingMode == softfloat_round_min, 0, 0 );
182 }
183 uiZ:
184 uZ.ui = uiZ;
185 return uZ.f;
186
187 }
188