1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Linux/PA-RISC Project (http://www.parisc-linux.org/) 4 * 5 * Floating-point emulation code 6 * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> 7 */ 8 /* 9 * BEGIN_DESC 10 * 11 * File: 12 * @(#) pa/spmath/sfdiv.c $Revision: 1.1 $ 13 * 14 * Purpose: 15 * Single Precision Floating-point Divide 16 * 17 * External Interfaces: 18 * sgl_fdiv(srcptr1,srcptr2,dstptr,status) 19 * 20 * Internal Interfaces: 21 * 22 * Theory: 23 * <<please update with a overview of the operation of this file>> 24 * 25 * END_DESC 26 */ 27 28 29 #include "float.h" 30 #include "sgl_float.h" 31 32 /* 33 * Single Precision Floating-point Divide 34 */ 35 36 int 37 sgl_fdiv (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2, 38 sgl_floating_point * dstptr, unsigned int *status) 39 { 40 register unsigned int opnd1, opnd2, opnd3, result; 41 register int dest_exponent, count; 42 register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE; 43 boolean is_tiny; 44 45 opnd1 = *srcptr1; 46 opnd2 = *srcptr2; 47 /* 48 * set sign bit of result 49 */ 50 if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result); 51 else Sgl_setzero(result); 52 /* 53 * check first operand for NaN's or infinity 54 */ 55 if (Sgl_isinfinity_exponent(opnd1)) { 56 if (Sgl_iszero_mantissa(opnd1)) { 57 if (Sgl_isnotnan(opnd2)) { 58 if (Sgl_isinfinity(opnd2)) { 59 /* 60 * invalid since both operands 61 * are infinity 62 */ 63 if (Is_invalidtrap_enabled()) 64 return(INVALIDEXCEPTION); 65 Set_invalidflag(); 66 Sgl_makequietnan(result); 67 *dstptr = result; 68 return(NOEXCEPTION); 69 } 70 /* 71 * return infinity 72 */ 73 Sgl_setinfinity_exponentmantissa(result); 74 *dstptr = result; 75 return(NOEXCEPTION); 76 } 77 } 78 else { 79 /* 80 * is NaN; signaling or quiet? 81 */ 82 if (Sgl_isone_signaling(opnd1)) { 83 /* trap if INVALIDTRAP enabled */ 84 if (Is_invalidtrap_enabled()) 85 return(INVALIDEXCEPTION); 86 /* make NaN quiet */ 87 Set_invalidflag(); 88 Sgl_set_quiet(opnd1); 89 } 90 /* 91 * is second operand a signaling NaN? 92 */ 93 else if (Sgl_is_signalingnan(opnd2)) { 94 /* trap if INVALIDTRAP enabled */ 95 if (Is_invalidtrap_enabled()) 96 return(INVALIDEXCEPTION); 97 /* make NaN quiet */ 98 Set_invalidflag(); 99 Sgl_set_quiet(opnd2); 100 *dstptr = opnd2; 101 return(NOEXCEPTION); 102 } 103 /* 104 * return quiet NaN 105 */ 106 *dstptr = opnd1; 107 return(NOEXCEPTION); 108 } 109 } 110 /* 111 * check second operand for NaN's or infinity 112 */ 113 if (Sgl_isinfinity_exponent(opnd2)) { 114 if (Sgl_iszero_mantissa(opnd2)) { 115 /* 116 * return zero 117 */ 118 Sgl_setzero_exponentmantissa(result); 119 *dstptr = result; 120 return(NOEXCEPTION); 121 } 122 /* 123 * is NaN; signaling or quiet? 124 */ 125 if (Sgl_isone_signaling(opnd2)) { 126 /* trap if INVALIDTRAP enabled */ 127 if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 128 /* make NaN quiet */ 129 Set_invalidflag(); 130 Sgl_set_quiet(opnd2); 131 } 132 /* 133 * return quiet NaN 134 */ 135 *dstptr = opnd2; 136 return(NOEXCEPTION); 137 } 138 /* 139 * check for division by zero 140 */ 141 if (Sgl_iszero_exponentmantissa(opnd2)) { 142 if (Sgl_iszero_exponentmantissa(opnd1)) { 143 /* invalid since both operands are zero */ 144 if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 145 Set_invalidflag(); 146 Sgl_makequietnan(result); 147 *dstptr = result; 148 return(NOEXCEPTION); 149 } 150 if (Is_divisionbyzerotrap_enabled()) 151 return(DIVISIONBYZEROEXCEPTION); 152 Set_divisionbyzeroflag(); 153 Sgl_setinfinity_exponentmantissa(result); 154 *dstptr = result; 155 return(NOEXCEPTION); 156 } 157 /* 158 * Generate exponent 159 */ 160 dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS; 161 162 /* 163 * Generate mantissa 164 */ 165 if (Sgl_isnotzero_exponent(opnd1)) { 166 /* set hidden bit */ 167 Sgl_clear_signexponent_set_hidden(opnd1); 168 } 169 else { 170 /* check for zero */ 171 if (Sgl_iszero_mantissa(opnd1)) { 172 Sgl_setzero_exponentmantissa(result); 173 *dstptr = result; 174 return(NOEXCEPTION); 175 } 176 /* is denormalized; want to normalize */ 177 Sgl_clear_signexponent(opnd1); 178 Sgl_leftshiftby1(opnd1); 179 Sgl_normalize(opnd1,dest_exponent); 180 } 181 /* opnd2 needs to have hidden bit set with msb in hidden bit */ 182 if (Sgl_isnotzero_exponent(opnd2)) { 183 Sgl_clear_signexponent_set_hidden(opnd2); 184 } 185 else { 186 /* is denormalized; want to normalize */ 187 Sgl_clear_signexponent(opnd2); 188 Sgl_leftshiftby1(opnd2); 189 while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) { 190 Sgl_leftshiftby8(opnd2); 191 dest_exponent += 8; 192 } 193 if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) { 194 Sgl_leftshiftby4(opnd2); 195 dest_exponent += 4; 196 } 197 while(Sgl_iszero_hidden(opnd2)) { 198 Sgl_leftshiftby1(opnd2); 199 dest_exponent += 1; 200 } 201 } 202 203 /* Divide the source mantissas */ 204 205 /* 206 * A non_restoring divide algorithm is used. 207 */ 208 Sgl_subtract(opnd1,opnd2,opnd1); 209 Sgl_setzero(opnd3); 210 for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) { 211 Sgl_leftshiftby1(opnd1); 212 Sgl_leftshiftby1(opnd3); 213 if (Sgl_iszero_sign(opnd1)) { 214 Sgl_setone_lowmantissa(opnd3); 215 Sgl_subtract(opnd1,opnd2,opnd1); 216 } 217 else Sgl_addition(opnd1,opnd2,opnd1); 218 } 219 if (count <= SGL_P) { 220 Sgl_leftshiftby1(opnd3); 221 Sgl_setone_lowmantissa(opnd3); 222 Sgl_leftshift(opnd3,SGL_P-count); 223 if (Sgl_iszero_hidden(opnd3)) { 224 Sgl_leftshiftby1(opnd3); 225 dest_exponent--; 226 } 227 } 228 else { 229 if (Sgl_iszero_hidden(opnd3)) { 230 /* need to get one more bit of result */ 231 Sgl_leftshiftby1(opnd1); 232 Sgl_leftshiftby1(opnd3); 233 if (Sgl_iszero_sign(opnd1)) { 234 Sgl_setone_lowmantissa(opnd3); 235 Sgl_subtract(opnd1,opnd2,opnd1); 236 } 237 else Sgl_addition(opnd1,opnd2,opnd1); 238 dest_exponent--; 239 } 240 if (Sgl_iszero_sign(opnd1)) guardbit = TRUE; 241 stickybit = Sgl_all(opnd1); 242 } 243 inexact = guardbit | stickybit; 244 245 /* 246 * round result 247 */ 248 if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) { 249 Sgl_clear_signexponent(opnd3); 250 switch (Rounding_mode()) { 251 case ROUNDPLUS: 252 if (Sgl_iszero_sign(result)) 253 Sgl_increment_mantissa(opnd3); 254 break; 255 case ROUNDMINUS: 256 if (Sgl_isone_sign(result)) 257 Sgl_increment_mantissa(opnd3); 258 break; 259 case ROUNDNEAREST: 260 if (guardbit) { 261 if (stickybit || Sgl_isone_lowmantissa(opnd3)) 262 Sgl_increment_mantissa(opnd3); 263 } 264 } 265 if (Sgl_isone_hidden(opnd3)) dest_exponent++; 266 } 267 Sgl_set_mantissa(result,opnd3); 268 269 /* 270 * Test for overflow 271 */ 272 if (dest_exponent >= SGL_INFINITY_EXPONENT) { 273 /* trap if OVERFLOWTRAP enabled */ 274 if (Is_overflowtrap_enabled()) { 275 /* 276 * Adjust bias of result 277 */ 278 Sgl_setwrapped_exponent(result,dest_exponent,ovfl); 279 *dstptr = result; 280 if (inexact) 281 if (Is_inexacttrap_enabled()) 282 return(OVERFLOWEXCEPTION | INEXACTEXCEPTION); 283 else Set_inexactflag(); 284 return(OVERFLOWEXCEPTION); 285 } 286 Set_overflowflag(); 287 /* set result to infinity or largest number */ 288 Sgl_setoverflow(result); 289 inexact = TRUE; 290 } 291 /* 292 * Test for underflow 293 */ 294 else if (dest_exponent <= 0) { 295 /* trap if UNDERFLOWTRAP enabled */ 296 if (Is_underflowtrap_enabled()) { 297 /* 298 * Adjust bias of result 299 */ 300 Sgl_setwrapped_exponent(result,dest_exponent,unfl); 301 *dstptr = result; 302 if (inexact) 303 if (Is_inexacttrap_enabled()) 304 return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION); 305 else Set_inexactflag(); 306 return(UNDERFLOWEXCEPTION); 307 } 308 309 /* Determine if should set underflow flag */ 310 is_tiny = TRUE; 311 if (dest_exponent == 0 && inexact) { 312 switch (Rounding_mode()) { 313 case ROUNDPLUS: 314 if (Sgl_iszero_sign(result)) { 315 Sgl_increment(opnd3); 316 if (Sgl_isone_hiddenoverflow(opnd3)) 317 is_tiny = FALSE; 318 Sgl_decrement(opnd3); 319 } 320 break; 321 case ROUNDMINUS: 322 if (Sgl_isone_sign(result)) { 323 Sgl_increment(opnd3); 324 if (Sgl_isone_hiddenoverflow(opnd3)) 325 is_tiny = FALSE; 326 Sgl_decrement(opnd3); 327 } 328 break; 329 case ROUNDNEAREST: 330 if (guardbit && (stickybit || 331 Sgl_isone_lowmantissa(opnd3))) { 332 Sgl_increment(opnd3); 333 if (Sgl_isone_hiddenoverflow(opnd3)) 334 is_tiny = FALSE; 335 Sgl_decrement(opnd3); 336 } 337 break; 338 } 339 } 340 341 /* 342 * denormalize result or set to signed zero 343 */ 344 stickybit = inexact; 345 Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact); 346 347 /* return rounded number */ 348 if (inexact) { 349 switch (Rounding_mode()) { 350 case ROUNDPLUS: 351 if (Sgl_iszero_sign(result)) { 352 Sgl_increment(opnd3); 353 } 354 break; 355 case ROUNDMINUS: 356 if (Sgl_isone_sign(result)) { 357 Sgl_increment(opnd3); 358 } 359 break; 360 case ROUNDNEAREST: 361 if (guardbit && (stickybit || 362 Sgl_isone_lowmantissa(opnd3))) { 363 Sgl_increment(opnd3); 364 } 365 break; 366 } 367 if (is_tiny) Set_underflowflag(); 368 } 369 Sgl_set_exponentmantissa(result,opnd3); 370 } 371 else Sgl_set_exponent(result,dest_exponent); 372 *dstptr = result; 373 /* check for inexact */ 374 if (inexact) { 375 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION); 376 else Set_inexactflag(); 377 } 378 return(NOEXCEPTION); 379 } 380
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.