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 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "quad.h" 28 29 #ifdef __sparcv9 30 31 /* 32 * _Qp_add(pz, ox, oy) sets *pz = *ox + *oy. 33 */ 34 void 35 _Qp_add(union longdouble *pz, const union longdouble *ox, 36 const union longdouble *oy) 37 38 #else 39 40 /* 41 * _Q_add(ox, oy) returns *ox + *oy. 42 */ 43 union longdouble 44 _Q_add(const union longdouble *ox, const union longdouble *oy) 45 46 #endif /* __sparcv9 */ 47 48 { 49 union longdouble z; 50 const union longdouble *x, *y; 51 unsigned int xm, ym, tm, fsr; 52 53 /* sort so |x| >= |y| */ 54 xm = ox->l.msw & 0x7fffffff; 55 ym = oy->l.msw & 0x7fffffff; 56 if (ym > xm || ym == xm && (oy->l.frac2 > ox->l.frac2 || 57 oy->l.frac2 == ox->l.frac2 && (oy->l.frac3 > ox->l.frac3 || 58 oy->l.frac3 == ox->l.frac3 && oy->l.frac4 > ox->l.frac4))) { 59 y = ox; 60 x = oy; 61 tm = xm; 62 xm = ym; 63 ym = tm; 64 } else { 65 x = ox; 66 y = oy; 67 } 68 69 /* get the fsr */ 70 __quad_getfsrp(&fsr); 71 72 /* handle nan and inf cases */ 73 if (xm >= 0x7fff0000) { 74 /* x is nan or inf */ 75 if (ym >= 0x7fff0000) { 76 /* y is nan or inf */ 77 if ((ym & 0xffff) | y->l.frac2 | y->l.frac3 | 78 y->l.frac4) { 79 /* y is nan; x must be nan too */ 80 /* the following logic implements V9 app. B */ 81 if (!(ym & 0x8000)) { 82 /* y is snan, signal invalid */ 83 if (fsr & FSR_NVM) { 84 __quad_faddq(ox, oy, &Z); 85 } else { 86 Z = (xm & 0x8000)? *y : *oy; 87 Z.l.msw |= 0x8000; 88 fsr = (fsr & ~FSR_CEXC) | 89 FSR_NVA | FSR_NVC; 90 __quad_setfsrp(&fsr); 91 } 92 QUAD_RETURN(Z); 93 } 94 /* x and y are both qnan */ 95 Z = *oy; 96 QUAD_RETURN(Z); 97 } 98 if (!((xm & 0xffff) | x->l.frac2 | x->l.frac3 | 99 x->l.frac4)) { 100 /* x and y are both inf */ 101 if ((x->l.msw ^ y->l.msw) & 0x80000000) { 102 /* inf - inf, signal invalid */ 103 if (fsr & FSR_NVM) { 104 __quad_faddq(ox, oy, &Z); 105 } else { 106 Z.l.msw = 0x7fffffff; 107 Z.l.frac2 = Z.l.frac3 = 108 Z.l.frac4 = 0xffffffff; 109 fsr = (fsr & ~FSR_CEXC) | 110 FSR_NVA | FSR_NVC; 111 __quad_setfsrp(&fsr); 112 } 113 QUAD_RETURN(Z); 114 } 115 /* inf + inf, return inf */ 116 Z = *x; 117 QUAD_RETURN(Z); 118 } 119 } 120 if ((xm & 0xffff) | x->l.frac2 | x->l.frac3 | x->l.frac4) { 121 /* x is nan */ 122 if (!(xm & 0x8000)) { 123 /* snan, signal invalid */ 124 if (fsr & FSR_NVM) { 125 __quad_faddq(ox, oy, &Z); 126 } else { 127 Z = *x; 128 Z.l.msw |= 0x8000; 129 fsr = (fsr & ~FSR_CEXC) | FSR_NVA | 130 FSR_NVC; 131 __quad_setfsrp(&fsr); 132 } 133 QUAD_RETURN(Z); 134 } 135 Z = *x; 136 QUAD_RETURN(Z); 137 } 138 /* x is inf */ 139 Z = *x; 140 QUAD_RETURN(Z); 141 } 142 143 /* now x and y are finite and |x| >= |y| */ 144 fsr &= ~FSR_CEXC; 145 z.l.msw = (x->l.msw & 0x80000000); 146 if ((x->l.msw ^ y->l.msw) & 0x80000000) 147 __quad_mag_sub(x, y, &z, &fsr); 148 else 149 __quad_mag_add(x, y, &z, &fsr); 150 if ((fsr & FSR_CEXC) & (fsr >> 23)) { 151 __quad_setfsrp(&fsr); 152 __quad_faddq(ox, oy, &Z); 153 } else { 154 Z = z; 155 fsr |= (fsr & 0x1f) << 5; 156 __quad_setfsrp(&fsr); 157 } 158 QUAD_RETURN(Z); 159 } 160