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