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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1994-1997, by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #include "quad.h" 28 29 #ifdef __sparcv9 30 #define _Q_qtod _Qp_qtod 31 #endif 32 33 /* 34 * _Q_qtod(x) returns (double)*x. 35 */ 36 double 37 _Q_qtod(const union longdouble *x) 38 { 39 union xdouble u; 40 unsigned int xm, round, sticky, fsr, rm; 41 int subnormal, e; 42 43 xm = x->l.msw & 0x7fffffff; 44 45 /* get the rounding mode, fudging directed rounding modes */ 46 /* as though the result were positive */ 47 __quad_getfsrp(&fsr); 48 rm = fsr >> 30; 49 if (x->l.msw & 0x80000000) 50 rm ^= (rm >> 1); 51 52 /* handle nan, inf, and out-of-range cases */ 53 if (xm >= 0x43ff0000) { 54 if (xm >= 0x7fff0000) { 55 if ((xm & 0xffff) | x->l.frac2 | x->l.frac3 | 56 x->l.frac4) { 57 /* x is nan */ 58 u.l.hi = (x->l.msw & 0x80000000) | 0x7ff80000; 59 u.l.hi |= ((xm & 0x7fff) << 4) | 60 (x->l.frac2 >> 28); 61 u.l.lo = (x->l.frac2 << 4) | 62 (x->l.frac3 >> 28); 63 if (!(xm & 0x8000)) { 64 /* snan, signal invalid */ 65 if (fsr & FSR_NVM) { 66 __quad_fqtod(x, &u.d); 67 } else { 68 fsr = (fsr & ~FSR_CEXC) | 69 FSR_NVA | FSR_NVC; 70 __quad_setfsrp(&fsr); 71 } 72 } 73 return (u.d); 74 } 75 /* x is inf */ 76 u.l.hi = (x->l.msw & 0x80000000) | 0x7ff00000; 77 u.l.lo = 0; 78 return (u.d); 79 } 80 /* x is too big, overflow */ 81 if (rm == FSR_RN || rm == FSR_RP) { 82 u.l.hi = 0x7ff00000; 83 u.l.lo = 0; 84 } else { 85 u.l.hi = 0x7fefffff; 86 u.l.lo = 0xffffffff; 87 } 88 u.l.hi |= (x->l.msw & 0x80000000); 89 if (fsr & (FSR_OFM | FSR_NXM)) { 90 __quad_fqtod(x, &u.d); 91 } else { 92 fsr = (fsr & ~FSR_CEXC) | FSR_OFA | FSR_OFC | 93 FSR_NXA | FSR_NXC; 94 __quad_setfsrp(&fsr); 95 } 96 return (u.d); 97 } 98 99 subnormal = 0; 100 if (xm < 0x3c010000) { 101 if (xm < 0x3bcc0000) { 102 if (QUAD_ISZERO(*x)) { 103 u.l.hi = (x->l.msw & 0x80000000); 104 u.l.lo = 0; 105 return (u.d); 106 } 107 /* x is too small, underflow */ 108 u.l.hi = (x->l.msw & 0x80000000); 109 u.l.lo = ((rm == FSR_RP)? 1 : 0); 110 if (fsr & (FSR_UFM | FSR_NXM)) { 111 __quad_fqtod(x, &u.d); 112 } else { 113 fsr = (fsr & ~FSR_CEXC) | FSR_UFA | FSR_UFC | 114 FSR_NXA | FSR_NXC; 115 __quad_setfsrp(&fsr); 116 } 117 return (u.d); 118 } 119 120 /* x is in the subnormal range for double */ 121 subnormal = 1; 122 u.l.hi = 0x80000 | ((xm & 0xffff) << 3) | (x->l.frac2 >> 29); 123 u.l.lo = (x->l.frac2 << 3) | (x->l.frac3 >> 29); 124 round = x->l.frac3 & 0x10000000; 125 sticky = (x->l.frac3 & 0xfffffff) | x->l.frac4; 126 e = 0x3c00 - (xm >> 16); 127 if (e >= 32) { 128 sticky |= round | (u.l.lo & 0x7fffffff); 129 round = u.l.lo & 0x80000000; 130 u.l.lo = u.l.hi; 131 u.l.hi = 0; 132 e -= 32; 133 } 134 if (e) { 135 sticky |= round | (u.l.lo & ((1 << (e - 1)) - 1)); 136 round = u.l.lo & (1 << (e - 1)); 137 u.l.lo = (u.l.lo >> e) | (u.l.hi << (32 - e)); 138 u.l.hi >>= e; 139 } 140 } else { 141 /* x is in the normal range for double */ 142 u.l.hi = ((xm - 0x3c000000) << 4) | (x->l.frac2 >> 28); 143 u.l.lo = (x->l.frac2 << 4) | (x->l.frac3 >> 28); 144 round = x->l.frac3 & 0x8000000; 145 sticky = (x->l.frac3 & 0x7ffffff) | x->l.frac4; 146 } 147 148 /* see if we need to round */ 149 fsr &= ~FSR_CEXC; 150 if (round | sticky) { 151 fsr |= FSR_NXC; 152 if (subnormal) 153 fsr |= FSR_UFC; 154 155 /* round up if necessary */ 156 if (rm == FSR_RP || (rm == FSR_RN && round && (sticky || 157 (u.l.lo & 1)))) { 158 /* round up and check for overflow */ 159 if (++u.l.lo == 0) 160 if (++u.l.hi >= 0x7ff00000) 161 fsr |= FSR_OFC; 162 } 163 } 164 165 /* if result is exact and subnormal but underflow trapping is */ 166 /* enabled, signal underflow */ 167 else if (subnormal && (fsr & FSR_UFM)) 168 fsr |= FSR_UFC; 169 170 /* attach the sign and raise exceptions as need be */ 171 u.l.hi |= (x->l.msw & 0x80000000); 172 if ((fsr & FSR_CEXC) & (fsr >> 23)) { 173 __quad_setfsrp(&fsr); 174 __quad_fqtod(x, &u.d); 175 } else { 176 fsr |= (fsr & 0x1f) << 5; 177 __quad_setfsrp(&fsr); 178 } 179 return (u.d); 180 } 181