1
2/*============================================================================
3
4This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
5Package, Release 3e, by John R. Hauser.
6
7Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of
8California.  All rights reserved.
9
10Redistribution and use in source and binary forms, with or without
11modification, 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
24THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
25EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
27DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
28DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31ON 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
33SOFTWARE, 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
43void
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            /*----------------------------------------------------------------
92            *----------------------------------------------------------------*/
93            isTiny =
94                   (softfloat_detectTininess
95                        == softfloat_tininess_beforeRounding)
96                || (exp < 0)
97                || (sig <= (uint64_t) (sig + roundIncrement));
98            sig = softfloat_shiftRightJam64( sig, 1 - exp );
99            roundBits = sig & roundMask;
100            if ( roundBits ) {
101                if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
102                softfloat_raiseFlags( softfloat_flag_inexact );
103#ifdef SOFTFLOAT_ROUND_ODD
104                if ( roundingMode == softfloat_round_odd ) {
105                    sig |= roundMask + 1;
106                }
107#endif
108            }
109            sig += roundIncrement;
110            exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
111            roundIncrement = roundMask + 1;
112            if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
113                roundMask |= roundIncrement;
114            }
115            sig &= ~roundMask;
116            goto packReturn;
117        }
118        if (
119               (0x7FFE < exp)
120            || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig))
121        ) {
122            goto overflow;
123        }
124    }
125    /*------------------------------------------------------------------------
126    *------------------------------------------------------------------------*/
127    if ( roundBits ) {
128        softfloat_raiseFlags( softfloat_flag_inexact );
129#ifdef SOFTFLOAT_ROUND_ODD
130        if ( roundingMode == softfloat_round_odd ) {
131            sig = (sig & ~roundMask) | (roundMask + 1);
132            goto packReturn;
133        }
134#endif
135    }
136    sig += roundIncrement;
137    if ( sig < roundIncrement ) {
138        ++exp;
139        sig = UINT64_C( 0x8000000000000000 );
140    }
141    roundIncrement = roundMask + 1;
142    if ( roundNearEven && (roundBits<<1 == roundIncrement) ) {
143        roundMask |= roundIncrement;
144    }
145    sig &= ~roundMask;
146    goto packReturn;
147    /*------------------------------------------------------------------------
148    *------------------------------------------------------------------------*/
149 precision80:
150    sigExtra = extSigPtr[indexWordLo( 3 )];
151    doIncrement = (0x80000000 <= sigExtra);
152    if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
153        doIncrement =
154            (roundingMode
155                 == (sign ? softfloat_round_min : softfloat_round_max))
156                && sigExtra;
157    }
158    /*------------------------------------------------------------------------
159    *------------------------------------------------------------------------*/
160    if ( 0x7FFD <= (uint32_t) (exp - 1) ) {
161        if ( exp <= 0 ) {
162            /*----------------------------------------------------------------
163            *----------------------------------------------------------------*/
164            isTiny =
165                   (softfloat_detectTininess
166                        == softfloat_tininess_beforeRounding)
167                || (exp < 0)
168                || ! doIncrement
169                || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF ));
170            softfloat_shiftRightJam96M( extSigPtr, 1 - exp, extSigPtr );
171            exp = 0;
172            sig =
173                (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32
174                    | extSigPtr[indexWord( 3, 1 )];
175            sigExtra = extSigPtr[indexWordLo( 3 )];
176            if ( sigExtra ) {
177                if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow );
178                softfloat_raiseFlags( softfloat_flag_inexact );
179#ifdef SOFTFLOAT_ROUND_ODD
180                if ( roundingMode == softfloat_round_odd ) {
181                    sig |= 1;
182                    goto packReturn;
183                }
184#endif
185            }
186            doIncrement = (0x80000000 <= sigExtra);
187            if (
188                ! roundNearEven
189                    && (roundingMode != softfloat_round_near_maxMag)
190            ) {
191                doIncrement =
192                    (roundingMode
193                         == (sign ? softfloat_round_min : softfloat_round_max))
194                        && sigExtra;
195            }
196            if ( doIncrement ) {
197                ++sig;
198                sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven);
199                exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0);
200            }
201            goto packReturn;
202        }
203        if (
204               (0x7FFE < exp)
205            || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF ))
206                    && doIncrement)
207        ) {
208            /*----------------------------------------------------------------
209            *----------------------------------------------------------------*/
210            roundMask = 0;
211 overflow:
212            softfloat_raiseFlags(
213                softfloat_flag_overflow | softfloat_flag_inexact );
214            if (
215                   roundNearEven
216                || (roundingMode == softfloat_round_near_maxMag)
217                || (roundingMode
218                        == (sign ? softfloat_round_min : softfloat_round_max))
219            ) {
220                exp = 0x7FFF;
221                sig = UINT64_C( 0x8000000000000000 );
222            } else {
223                exp = 0x7FFE;
224                sig = ~roundMask;
225            }
226            goto packReturn;
227        }
228    }
229    /*------------------------------------------------------------------------
230    *------------------------------------------------------------------------*/
231    if ( sigExtra ) {
232        softfloat_raiseFlags( softfloat_flag_inexact );
233#ifdef SOFTFLOAT_ROUND_ODD
234        if ( roundingMode == softfloat_round_odd ) {
235            sig |= 1;
236            goto packReturn;
237        }
238#endif
239    }
240    if ( doIncrement ) {
241        ++sig;
242        if ( ! sig ) {
243            ++exp;
244            sig = UINT64_C( 0x8000000000000000 );
245        } else {
246            sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven);
247        }
248    }
249    /*------------------------------------------------------------------------
250    *------------------------------------------------------------------------*/
251 packReturn:
252    zSPtr->signExp = packToExtF80UI64( sign, exp );
253    zSPtr->signif = sig;
254
255}
256
257