1/* Id: softfloat.c,v 1.4 2009/07/29 12:32:34 ragge Exp */ 2/* $NetBSD: softfloat.c,v 1.1.1.2 2010/06/03 18:57:43 plunky Exp $ */ 3 4/* 5 * Copyright (c) 2008 Anders Magnusson. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#ifdef SOFTFLOAT 31 32#include "pass1.h" 33 34 35/* 36 * Floating point emulation to be used when cross-compiling. 37 * Currently only supports F- and D-float, used in DEC machines. 38 * Should be trivial to add other emulations. 39 * 40 * XXX - assumes that: 41 * - long long is (at least) 64 bits 42 * - int is at least 32 bits. 43 * - short is 16 bits. 44 */ 45 46#ifdef FDFLOAT 47 48/* 49 * Useful macros to manipulate the float. 50 */ 51#define DSIGN(w) (((w).fd1 >> 15) & 1) 52#define DSIGNSET(w,s) ((w).fd1 = (s << 15) | ((w).fd1 & 077777)) 53#define DEXP(w) (((w).fd1 >> 7) & 0377) 54#define DEXPSET(w,e) ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177)) 55#define DMANTH(w) ((w).fd1 & 0177) 56#define DMANTHSET(w,m) ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600)) 57 58typedef unsigned int lword; 59typedef unsigned long long dword; 60 61#define MAXMANT 0x100000000000000LL 62 63/* 64 * Returns a zero dfloat. 65 */ 66static SF 67nulldf(void) 68{ 69 SF rv; 70 71 rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0; 72 return rv; 73} 74 75/* 76 * Convert a (u)longlong to dfloat. 77 * XXX - fails on too large (> 55 bits) numbers. 78 */ 79SF 80soft_cast(CONSZ ll, TWORD t) 81{ 82 int i; 83 SF rv; 84 85 rv = nulldf(); 86 if (ll == 0) 87 return rv; /* fp is zero */ 88 if (ll < 0) 89 DSIGNSET(rv,1), ll = -ll; 90 for (i = 0; ll > 0; i++, ll <<= 1) 91 ; 92 DEXPSET(rv, 192-i); 93 DMANTHSET(rv, ll >> 56); 94 rv.fd2 = ll >> 40; 95 rv.fd3 = ll >> 24; 96 rv.fd4 = ll >> 8; 97 return rv; 98} 99 100/* 101 * multiply two dfloat. Use chop, not round. 102 */ 103SF 104soft_mul(SF p1, SF p2) 105{ 106 SF rv; 107 lword a1[2], a2[2], res[4]; 108 dword sum; 109 110 res[0] = res[1] = res[2] = res[3] = 0; 111 112 /* move mantissa into lwords */ 113 a1[0] = p1.fd4 | (p1.fd3 << 16); 114 a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000; 115 116 a2[0] = p2.fd4 | (p2.fd3 << 16); 117 a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000; 118 119#define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \ 120 res[r] = sum; sum >>= 32; 121 122 sum = 0; 123 MULONE(0, 0, 0); 124 MULONE(1, 0, 1); 125 res[2] = sum; 126 sum = 0; 127 MULONE(0, 1, 1); 128 MULONE(1, 1, 2); 129 res[3] = sum; 130 131 rv.fd1 = 0; 132 DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2)); 133 DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128); 134 if (res[3] & 0x8000) { 135 res[3] = (res[3] << 8) | (res[2] >> 24); 136 res[2] = (res[2] << 8) | (res[1] >> 24); 137 } else { 138 DEXPSET(rv, DEXP(rv) - 1); 139 res[3] = (res[3] << 9) | (res[2] >> 23); 140 res[2] = (res[2] << 9) | (res[1] >> 23); 141 } 142 DMANTHSET(rv, res[3] >> 16); 143 rv.fd2 = res[3]; 144 rv.fd3 = res[2] >> 16; 145 rv.fd4 = res[2]; 146 return rv; 147} 148 149SF 150soft_div(SF t, SF n) 151{ 152 SF rv; 153 dword T, N, K; 154 int c; 155 156#define SHL(x,b) ((dword)(x) << b) 157 T = SHL(1,55) | SHL(DMANTH(t), 48) | 158 SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4; 159 N = SHL(1,55) | SHL(DMANTH(n), 48) | 160 SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4; 161 162 c = T > N; 163 for (K = 0; (K & 0x80000000000000ULL) == 0; ) { 164 if (T >= N) { 165 T -= N; 166 K |= 1; 167 } 168 T <<= 1; 169 K <<= 1; 170 } 171 rv.fd1 = 0; 172 DSIGNSET(rv, DSIGN(t) ^ DSIGN(n)); 173 DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c); 174 DMANTHSET(rv, K >> 48); 175 rv.fd2 = K >> 32; 176 rv.fd3 = K >> 16; 177 rv.fd4 = K; 178 return rv; 179} 180 181/* 182 * Negate a float number. Easy. 183 */ 184SF 185soft_neg(SF sf) 186{ 187 int sign = DSIGN(sf) == 0; 188 DSIGNSET(sf, sign); 189 return sf; 190} 191 192/* 193 * Return true if fp number is zero. 194 */ 195int 196soft_isz(SF sf) 197{ 198 return (DEXP(sf) == 0); 199} 200 201int 202soft_cmp_eq(SF x1, SF x2) 203{ 204 cerror("soft_cmp_eq"); 205 return 0; 206} 207 208int 209soft_cmp_ne(SF x1, SF x2) 210{ 211 cerror("soft_cmp_ne"); 212 return 0; 213} 214 215int 216soft_cmp_le(SF x1, SF x2) 217{ 218 cerror("soft_cmp_le"); 219 return 0; 220} 221 222int 223soft_cmp_lt(SF x1, SF x2) 224{ 225 cerror("soft_cmp_lt"); 226 return 0; 227} 228 229int 230soft_cmp_ge(SF x1, SF x2) 231{ 232 cerror("soft_cmp_ge"); 233 return 0; 234} 235 236int 237soft_cmp_gt(SF x1, SF x2) 238{ 239 cerror("soft_cmp_gt"); 240 return 0; 241} 242 243/* 244 * Convert a fp number to a CONSZ. 245 */ 246CONSZ 247soft_val(SF sf) 248{ 249 CONSZ mant; 250 int exp = DEXP(sf) - 128; 251 252 mant = SHL(1,55) | SHL(DMANTH(sf), 48) | 253 SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4; 254 255 while (exp < 0) 256 mant >>= 1, exp++; 257 while (exp > 0) 258 mant <<= 1, exp--; 259 return mant; 260} 261 262SF 263soft_plus(SF x1, SF x2) 264{ 265 cerror("soft_plus"); 266 return x1; 267} 268 269SF 270soft_minus(SF x1, SF x2) 271{ 272 cerror("soft_minus"); 273 return x1; 274} 275 276/* 277 * Convert a hex constant to floating point number. 278 */ 279NODE * 280fhexcon(char *s) 281{ 282 cerror("fhexcon"); 283 return NULL; 284} 285 286/* 287 * Convert a floating-point constant to D-float and store it in a NODE. 288 */ 289NODE * 290floatcon(char *s) 291{ 292 NODE *p; 293 dword mant; 294 SF fl, flexp, exp5; 295 int exp, negexp, bexp; 296 297 exp = 0; 298 mant = 0; 299#define ADDTO(sum, val) sum = sum * 10 + val - '0' 300 for (; *s >= '0' && *s <= '9'; s++) { 301 if (mant<MAXMANT) 302 ADDTO(mant, *s); 303 else 304 exp++; 305 } 306 if (*s == '.') { 307 for (s++; *s >= '0' && *s <= '9'; s++) { 308 if (mant<MAXMANT) { 309 ADDTO(mant, *s); 310 exp--; 311 } 312 } 313 } 314 315 if ((*s == 'E') || (*s == 'e')) { 316 int eexp = 0, sign = 0; 317 s++; 318 if (*s == '+') 319 s++; 320 else if (*s=='-') 321 sign = 1, s++; 322 323 for (; *s >= '0' && *s <= '9'; s++) 324 ADDTO(eexp, *s); 325 if (sign) 326 eexp = -eexp; 327 exp = exp + eexp; 328 } 329 330 negexp = 1; 331 if (exp<0) { 332 negexp = -1; 333 exp = -exp; 334 } 335 336 337 flexp = soft_cast(1, INT); 338 exp5 = soft_cast(5, INT); 339 bexp = exp; 340 fl = soft_cast(mant, INT); 341 342 for (; exp; exp >>= 1) { 343 if (exp&01) 344 flexp = soft_mul(flexp, exp5); 345 exp5 = soft_mul(exp5, exp5); 346 } 347 if (negexp<0) 348 fl = soft_div(fl, flexp); 349 else 350 fl = soft_mul(fl, flexp); 351 352 DEXPSET(fl, DEXP(fl) + negexp*bexp); 353 p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */ 354 p->n_dcon = fl; 355 return p; 356} 357#else 358#error missing softfloat definition 359#endif 360#endif 361