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