1249259Sdim
2249259Sdim/*============================================================================
3249259Sdim
4249259SdimThis C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
5249259SdimPackage, Release 3e, by John R. Hauser.
6249259Sdim
7249259SdimCopyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of
8249259SdimCalifornia.  All rights reserved.
9249259Sdim
10249259SdimRedistribution and use in source and binary forms, with or without
11249259Sdimmodification, are permitted provided that the following conditions are met:
12249259Sdim
13249259Sdim 1. Redistributions of source code must retain the above copyright notice,
14249259Sdim    this list of conditions, and the following disclaimer.
15249259Sdim
16249259Sdim 2. Redistributions in binary form must reproduce the above copyright notice,
17249259Sdim    this list of conditions, and the following disclaimer in the documentation
18249259Sdim    and/or other materials provided with the distribution.
19249259Sdim
20249259Sdim 3. Neither the name of the University nor the names of its contributors may
21249259Sdim    be used to endorse or promote products derived from this software without
22249259Sdim    specific prior written permission.
23249259Sdim
24249259SdimTHIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
25249259SdimEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26249259SdimWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
27249259SdimDISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
28249259SdimDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29249259Sdim(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30249259SdimLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31249259SdimON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32249259Sdim(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33249259SdimSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34249259Sdim
35249259Sdim=============================================================================*/
36249259Sdim
37249259Sdim#include <stdbool.h>
38249259Sdim#include <stdint.h>
39249259Sdim#include "platform.h"
40249259Sdim#include "internals.h"
41249259Sdim#include "softfloat.h"
42249259Sdim
43249259Sdimvoid
44249259Sdim softfloat_roundPackMToExtF80M(
45249259Sdim     bool sign,
46249259Sdim     int32_t exp,
47249259Sdim     uint32_t *extSigPtr,
48249259Sdim     uint_fast8_t roundingPrecision,
49249259Sdim     struct extFloat80M *zSPtr
50249259Sdim )
51249259Sdim{
52249259Sdim    uint_fast8_t roundingMode;
53249259Sdim    bool roundNearEven;
54249259Sdim    uint64_t sig, roundIncrement, roundMask, roundBits;
55249259Sdim    bool isTiny;
56249259Sdim    uint32_t sigExtra;
57249259Sdim    bool doIncrement;
58249259Sdim
59249259Sdim    /*------------------------------------------------------------------------
60249259Sdim    *------------------------------------------------------------------------*/
61249259Sdim    roundingMode = softfloat_roundingMode;
62249259Sdim    roundNearEven = (roundingMode == softfloat_round_near_even);
63249259Sdim    sig =
64249259Sdim        (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32
65249259Sdim            | extSigPtr[indexWord( 3, 1 )];
66249259Sdim    if ( roundingPrecision == 80 ) goto precision80;
67249259Sdim    if ( roundingPrecision == 64 ) {
68249259Sdim        roundIncrement = UINT64_C( 0x0000000000000400 );
69249259Sdim        roundMask = UINT64_C( 0x00000000000007FF );
70249259Sdim    } else if ( roundingPrecision == 32 ) {
71249259Sdim        roundIncrement = UINT64_C( 0x0000008000000000 );
72249259Sdim        roundMask = UINT64_C( 0x000000FFFFFFFFFF );
73249259Sdim    } else {
74249259Sdim        goto precision80;
75249259Sdim    }
76249259Sdim    /*------------------------------------------------------------------------
77249259Sdim    *------------------------------------------------------------------------*/
78249259Sdim    if ( extSigPtr[indexWordLo( 3 )] ) sig |= 1;
79249259Sdim    if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
80249259Sdim        roundIncrement =
81249259Sdim            (roundingMode
82249259Sdim                 == (sign ? softfloat_round_min : softfloat_round_max))
83249259Sdim                ? roundMask
84249259Sdim                : 0;
85249259Sdim    }
86249259Sdim    roundBits = sig & roundMask;
87249259Sdim    /*------------------------------------------------------------------------
88249259Sdim    *------------------------------------------------------------------------*/
89249259Sdim    if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
90249259Sdim        if ( exp <= 0 ) {
91249259Sdim            /*----------------------------------------------------------------
92249259Sdim            *----------------------------------------------------------------*/
93249259Sdim            isTiny =
94249259Sdim                   (softfloat_detectTininess
95249259Sdim                        == softfloat_tininess_beforeRounding)
96249259Sdim                || (exp < 0)
97249259Sdim                || (sig <= (uint64_t) (sig + roundIncrement));
98249259Sdim            sig = softfloat_shiftRightJam64( sig, 1 - exp );
99249259Sdim            roundBits = sig & roundMask;
100249259Sdim            if ( roundBits ) {
101249259Sdim                if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
102249259Sdim                softfloat_raiseFlags( softfloat_flag_inexact );
103249259Sdim#ifdef SOFTFLOAT_ROUND_ODD
104249259Sdim                if ( roundingMode == softfloat_round_odd ) {
105249259Sdim                    sig |= roundMask + 1;
106249259Sdim                }
107249259Sdim#endif
108249259Sdim            }
109249259Sdim            sig += roundIncrement;
110249259Sdim            exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
111249259Sdim            roundIncrement = roundMask + 1;
112249259Sdim            if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
113249259Sdim                roundMask |= roundIncrement;
114249259Sdim            }
115249259Sdim            sig &= ~roundMask;
116249259Sdim            goto packReturn;
117249259Sdim        }
118249259Sdim        if (
119249259Sdim               (0x7FFE < exp)
120249259Sdim            || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig))
121249259Sdim        ) {
122249259Sdim            goto overflow;
123249259Sdim        }
124249259Sdim    }
125249259Sdim    /*------------------------------------------------------------------------
126249259Sdim    *------------------------------------------------------------------------*/
127249259Sdim    if ( roundBits ) {
128249259Sdim        softfloat_raiseFlags( softfloat_flag_inexact );
129249259Sdim#ifdef SOFTFLOAT_ROUND_ODD
130249259Sdim        if ( roundingMode == softfloat_round_odd ) {
131249259Sdim            sig = (sig & ~roundMask) | (roundMask + 1);
132249259Sdim            goto packReturn;
133249259Sdim        }
134249259Sdim#endif
135249259Sdim    }
136249259Sdim    sig += roundIncrement;
137249259Sdim    if ( sig < roundIncrement ) {
138249259Sdim        ++exp;
139249259Sdim        sig = UINT64_C( 0x8000000000000000 );
140249259Sdim    }
141249259Sdim    roundIncrement = roundMask + 1;
142249259Sdim    if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
143249259Sdim        roundMask |= roundIncrement;
144249259Sdim    }
145249259Sdim    sig &= ~roundMask;
146249259Sdim    goto packReturn;
147249259Sdim    /*------------------------------------------------------------------------
148249259Sdim    *------------------------------------------------------------------------*/
149249259Sdim precision80:
150249259Sdim    sigExtra = extSigPtr[indexWordLo( 3 )];
151249259Sdim    doIncrement = (0x80000000 <= sigExtra);
152249259Sdim    if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
153249259Sdim        doIncrement =
154249259Sdim            (roundingMode
155249259Sdim                 == (sign ? softfloat_round_min : softfloat_round_max))
156249259Sdim                && sigExtra;
157249259Sdim    }
158249259Sdim    /*------------------------------------------------------------------------
159249259Sdim    *------------------------------------------------------------------------*/
160249259Sdim    if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
161249259Sdim        if ( exp <= 0 ) {
162249259Sdim            /*----------------------------------------------------------------
163249259Sdim            *----------------------------------------------------------------*/
164249259Sdim            isTiny =
165249259Sdim                   (softfloat_detectTininess
166249259Sdim                        == softfloat_tininess_beforeRounding)
167249259Sdim                || (exp < 0)
168249259Sdim                || ! doIncrement
169249259Sdim                || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF ));
170249259Sdim            softfloat_shiftRightJam96M( extSigPtr, 1 - exp, extSigPtr );
171249259Sdim            exp = 0;
172249259Sdim            sig =
173249259Sdim                (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32
174249259Sdim                    | extSigPtr[indexWord( 3, 1 )];
175249259Sdim            sigExtra = extSigPtr[indexWordLo( 3 )];
176249259Sdim            if ( sigExtra ) {
177249259Sdim                if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
178249259Sdim                softfloat_raiseFlags( softfloat_flag_inexact );
179249259Sdim#ifdef SOFTFLOAT_ROUND_ODD
180249259Sdim                if ( roundingMode == softfloat_round_odd ) {
181249259Sdim                    sig |= 1;
182249259Sdim                    goto packReturn;
183249259Sdim                }
184249259Sdim#endif
185249259Sdim            }
186249259Sdim            doIncrement = (0x80000000 <= sigExtra);
187249259Sdim            if (
188249259Sdim                ! roundNearEven
189249259Sdim                    && (roundingMode != softfloat_round_near_maxMag)
190249259Sdim            ) {
191249259Sdim                doIncrement =
192249259Sdim                    (roundingMode
193249259Sdim                         == (sign ? softfloat_round_min : softfloat_round_max))
194249259Sdim                        && sigExtra;
195249259Sdim            }
196249259Sdim            if ( doIncrement ) {
197249259Sdim                ++sig;
198249259Sdim                sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven);
199249259Sdim                exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
200249259Sdim            }
201249259Sdim            goto packReturn;
202249259Sdim        }
203249259Sdim        if (
204249259Sdim               (0x7FFE < exp)
205249259Sdim            || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF ))
206249259Sdim                    && doIncrement)
207249259Sdim        ) {
208249259Sdim            /*----------------------------------------------------------------
209249259Sdim            *----------------------------------------------------------------*/
210249259Sdim            roundMask = 0;
211249259Sdim overflow:
212249259Sdim            softfloat_raiseFlags(
213249259Sdim                softfloat_flag_overflow | softfloat_flag_inexact );
214249259Sdim            if (
215249259Sdim                   roundNearEven
216249259Sdim                || (roundingMode == softfloat_round_near_maxMag)
217249259Sdim                || (roundingMode
218249259Sdim                        == (sign ? softfloat_round_min : softfloat_round_max))
219249259Sdim            ) {
220249259Sdim                exp = 0x7FFF;
221249259Sdim                sig = UINT64_C( 0x8000000000000000 );
222249259Sdim            } else {
223249259Sdim                exp = 0x7FFE;
224249259Sdim                sig = ~roundMask;
225249259Sdim            }
226249259Sdim            goto packReturn;
227249259Sdim        }
228249259Sdim    }
229249259Sdim    /*------------------------------------------------------------------------
230249259Sdim    *------------------------------------------------------------------------*/
231249259Sdim    if ( sigExtra ) {
232249259Sdim        softfloat_raiseFlags( softfloat_flag_inexact );
233249259Sdim#ifdef SOFTFLOAT_ROUND_ODD
234249259Sdim        if ( roundingMode == softfloat_round_odd ) {
235249259Sdim            sig |= 1;
236249259Sdim            goto packReturn;
237249259Sdim        }
238249259Sdim#endif
239249259Sdim    }
240249259Sdim    if ( doIncrement ) {
241249259Sdim        ++sig;
242249259Sdim        if ( ! sig ) {
243249259Sdim            ++exp;
244249259Sdim            sig = UINT64_C( 0x8000000000000000 );
245249259Sdim        } else {
246249259Sdim            sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven);
247249259Sdim        }
248249259Sdim    }
249249259Sdim    /*------------------------------------------------------------------------
250249259Sdim    *------------------------------------------------------------------------*/
251249259Sdim packReturn:
252249259Sdim    zSPtr->signExp = packToExtF80UI64( sign, exp );
253249259Sdim    zSPtr->signif = sig;
254249259Sdim
255249259Sdim}
256249259Sdim
257249259Sdim