xref: /optee_os/lib/libutils/isoc/arch/arm/softfloat/source/s_roundPackMToExtF80M.c (revision 9403c583381528e7fb391e3769644cc9653cfbb6)
1 
2 /*============================================================================
3 
4 This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
5 Package, Release 3a, by John R. Hauser.
6 
7 Copyright 2011, 2012, 2013, 2014, 2015 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 void
44  softfloat_roundPackMToExtF80M(
45      bool sign,
46      int32_t exp,
47      uint32_t *extSigPtr,
48      uint_fast8_t roundingPrecision,
49      struct extFloat80M *zSPtr
50  )
51 {
52     uint_fast8_t roundingMode;
53     bool roundNearEven;
54     uint64_t sig, roundIncrement, roundMask, roundBits;
55     bool isTiny;
56     uint32_t sigExtra;
57     bool doIncrement;
58 
59     /*------------------------------------------------------------------------
60     *------------------------------------------------------------------------*/
61     roundingMode = softfloat_roundingMode;
62     roundNearEven = (roundingMode == softfloat_round_near_even);
63     sig =
64         (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32
65             | extSigPtr[indexWord( 3, 1 )];
66     if ( roundingPrecision == 80 ) goto precision80;
67     if ( roundingPrecision == 64 ) {
68         roundIncrement = UINT64_C( 0x0000000000000400 );
69         roundMask = UINT64_C( 0x00000000000007FF );
70     } else if ( roundingPrecision == 32 ) {
71         roundIncrement = UINT64_C( 0x0000008000000000 );
72         roundMask = UINT64_C( 0x000000FFFFFFFFFF );
73     } else {
74         goto precision80;
75     }
76     /*------------------------------------------------------------------------
77     *------------------------------------------------------------------------*/
78     if ( extSigPtr[indexWordLo( 3 )] ) sig |= 1;
79     if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
80         roundIncrement =
81             (roundingMode
82                  == (sign ? softfloat_round_min : softfloat_round_max))
83                 ? roundMask
84                 : 0;
85     }
86     roundBits = sig & roundMask;
87     /*------------------------------------------------------------------------
88     *------------------------------------------------------------------------*/
89     if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
90         if ( exp <= 0 ) {
91             isTiny =
92                    (softfloat_detectTininess
93                         == softfloat_tininess_beforeRounding)
94                 || (exp < 0)
95                 || (sig <= (uint64_t) (sig + roundIncrement));
96             sig = softfloat_shiftRightJam64( sig, 1 - exp );
97             roundBits = sig & roundMask;
98             if ( roundBits ) {
99                 if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
100                 softfloat_exceptionFlags |= softfloat_flag_inexact;
101             }
102             sig += roundIncrement;
103             exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
104             roundIncrement = roundMask + 1;
105             if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
106                 roundMask |= roundIncrement;
107             }
108             sig &= ~roundMask;
109             goto packReturn;
110         }
111         if (
112                (0x7FFE < exp)
113             || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig))
114         ) {
115             goto overflow;
116         }
117     }
118     /*------------------------------------------------------------------------
119     *------------------------------------------------------------------------*/
120     if ( roundBits ) softfloat_exceptionFlags |= softfloat_flag_inexact;
121     sig += roundIncrement;
122     if ( sig < roundIncrement ) {
123         ++exp;
124         sig = UINT64_C( 0x8000000000000000 );
125     }
126     roundIncrement = roundMask + 1;
127     if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
128         roundMask |= roundIncrement;
129     }
130     sig &= ~roundMask;
131     goto packReturn;
132     /*------------------------------------------------------------------------
133     *------------------------------------------------------------------------*/
134  precision80:
135     sigExtra = extSigPtr[indexWordLo( 3 )];
136     doIncrement = (0x80000000 <= sigExtra);
137     if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
138         doIncrement =
139             (roundingMode
140                  == (sign ? softfloat_round_min : softfloat_round_max))
141                 && sigExtra;
142     }
143     /*------------------------------------------------------------------------
144     *------------------------------------------------------------------------*/
145     if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
146         /*--------------------------------------------------------------------
147         *--------------------------------------------------------------------*/
148         if ( exp <= 0 ) {
149             isTiny =
150                    (softfloat_detectTininess
151                         == softfloat_tininess_beforeRounding)
152                 || (exp < 0)
153                 || ! doIncrement
154                 || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF ));
155             softfloat_shiftRightJam96M( extSigPtr, 1 - exp, extSigPtr );
156             sigExtra = extSigPtr[indexWordLo( 3 )];
157             if ( sigExtra ) {
158                 if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
159                 softfloat_exceptionFlags |= softfloat_flag_inexact;
160             }
161             doIncrement = (0x80000000 <= sigExtra);
162             if (
163                    ! roundNearEven
164                 && (roundingMode != softfloat_round_near_maxMag)
165             ) {
166                 doIncrement =
167                     (roundingMode
168                          == (sign ? softfloat_round_min : softfloat_round_max))
169                         && sigExtra;
170             }
171             exp = 0;
172             sig =
173                 (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32
174                     | extSigPtr[indexWord( 3, 1 )];
175             if ( doIncrement ) {
176                 ++sig;
177                 sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven);
178                 exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
179             }
180             goto packReturn;
181         }
182         /*--------------------------------------------------------------------
183         *--------------------------------------------------------------------*/
184         if (
185                (0x7FFE < exp)
186             || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF ))
187                     && doIncrement)
188         ) {
189             roundMask = 0;
190  overflow:
191             softfloat_raiseFlags(
192                 softfloat_flag_overflow | softfloat_flag_inexact );
193             if (
194                    roundNearEven
195                 || (roundingMode == softfloat_round_near_maxMag)
196                 || (roundingMode
197                         == (sign ? softfloat_round_min : softfloat_round_max))
198             ) {
199                 exp = 0x7FFF;
200                 sig = UINT64_C( 0x8000000000000000 );
201             } else {
202                 exp = 0x7FFE;
203                 sig = ~roundMask;
204             }
205             goto packReturn;
206         }
207     }
208     /*------------------------------------------------------------------------
209     *------------------------------------------------------------------------*/
210     if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact;
211     if ( doIncrement ) {
212         ++sig;
213         if ( ! sig ) {
214             ++exp;
215             sig = UINT64_C( 0x8000000000000000 );
216         } else {
217             sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven);
218         }
219     }
220     /*------------------------------------------------------------------------
221     *------------------------------------------------------------------------*/
222  packReturn:
223     zSPtr->signExp = packToExtF80UI64( sign, exp );
224     zSPtr->signif = sig;
225 
226 }
227 
228