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