1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "lint.h" 30 #include "base_conversion.h" 31 32 static void 33 __fp_rightshift(unpacked *pu, int n) 34 35 /* Right shift significand sticky by n bits. */ 36 37 { 38 int i; 39 40 if (n >= (32 * UNPACKED_SIZE)) { /* drastic */ 41 for (i = 0; (pu->significand[i] == 0) && (i < UNPACKED_SIZE); 42 i++); 43 if (i >= UNPACKED_SIZE) { 44 pu->fpclass = fp_zero; 45 return; 46 } else { 47 for (i = 0; i < (UNPACKED_SIZE - 1); i++) 48 pu->significand[i] = 0; 49 pu->significand[UNPACKED_SIZE - 1] = 1; 50 return; 51 } 52 } 53 while (n >= 32) { /* big shift */ 54 if (pu->significand[UNPACKED_SIZE - 1] != 0) 55 pu->significand[UNPACKED_SIZE - 2] |= 1; 56 for (i = UNPACKED_SIZE - 2; i >= 0; i--) 57 pu->significand[i + 1] = pu->significand[i]; 58 pu->significand[0] = 0; 59 n -= 32; 60 } 61 if (n >= 1) { /* small shift */ 62 unsigned int high, low, shiftout = 0; 63 for (i = 0; i < UNPACKED_SIZE; i++) { 64 high = pu->significand[i] >> n; 65 low = pu->significand[i] << (32 - n); 66 pu->significand[i] = shiftout | high; 67 shiftout = low; 68 } 69 if (shiftout != 0) 70 pu->significand[UNPACKED_SIZE - 1] |= 1; 71 } 72 } 73 74 static int 75 overflow_to_infinity(int sign, enum fp_direction_type rd) 76 77 /* Returns 1 if overflow should go to infinity, 0 if to max finite. */ 78 79 { 80 int inf; 81 82 switch (rd) { 83 case fp_nearest: 84 inf = 1; 85 break; 86 case fp_tozero: 87 inf = 0; 88 break; 89 case fp_positive: 90 inf = !sign; 91 break; 92 case fp_negative: 93 inf = sign; 94 break; 95 } 96 return (inf); 97 } 98 99 static void 100 round(unpacked *pu, int roundword, enum fp_direction_type rd, int *ex) 101 /* 102 * Round according to current rounding mode. pu must be shifted to so that 103 * the roundbit is pu->significand[roundword] & 0x80000000 104 */ 105 { 106 int increment; /* boolean to indicate round up */ 107 int is; 108 unsigned msw; /* msw before increment */ 109 110 for (is = (roundword + 1); is < UNPACKED_SIZE; is++) 111 if (pu->significand[is] != 0) { 112 /* Condense extra bits into sticky bottom of roundword. */ 113 pu->significand[roundword] |= 1; 114 break; 115 } 116 if (pu->significand[roundword] == 0) 117 return; 118 *ex |= (1 << fp_inexact); 119 switch (rd) { 120 case fp_nearest: 121 increment = pu->significand[roundword] >= 0x80000000; 122 break; 123 case fp_tozero: 124 increment = 0; 125 break; 126 case fp_positive: 127 increment = (pu->sign == 0) & (pu->significand[roundword] != 0); 128 break; 129 case fp_negative: 130 increment = (pu->sign != 0) & (pu->significand[roundword] != 0); 131 break; 132 } 133 if (increment) { 134 msw = pu->significand[0]; /* save msw before round */ 135 is = roundword; 136 do { 137 is--; 138 pu->significand[is]++; 139 } 140 while ((pu->significand[is] == 0) && (is > 0)); 141 if (pu->significand[0] < msw) { /* rounding carried out */ 142 pu->exponent++; 143 pu->significand[0] = 0x80000000; 144 } 145 } 146 if ((rd == fp_nearest) && 147 (pu->significand[roundword] == 0x80000000)) { 148 /* ambiguous case */ 149 pu->significand[roundword - 1] &= ~1; /* force round to even */ 150 } 151 } 152 153 void 154 __pack_single(unpacked *pu, single *px, enum fp_direction_type rd, 155 fp_exception_field_type *ex) 156 { 157 single_equivalence kluge; 158 int e; 159 160 e = 0; 161 kluge.f.msw.sign = pu->sign; 162 switch (pu->fpclass) { 163 case fp_zero: 164 kluge.f.msw.exponent = 0; 165 kluge.f.msw.significand = 0; 166 break; 167 case fp_infinity: 168 infinity: 169 kluge.f.msw.exponent = 0xff; 170 kluge.f.msw.significand = 0; 171 break; 172 case fp_quiet: 173 kluge.f.msw.exponent = 0xff; 174 kluge.f.msw.significand = 0x400000 | 175 (0x3fffff & (pu->significand[0] >> 8)); 176 break; 177 case fp_normal: 178 __fp_rightshift(pu, 8); 179 pu->exponent += SINGLE_BIAS; 180 if (pu->exponent <= 0) { 181 kluge.f.msw.exponent = 0; 182 __fp_rightshift(pu, 1 - pu->exponent); 183 round(pu, 1, rd, &e); 184 if (pu->significand[0] == 0x800000) { 185 /* rounded back up to normal */ 186 kluge.f.msw.exponent = 1; 187 kluge.f.msw.significand = 0; 188 e |= (1 << fp_underflow); 189 goto ret; 190 } 191 if (e & (1 << fp_inexact)) 192 e |= (1 << fp_underflow); 193 kluge.f.msw.significand = 0x7fffff & pu->significand[0]; 194 goto ret; 195 } 196 round(pu, 1, rd, &e); 197 if (pu->significand[0] == 0x1000000) { /* rounding overflow */ 198 pu->significand[0] = 0x800000; 199 pu->exponent += 1; 200 } 201 if (pu->exponent >= 0xff) { 202 e |= (1 << fp_overflow) | (1 << fp_inexact); 203 if (overflow_to_infinity(pu->sign, rd)) 204 goto infinity; 205 kluge.f.msw.exponent = 0xfe; 206 kluge.f.msw.significand = 0x7fffff; 207 goto ret; 208 } 209 kluge.f.msw.exponent = pu->exponent; 210 kluge.f.msw.significand = 0x7fffff & pu->significand[0]; 211 } 212 ret: 213 *px = kluge.x; 214 *ex = (fp_exception_field_type)e; 215 } 216 217 void 218 __pack_double(unpacked *pu, double *px, enum fp_direction_type rd, 219 fp_exception_field_type *ex) 220 { 221 double_equivalence kluge; 222 int e; 223 224 e = 0; 225 kluge.f.msw.sign = pu->sign; 226 switch (pu->fpclass) { 227 case fp_zero: 228 kluge.f.msw.exponent = 0; 229 kluge.f.msw.significand = 0; 230 kluge.f.significand2 = 0; 231 break; 232 case fp_infinity: 233 infinity: 234 kluge.f.msw.exponent = 0x7ff; 235 kluge.f.msw.significand = 0; 236 kluge.f.significand2 = 0; 237 break; 238 case fp_quiet: 239 kluge.f.msw.exponent = 0x7ff; 240 __fp_rightshift(pu, 11); 241 kluge.f.msw.significand = 0x80000 | 242 (0x7ffff & pu->significand[0]); 243 kluge.f.significand2 = pu->significand[1]; 244 break; 245 case fp_normal: 246 __fp_rightshift(pu, 11); 247 pu->exponent += DOUBLE_BIAS; 248 if (pu->exponent <= 0) { /* underflow */ 249 __fp_rightshift(pu, 1 - pu->exponent); 250 round(pu, 2, rd, &e); 251 if (pu->significand[0] == 0x100000) { 252 /* rounded back up to normal */ 253 kluge.f.msw.exponent = 1; 254 kluge.f.msw.significand = 0; 255 kluge.f.significand2 = 0; 256 e |= (1 << fp_underflow); 257 goto ret; 258 } 259 if (e & (1 << fp_inexact)) 260 e |= (1 << fp_underflow); 261 kluge.f.msw.exponent = 0; 262 kluge.f.msw.significand = 0xfffff & pu->significand[0]; 263 kluge.f.significand2 = pu->significand[1]; 264 goto ret; 265 } 266 round(pu, 2, rd, &e); 267 if (pu->significand[0] == 0x200000) { /* rounding overflow */ 268 pu->significand[0] = 0x100000; 269 pu->exponent += 1; 270 } 271 if (pu->exponent >= 0x7ff) { /* overflow */ 272 e |= (1 << fp_overflow) | (1 << fp_inexact); 273 if (overflow_to_infinity(pu->sign, rd)) 274 goto infinity; 275 kluge.f.msw.exponent = 0x7fe; 276 kluge.f.msw.significand = 0xfffff; 277 kluge.f.significand2 = 0xffffffff; 278 goto ret; 279 } 280 kluge.f.msw.exponent = pu->exponent; 281 kluge.f.msw.significand = 0xfffff & pu->significand[0]; 282 kluge.f.significand2 = pu->significand[1]; 283 break; 284 } 285 ret: 286 *px = kluge.x; 287 *ex = (fp_exception_field_type)e; 288 } 289 290 void 291 __pack_extended(unpacked *pu, extended *px, enum fp_direction_type rd, 292 fp_exception_field_type *ex) 293 { 294 extended_equivalence kluge; 295 int e; 296 297 e = 0; 298 kluge.f.msw.sign = pu->sign; 299 switch (pu->fpclass) { 300 case fp_zero: 301 kluge.f.msw.exponent = 0; 302 kluge.f.significand = 0; 303 kluge.f.significand2 = 0; 304 break; 305 case fp_infinity: 306 infinity: 307 kluge.f.msw.exponent = 0x7fff; 308 kluge.f.significand = 0x80000000; 309 kluge.f.significand2 = 0; 310 break; 311 case fp_quiet: 312 kluge.f.msw.exponent = 0x7fff; 313 kluge.f.significand = 0x40000000 | pu->significand[0]; 314 kluge.f.significand2 = pu->significand[1]; 315 break; 316 case fp_normal: 317 pu->exponent += EXTENDED_BIAS; 318 if (pu->exponent <= 0) { /* underflow */ 319 __fp_rightshift(pu, 1 - pu->exponent); 320 round(pu, 2, rd, &e); 321 if (pu->significand[0] == 0x80000000u) { 322 /* rounded back up to normal */ 323 kluge.f.msw.exponent = 1; 324 kluge.f.significand = 0x80000000u; 325 kluge.f.significand2 = 0; 326 e |= (1 << fp_underflow); 327 goto ret; 328 } 329 if (e & (1 << fp_inexact)) 330 e |= (1 << fp_underflow); 331 kluge.f.msw.exponent = 0; 332 kluge.f.significand = pu->significand[0]; 333 kluge.f.significand2 = pu->significand[1]; 334 goto ret; 335 } 336 round(pu, 2, rd, &e); 337 if (pu->exponent >= 0x7fff) { /* overflow */ 338 e |= (1 << fp_overflow) | (1 << fp_inexact); 339 if (overflow_to_infinity(pu->sign, rd)) 340 goto infinity; 341 kluge.f.msw.exponent = 0x7ffe; 342 kluge.f.significand = 0xffffffff; 343 kluge.f.significand2 = 0xffffffff; 344 goto ret; 345 } 346 kluge.f.msw.exponent = pu->exponent; 347 kluge.f.significand = pu->significand[0]; 348 kluge.f.significand2 = pu->significand[1]; 349 break; 350 } 351 ret: 352 (*px)[0] = kluge.x[0]; 353 (*px)[1] = kluge.x[1]; 354 (*px)[2] = kluge.x[2]; 355 *ex = (fp_exception_field_type)e; 356 } 357 358 void 359 __pack_quadruple(unpacked *pu, quadruple *px, enum fp_direction_type rd, 360 fp_exception_field_type *ex) 361 { 362 quadruple_equivalence kluge; 363 int e; 364 365 e = 0; 366 kluge.f.msw.sign = pu->sign; 367 switch (pu->fpclass) { 368 case fp_zero: 369 kluge.f.msw.exponent = 0; 370 kluge.f.msw.significand = 0; 371 kluge.f.significand2 = 0; 372 kluge.f.significand3 = 0; 373 kluge.f.significand4 = 0; 374 break; 375 case fp_infinity: 376 infinity: 377 kluge.f.msw.exponent = 0x7fff; 378 kluge.f.msw.significand = 0; 379 kluge.f.significand2 = 0; 380 kluge.f.significand3 = 0; 381 kluge.f.significand4 = 0; 382 break; 383 case fp_quiet: 384 kluge.f.msw.exponent = 0x7fff; 385 __fp_rightshift(pu, 15); 386 kluge.f.msw.significand = 0x8000 | 387 (0xffff & pu->significand[0]); 388 kluge.f.significand2 = pu->significand[1]; 389 kluge.f.significand3 = pu->significand[2]; 390 kluge.f.significand4 = pu->significand[3]; 391 break; 392 case fp_normal: 393 __fp_rightshift(pu, 15); 394 pu->exponent += QUAD_BIAS; 395 if (pu->exponent <= 0) { /* underflow */ 396 __fp_rightshift(pu, 1 - pu->exponent); 397 round(pu, 4, rd, &e); 398 if (pu->significand[0] == 0x10000) { 399 /* rounded back up to normal */ 400 kluge.f.msw.exponent = 1; 401 kluge.f.msw.significand = 0; 402 kluge.f.significand2 = 0; 403 kluge.f.significand3 = 0; 404 kluge.f.significand4 = 0; 405 e |= (1 << fp_underflow); 406 goto ret; 407 } 408 if (e & (1 << fp_inexact)) 409 e |= (1 << fp_underflow); 410 kluge.f.msw.exponent = 0; 411 kluge.f.msw.significand = 0xffff & pu->significand[0]; 412 kluge.f.significand2 = pu->significand[1]; 413 kluge.f.significand3 = pu->significand[2]; 414 kluge.f.significand4 = pu->significand[3]; 415 goto ret; 416 } 417 round(pu, 4, rd, &e); 418 if (pu->significand[0] == 0x20000) { /* rounding overflow */ 419 pu->significand[0] = 0x10000; 420 pu->exponent += 1; 421 } 422 if (pu->exponent >= 0x7fff) { /* overflow */ 423 e |= (1 << fp_overflow) | (1 << fp_inexact); 424 if (overflow_to_infinity(pu->sign, rd)) 425 goto infinity; 426 kluge.f.msw.exponent = 0x7ffe; 427 kluge.f.msw.significand = 0xffff; 428 kluge.f.significand2 = 0xffffffff; 429 kluge.f.significand3 = 0xffffffff; 430 kluge.f.significand4 = 0xffffffff; 431 goto ret; 432 } 433 kluge.f.msw.exponent = pu->exponent; 434 kluge.f.msw.significand = pu->significand[0] & 0xffff; 435 kluge.f.significand2 = pu->significand[1]; 436 kluge.f.significand3 = pu->significand[2]; 437 kluge.f.significand4 = pu->significand[3]; 438 break; 439 } 440 ret: 441 *px = kluge.x; 442 *ex = (fp_exception_field_type)e; 443 } 444