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, 2017 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 "softfloat.h"
42 
43 extFloat80_t
softfloat_roundPackToExtF80(bool sign,int_fast32_t exp,uint_fast64_t sig,uint_fast64_t sigExtra,uint_fast8_t roundingPrecision)44  softfloat_roundPackToExtF80(
45      bool sign,
46      int_fast32_t exp,
47      uint_fast64_t sig,
48      uint_fast64_t sigExtra,
49      uint_fast8_t roundingPrecision
50  )
51 {
52     uint_fast8_t roundingMode;
53     bool roundNearEven;
54     uint_fast64_t roundIncrement, roundMask, roundBits;
55     bool isTiny, doIncrement;
56     struct uint64_extra sig64Extra;
57     union { struct extFloat80M s; extFloat80_t f; } uZ;
58 
59     /*------------------------------------------------------------------------
60     *------------------------------------------------------------------------*/
61     roundingMode = softfloat_roundingMode;
62     roundNearEven = (roundingMode == softfloat_round_near_even);
63     if ( roundingPrecision == 80 ) goto precision80;
64     if ( roundingPrecision == 64 ) {
65         roundIncrement = UINT64_C( 0x0000000000000400 );
66         roundMask = UINT64_C( 0x00000000000007FF );
67     } else if ( roundingPrecision == 32 ) {
68         roundIncrement = UINT64_C( 0x0000008000000000 );
69         roundMask = UINT64_C( 0x000000FFFFFFFFFF );
70     } else {
71         goto precision80;
72     }
73     sig |= (sigExtra != 0);
74     if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
75         roundIncrement =
76             (roundingMode
77                  == (sign ? softfloat_round_min : softfloat_round_max))
78                 ? roundMask
79                 : 0;
80     }
81     roundBits = sig & roundMask;
82     /*------------------------------------------------------------------------
83     *------------------------------------------------------------------------*/
84     if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
85         if ( exp <= 0 ) {
86             /*----------------------------------------------------------------
87             *----------------------------------------------------------------*/
88             isTiny =
89                    (softfloat_detectTininess
90                         == softfloat_tininess_beforeRounding)
91                 || (exp < 0)
92                 || (sig <= (uint64_t) (sig + roundIncrement));
93             sig = softfloat_shiftRightJam64( sig, 1 - exp );
94             roundBits = sig & roundMask;
95             if ( roundBits ) {
96                 if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
97                 softfloat_exceptionFlags |= softfloat_flag_inexact;
98 #ifdef SOFTFLOAT_ROUND_ODD
99                 if ( roundingMode == softfloat_round_odd ) {
100                     sig |= roundMask + 1;
101                 }
102 #endif
103             }
104             sig += roundIncrement;
105             exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
106             roundIncrement = roundMask + 1;
107             if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
108                 roundMask |= roundIncrement;
109             }
110             sig &= ~roundMask;
111             goto packReturn;
112         }
113         if (
114                (0x7FFE < exp)
115             || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig))
116         ) {
117             goto overflow;
118         }
119     }
120     /*------------------------------------------------------------------------
121     *------------------------------------------------------------------------*/
122     if ( roundBits ) {
123         softfloat_exceptionFlags |= softfloat_flag_inexact;
124 #ifdef SOFTFLOAT_ROUND_ODD
125         if ( roundingMode == softfloat_round_odd ) {
126             sig = (sig & ~roundMask) | (roundMask + 1);
127             goto packReturn;
128         }
129 #endif
130     }
131     sig = (uint64_t) (sig + roundIncrement);
132     if ( sig < roundIncrement ) {
133         ++exp;
134         sig = UINT64_C( 0x8000000000000000 );
135     }
136     roundIncrement = roundMask + 1;
137     if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
138         roundMask |= roundIncrement;
139     }
140     sig &= ~roundMask;
141     goto packReturn;
142     /*------------------------------------------------------------------------
143     *------------------------------------------------------------------------*/
144  precision80:
145     doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra);
146     if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
147         doIncrement =
148             (roundingMode
149                  == (sign ? softfloat_round_min : softfloat_round_max))
150                 && sigExtra;
151     }
152     /*------------------------------------------------------------------------
153     *------------------------------------------------------------------------*/
154     if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
155         if ( exp <= 0 ) {
156             /*----------------------------------------------------------------
157             *----------------------------------------------------------------*/
158             isTiny =
159                    (softfloat_detectTininess
160                         == softfloat_tininess_beforeRounding)
161                 || (exp < 0)
162                 || ! doIncrement
163                 || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF ));
164             sig64Extra =
165                 softfloat_shiftRightJam64Extra( sig, sigExtra, 1 - exp );
166             exp = 0;
167             sig = sig64Extra.v;
168             sigExtra = sig64Extra.extra;
169             if ( sigExtra ) {
170                 if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
171                 softfloat_exceptionFlags |= softfloat_flag_inexact;
172 #ifdef SOFTFLOAT_ROUND_ODD
173                 if ( roundingMode == softfloat_round_odd ) {
174                     sig |= 1;
175                     goto packReturn;
176                 }
177 #endif
178             }
179             doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra);
180             if (
181                 ! roundNearEven
182                     && (roundingMode != softfloat_round_near_maxMag)
183             ) {
184                 doIncrement =
185                     (roundingMode
186                          == (sign ? softfloat_round_min : softfloat_round_max))
187                         && sigExtra;
188             }
189             if ( doIncrement ) {
190                 ++sig;
191                 sig &=
192                     ~(uint_fast64_t)
193                          (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF ))
194                               & roundNearEven);
195                 exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
196             }
197             goto packReturn;
198         }
199         if (
200                (0x7FFE < exp)
201             || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF ))
202                     && doIncrement)
203         ) {
204             /*----------------------------------------------------------------
205             *----------------------------------------------------------------*/
206             roundMask = 0;
207  overflow:
208             softfloat_raiseFlags(
209                 softfloat_flag_overflow | softfloat_flag_inexact );
210             if (
211                    roundNearEven
212                 || (roundingMode == softfloat_round_near_maxMag)
213                 || (roundingMode
214                         == (sign ? softfloat_round_min : softfloat_round_max))
215             ) {
216                 exp = 0x7FFF;
217                 sig = UINT64_C( 0x8000000000000000 );
218             } else {
219                 exp = 0x7FFE;
220                 sig = ~roundMask;
221             }
222             goto packReturn;
223         }
224     }
225     /*------------------------------------------------------------------------
226     *------------------------------------------------------------------------*/
227     if ( sigExtra ) {
228         softfloat_exceptionFlags |= softfloat_flag_inexact;
229 #ifdef SOFTFLOAT_ROUND_ODD
230         if ( roundingMode == softfloat_round_odd ) {
231             sig |= 1;
232             goto packReturn;
233         }
234 #endif
235     }
236     if ( doIncrement ) {
237         ++sig;
238         if ( ! sig ) {
239             ++exp;
240             sig = UINT64_C( 0x8000000000000000 );
241         } else {
242             sig &=
243                 ~(uint_fast64_t)
244                      (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF ))
245                           & roundNearEven);
246         }
247     }
248     /*------------------------------------------------------------------------
249     *------------------------------------------------------------------------*/
250  packReturn:
251     uZ.s.signExp = packToExtF80UI64( sign, exp );
252     uZ.s.signif = sig;
253     return uZ.f;
254 
255 }
256 
257