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 extFloat80_t 44 softfloat_roundPackToExtF80( 45 bool sign, 46 int_fast32_t exp, 47 uint_fast64_t sig, 48 uint_fast64_t sigExtra, 49 uint_fast8_t roundingPrecision 50 ) 51 { 52 uint_fast8_t roundingMode; 53 bool roundNearEven; 54 uint_fast64_t roundIncrement, roundMask, roundBits; 55 bool isTiny, doIncrement; 56 struct uint64_extra sig64Extra; 57 union { struct extFloat80M s; extFloat80_t f; } uZ; 58 59 roundingMode = softfloat_roundingMode; 60 roundNearEven = (roundingMode == softfloat_round_near_even); 61 if ( roundingPrecision == 80 ) goto precision80; 62 if ( roundingPrecision == 64 ) { 63 roundIncrement = UINT64_C( 0x0000000000000400 ); 64 roundMask = UINT64_C( 0x00000000000007FF ); 65 } else if ( roundingPrecision == 32 ) { 66 roundIncrement = UINT64_C( 0x0000008000000000 ); 67 roundMask = UINT64_C( 0x000000FFFFFFFFFF ); 68 } else { 69 goto precision80; 70 } 71 sig |= (sigExtra != 0); 72 if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { 73 roundIncrement = 74 (roundingMode 75 == (sign ? softfloat_round_min : softfloat_round_max)) 76 ? roundMask 77 : 0; 78 } 79 roundBits = sig & roundMask; 80 if ( 0x7FFD <= (uint32_t) (exp - 1) ) { 81 if ( exp <= 0 ) { 82 isTiny = 83 (softfloat_detectTininess 84 == softfloat_tininess_beforeRounding) 85 || (exp < 0) 86 || (sig <= (uint64_t) (sig + roundIncrement)); 87 sig = softfloat_shiftRightJam64( sig, 1 - exp ); 88 roundBits = sig & roundMask; 89 if ( isTiny && roundBits ) { 90 softfloat_raiseFlags( softfloat_flag_underflow ); 91 } 92 if ( roundBits ) { 93 softfloat_exceptionFlags |= softfloat_flag_inexact; 94 } 95 sig += roundIncrement; 96 exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); 97 roundIncrement = roundMask + 1; 98 if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { 99 roundMask |= roundIncrement; 100 } 101 sig &= ~roundMask; 102 goto packReturn; 103 } 104 if ( 105 (0x7FFE < exp) 106 || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) 107 ) { 108 goto overflow; 109 } 110 } 111 if ( roundBits ) softfloat_exceptionFlags |= softfloat_flag_inexact; 112 sig = (uint64_t) (sig + roundIncrement); 113 if ( sig < roundIncrement ) { 114 ++exp; 115 sig = UINT64_C( 0x8000000000000000 ); 116 } 117 roundIncrement = roundMask + 1; 118 if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { 119 roundMask |= roundIncrement; 120 } 121 sig &= ~roundMask; 122 if ( ! sig ) exp = 0; 123 goto packReturn; 124 precision80: 125 doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); 126 if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { 127 doIncrement = 128 (roundingMode 129 == (sign ? softfloat_round_min : softfloat_round_max)) 130 && sigExtra; 131 } 132 if ( 0x7FFD <= (uint32_t) (exp - 1) ) { 133 if ( exp <= 0 ) { 134 isTiny = 135 (softfloat_detectTininess 136 == softfloat_tininess_beforeRounding) 137 || (exp < 0) 138 || ! doIncrement 139 || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); 140 sig64Extra = 141 softfloat_shiftRightJam64Extra( sig, sigExtra, 1 - exp ); 142 sig = sig64Extra.v; 143 sigExtra = sig64Extra.extra; 144 if ( isTiny && sigExtra ) { 145 softfloat_raiseFlags( softfloat_flag_underflow ); 146 } 147 if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact; 148 doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); 149 if ( 150 ! roundNearEven 151 && (roundingMode != softfloat_round_near_maxMag) 152 ) { 153 doIncrement = 154 (roundingMode 155 == (sign ? softfloat_round_min : softfloat_round_max)) 156 && sigExtra; 157 } 158 exp = 0; 159 if ( doIncrement ) { 160 ++sig; 161 sig &= 162 ~(uint_fast64_t) 163 (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) 164 & roundNearEven); 165 exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); 166 } 167 goto packReturn; 168 } 169 if ( 170 (0x7FFE < exp) 171 || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) 172 && doIncrement) 173 ) { 174 roundMask = 0; 175 overflow: 176 softfloat_raiseFlags( 177 softfloat_flag_overflow | softfloat_flag_inexact ); 178 if ( 179 roundNearEven 180 || (roundingMode == softfloat_round_near_maxMag) 181 || (roundingMode 182 == (sign ? softfloat_round_min : softfloat_round_max)) 183 ) { 184 exp = 0x7FFF; 185 sig = UINT64_C( 0x8000000000000000 ); 186 } else { 187 exp = 0x7FFE; 188 sig = ~roundMask; 189 } 190 goto packReturn; 191 } 192 } 193 if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact; 194 if ( doIncrement ) { 195 ++sig; 196 if ( ! sig ) { 197 ++exp; 198 sig = UINT64_C( 0x8000000000000000 ); 199 } else { 200 sig &= 201 ~(uint_fast64_t) 202 (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) 203 & roundNearEven); 204 } 205 } else { 206 if ( ! sig ) exp = 0; 207 } 208 packReturn: 209 uZ.s.signExp = packToExtF80UI64( sign, exp ); 210 uZ.s.signif = sig; 211 return uZ.f; 212 213 } 214 215