|
|
1.1 ! root 1: /* ! 2: * Helpers for floating point instructions. ! 3: * ! 4: * Copyright (c) 2007 Jocelyn Mayer ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License as published by the Free Software Foundation; either ! 9: * version 2 of the License, or (at your option) any later version. ! 10: * ! 11: * This library is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * Lesser General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU Lesser General Public ! 17: * License along with this library; if not, see <http://www.gnu.org/licenses/>. ! 18: */ ! 19: ! 20: #include "cpu.h" ! 21: #include "helper.h" ! 22: #include "softfloat.h" ! 23: ! 24: #define FP_STATUS (env->fp_status) ! 25: ! 26: ! 27: void helper_setroundmode(CPUAlphaState *env, uint32_t val) ! 28: { ! 29: set_float_rounding_mode(val, &FP_STATUS); ! 30: } ! 31: ! 32: void helper_setflushzero(CPUAlphaState *env, uint32_t val) ! 33: { ! 34: set_flush_to_zero(val, &FP_STATUS); ! 35: } ! 36: ! 37: void helper_fp_exc_clear(CPUAlphaState *env) ! 38: { ! 39: set_float_exception_flags(0, &FP_STATUS); ! 40: } ! 41: ! 42: uint32_t helper_fp_exc_get(CPUAlphaState *env) ! 43: { ! 44: return get_float_exception_flags(&FP_STATUS); ! 45: } ! 46: ! 47: static inline void inline_fp_exc_raise(CPUAlphaState *env, uintptr_t retaddr, ! 48: uint32_t exc, uint32_t regno) ! 49: { ! 50: if (exc) { ! 51: uint32_t hw_exc = 0; ! 52: ! 53: if (exc & float_flag_invalid) { ! 54: hw_exc |= EXC_M_INV; ! 55: } ! 56: if (exc & float_flag_divbyzero) { ! 57: hw_exc |= EXC_M_DZE; ! 58: } ! 59: if (exc & float_flag_overflow) { ! 60: hw_exc |= EXC_M_FOV; ! 61: } ! 62: if (exc & float_flag_underflow) { ! 63: hw_exc |= EXC_M_UNF; ! 64: } ! 65: if (exc & float_flag_inexact) { ! 66: hw_exc |= EXC_M_INE; ! 67: } ! 68: ! 69: arith_excp(env, retaddr, hw_exc, 1ull << regno); ! 70: } ! 71: } ! 72: ! 73: /* Raise exceptions for ieee fp insns without software completion. ! 74: In that case there are no exceptions that don't trap; the mask ! 75: doesn't apply. */ ! 76: void helper_fp_exc_raise(CPUAlphaState *env, uint32_t exc, uint32_t regno) ! 77: { ! 78: inline_fp_exc_raise(env, GETPC(), exc, regno); ! 79: } ! 80: ! 81: /* Raise exceptions for ieee fp insns with software completion. */ ! 82: void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t exc, uint32_t regno) ! 83: { ! 84: if (exc) { ! 85: env->fpcr_exc_status |= exc; ! 86: exc &= ~env->fpcr_exc_mask; ! 87: inline_fp_exc_raise(env, GETPC(), exc, regno); ! 88: } ! 89: } ! 90: ! 91: /* Input handing without software completion. Trap for all ! 92: non-finite numbers. */ ! 93: void helper_ieee_input(CPUAlphaState *env, uint64_t val) ! 94: { ! 95: uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; ! 96: uint64_t frac = val & 0xfffffffffffffull; ! 97: ! 98: if (exp == 0) { ! 99: /* Denormals without DNZ set raise an exception. */ ! 100: if (frac != 0 && !env->fp_status.flush_inputs_to_zero) { ! 101: arith_excp(env, GETPC(), EXC_M_UNF, 0); ! 102: } ! 103: } else if (exp == 0x7ff) { ! 104: /* Infinity or NaN. */ ! 105: /* ??? I'm not sure these exception bit flags are correct. I do ! 106: know that the Linux kernel, at least, doesn't rely on them and ! 107: just emulates the insn to figure out what exception to use. */ ! 108: arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0); ! 109: } ! 110: } ! 111: ! 112: /* Similar, but does not trap for infinities. Used for comparisons. */ ! 113: void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val) ! 114: { ! 115: uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; ! 116: uint64_t frac = val & 0xfffffffffffffull; ! 117: ! 118: if (exp == 0) { ! 119: /* Denormals without DNZ set raise an exception. */ ! 120: if (frac != 0 && !env->fp_status.flush_inputs_to_zero) { ! 121: arith_excp(env, GETPC(), EXC_M_UNF, 0); ! 122: } ! 123: } else if (exp == 0x7ff && frac) { ! 124: /* NaN. */ ! 125: arith_excp(env, GETPC(), EXC_M_INV, 0); ! 126: } ! 127: } ! 128: ! 129: /* F floating (VAX) */ ! 130: static uint64_t float32_to_f(float32 fa) ! 131: { ! 132: uint64_t r, exp, mant, sig; ! 133: CPU_FloatU a; ! 134: ! 135: a.f = fa; ! 136: sig = ((uint64_t)a.l & 0x80000000) << 32; ! 137: exp = (a.l >> 23) & 0xff; ! 138: mant = ((uint64_t)a.l & 0x007fffff) << 29; ! 139: ! 140: if (exp == 255) { ! 141: /* NaN or infinity */ ! 142: r = 1; /* VAX dirty zero */ ! 143: } else if (exp == 0) { ! 144: if (mant == 0) { ! 145: /* Zero */ ! 146: r = 0; ! 147: } else { ! 148: /* Denormalized */ ! 149: r = sig | ((exp + 1) << 52) | mant; ! 150: } ! 151: } else { ! 152: if (exp >= 253) { ! 153: /* Overflow */ ! 154: r = 1; /* VAX dirty zero */ ! 155: } else { ! 156: r = sig | ((exp + 2) << 52); ! 157: } ! 158: } ! 159: ! 160: return r; ! 161: } ! 162: ! 163: static float32 f_to_float32(CPUAlphaState *env, uintptr_t retaddr, uint64_t a) ! 164: { ! 165: uint32_t exp, mant_sig; ! 166: CPU_FloatU r; ! 167: ! 168: exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f); ! 169: mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff); ! 170: ! 171: if (unlikely(!exp && mant_sig)) { ! 172: /* Reserved operands / Dirty zero */ ! 173: dynamic_excp(env, retaddr, EXCP_OPCDEC, 0); ! 174: } ! 175: ! 176: if (exp < 3) { ! 177: /* Underflow */ ! 178: r.l = 0; ! 179: } else { ! 180: r.l = ((exp - 2) << 23) | mant_sig; ! 181: } ! 182: ! 183: return r.f; ! 184: } ! 185: ! 186: uint32_t helper_f_to_memory(uint64_t a) ! 187: { ! 188: uint32_t r; ! 189: r = (a & 0x00001fffe0000000ull) >> 13; ! 190: r |= (a & 0x07ffe00000000000ull) >> 45; ! 191: r |= (a & 0xc000000000000000ull) >> 48; ! 192: return r; ! 193: } ! 194: ! 195: uint64_t helper_memory_to_f(uint32_t a) ! 196: { ! 197: uint64_t r; ! 198: r = ((uint64_t)(a & 0x0000c000)) << 48; ! 199: r |= ((uint64_t)(a & 0x003fffff)) << 45; ! 200: r |= ((uint64_t)(a & 0xffff0000)) << 13; ! 201: if (!(a & 0x00004000)) { ! 202: r |= 0x7ll << 59; ! 203: } ! 204: return r; ! 205: } ! 206: ! 207: /* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should ! 208: either implement VAX arithmetic properly or just signal invalid opcode. */ ! 209: ! 210: uint64_t helper_addf(CPUAlphaState *env, uint64_t a, uint64_t b) ! 211: { ! 212: float32 fa, fb, fr; ! 213: ! 214: fa = f_to_float32(env, GETPC(), a); ! 215: fb = f_to_float32(env, GETPC(), b); ! 216: fr = float32_add(fa, fb, &FP_STATUS); ! 217: return float32_to_f(fr); ! 218: } ! 219: ! 220: uint64_t helper_subf(CPUAlphaState *env, uint64_t a, uint64_t b) ! 221: { ! 222: float32 fa, fb, fr; ! 223: ! 224: fa = f_to_float32(env, GETPC(), a); ! 225: fb = f_to_float32(env, GETPC(), b); ! 226: fr = float32_sub(fa, fb, &FP_STATUS); ! 227: return float32_to_f(fr); ! 228: } ! 229: ! 230: uint64_t helper_mulf(CPUAlphaState *env, uint64_t a, uint64_t b) ! 231: { ! 232: float32 fa, fb, fr; ! 233: ! 234: fa = f_to_float32(env, GETPC(), a); ! 235: fb = f_to_float32(env, GETPC(), b); ! 236: fr = float32_mul(fa, fb, &FP_STATUS); ! 237: return float32_to_f(fr); ! 238: } ! 239: ! 240: uint64_t helper_divf(CPUAlphaState *env, uint64_t a, uint64_t b) ! 241: { ! 242: float32 fa, fb, fr; ! 243: ! 244: fa = f_to_float32(env, GETPC(), a); ! 245: fb = f_to_float32(env, GETPC(), b); ! 246: fr = float32_div(fa, fb, &FP_STATUS); ! 247: return float32_to_f(fr); ! 248: } ! 249: ! 250: uint64_t helper_sqrtf(CPUAlphaState *env, uint64_t t) ! 251: { ! 252: float32 ft, fr; ! 253: ! 254: ft = f_to_float32(env, GETPC(), t); ! 255: fr = float32_sqrt(ft, &FP_STATUS); ! 256: return float32_to_f(fr); ! 257: } ! 258: ! 259: ! 260: /* G floating (VAX) */ ! 261: static uint64_t float64_to_g(float64 fa) ! 262: { ! 263: uint64_t r, exp, mant, sig; ! 264: CPU_DoubleU a; ! 265: ! 266: a.d = fa; ! 267: sig = a.ll & 0x8000000000000000ull; ! 268: exp = (a.ll >> 52) & 0x7ff; ! 269: mant = a.ll & 0x000fffffffffffffull; ! 270: ! 271: if (exp == 2047) { ! 272: /* NaN or infinity */ ! 273: r = 1; /* VAX dirty zero */ ! 274: } else if (exp == 0) { ! 275: if (mant == 0) { ! 276: /* Zero */ ! 277: r = 0; ! 278: } else { ! 279: /* Denormalized */ ! 280: r = sig | ((exp + 1) << 52) | mant; ! 281: } ! 282: } else { ! 283: if (exp >= 2045) { ! 284: /* Overflow */ ! 285: r = 1; /* VAX dirty zero */ ! 286: } else { ! 287: r = sig | ((exp + 2) << 52); ! 288: } ! 289: } ! 290: ! 291: return r; ! 292: } ! 293: ! 294: static float64 g_to_float64(CPUAlphaState *env, uintptr_t retaddr, uint64_t a) ! 295: { ! 296: uint64_t exp, mant_sig; ! 297: CPU_DoubleU r; ! 298: ! 299: exp = (a >> 52) & 0x7ff; ! 300: mant_sig = a & 0x800fffffffffffffull; ! 301: ! 302: if (!exp && mant_sig) { ! 303: /* Reserved operands / Dirty zero */ ! 304: dynamic_excp(env, retaddr, EXCP_OPCDEC, 0); ! 305: } ! 306: ! 307: if (exp < 3) { ! 308: /* Underflow */ ! 309: r.ll = 0; ! 310: } else { ! 311: r.ll = ((exp - 2) << 52) | mant_sig; ! 312: } ! 313: ! 314: return r.d; ! 315: } ! 316: ! 317: uint64_t helper_g_to_memory(uint64_t a) ! 318: { ! 319: uint64_t r; ! 320: r = (a & 0x000000000000ffffull) << 48; ! 321: r |= (a & 0x00000000ffff0000ull) << 16; ! 322: r |= (a & 0x0000ffff00000000ull) >> 16; ! 323: r |= (a & 0xffff000000000000ull) >> 48; ! 324: return r; ! 325: } ! 326: ! 327: uint64_t helper_memory_to_g(uint64_t a) ! 328: { ! 329: uint64_t r; ! 330: r = (a & 0x000000000000ffffull) << 48; ! 331: r |= (a & 0x00000000ffff0000ull) << 16; ! 332: r |= (a & 0x0000ffff00000000ull) >> 16; ! 333: r |= (a & 0xffff000000000000ull) >> 48; ! 334: return r; ! 335: } ! 336: ! 337: uint64_t helper_addg(CPUAlphaState *env, uint64_t a, uint64_t b) ! 338: { ! 339: float64 fa, fb, fr; ! 340: ! 341: fa = g_to_float64(env, GETPC(), a); ! 342: fb = g_to_float64(env, GETPC(), b); ! 343: fr = float64_add(fa, fb, &FP_STATUS); ! 344: return float64_to_g(fr); ! 345: } ! 346: ! 347: uint64_t helper_subg(CPUAlphaState *env, uint64_t a, uint64_t b) ! 348: { ! 349: float64 fa, fb, fr; ! 350: ! 351: fa = g_to_float64(env, GETPC(), a); ! 352: fb = g_to_float64(env, GETPC(), b); ! 353: fr = float64_sub(fa, fb, &FP_STATUS); ! 354: return float64_to_g(fr); ! 355: } ! 356: ! 357: uint64_t helper_mulg(CPUAlphaState *env, uint64_t a, uint64_t b) ! 358: { ! 359: float64 fa, fb, fr; ! 360: ! 361: fa = g_to_float64(env, GETPC(), a); ! 362: fb = g_to_float64(env, GETPC(), b); ! 363: fr = float64_mul(fa, fb, &FP_STATUS); ! 364: return float64_to_g(fr); ! 365: } ! 366: ! 367: uint64_t helper_divg(CPUAlphaState *env, uint64_t a, uint64_t b) ! 368: { ! 369: float64 fa, fb, fr; ! 370: ! 371: fa = g_to_float64(env, GETPC(), a); ! 372: fb = g_to_float64(env, GETPC(), b); ! 373: fr = float64_div(fa, fb, &FP_STATUS); ! 374: return float64_to_g(fr); ! 375: } ! 376: ! 377: uint64_t helper_sqrtg(CPUAlphaState *env, uint64_t a) ! 378: { ! 379: float64 fa, fr; ! 380: ! 381: fa = g_to_float64(env, GETPC(), a); ! 382: fr = float64_sqrt(fa, &FP_STATUS); ! 383: return float64_to_g(fr); ! 384: } ! 385: ! 386: ! 387: /* S floating (single) */ ! 388: ! 389: /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */ ! 390: static inline uint64_t float32_to_s_int(uint32_t fi) ! 391: { ! 392: uint32_t frac = fi & 0x7fffff; ! 393: uint32_t sign = fi >> 31; ! 394: uint32_t exp_msb = (fi >> 30) & 1; ! 395: uint32_t exp_low = (fi >> 23) & 0x7f; ! 396: uint32_t exp; ! 397: ! 398: exp = (exp_msb << 10) | exp_low; ! 399: if (exp_msb) { ! 400: if (exp_low == 0x7f) { ! 401: exp = 0x7ff; ! 402: } ! 403: } else { ! 404: if (exp_low != 0x00) { ! 405: exp |= 0x380; ! 406: } ! 407: } ! 408: ! 409: return (((uint64_t)sign << 63) ! 410: | ((uint64_t)exp << 52) ! 411: | ((uint64_t)frac << 29)); ! 412: } ! 413: ! 414: static inline uint64_t float32_to_s(float32 fa) ! 415: { ! 416: CPU_FloatU a; ! 417: a.f = fa; ! 418: return float32_to_s_int(a.l); ! 419: } ! 420: ! 421: static inline uint32_t s_to_float32_int(uint64_t a) ! 422: { ! 423: return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); ! 424: } ! 425: ! 426: static inline float32 s_to_float32(uint64_t a) ! 427: { ! 428: CPU_FloatU r; ! 429: r.l = s_to_float32_int(a); ! 430: return r.f; ! 431: } ! 432: ! 433: uint32_t helper_s_to_memory(uint64_t a) ! 434: { ! 435: return s_to_float32_int(a); ! 436: } ! 437: ! 438: uint64_t helper_memory_to_s(uint32_t a) ! 439: { ! 440: return float32_to_s_int(a); ! 441: } ! 442: ! 443: uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b) ! 444: { ! 445: float32 fa, fb, fr; ! 446: ! 447: fa = s_to_float32(a); ! 448: fb = s_to_float32(b); ! 449: fr = float32_add(fa, fb, &FP_STATUS); ! 450: return float32_to_s(fr); ! 451: } ! 452: ! 453: uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b) ! 454: { ! 455: float32 fa, fb, fr; ! 456: ! 457: fa = s_to_float32(a); ! 458: fb = s_to_float32(b); ! 459: fr = float32_sub(fa, fb, &FP_STATUS); ! 460: return float32_to_s(fr); ! 461: } ! 462: ! 463: uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b) ! 464: { ! 465: float32 fa, fb, fr; ! 466: ! 467: fa = s_to_float32(a); ! 468: fb = s_to_float32(b); ! 469: fr = float32_mul(fa, fb, &FP_STATUS); ! 470: return float32_to_s(fr); ! 471: } ! 472: ! 473: uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b) ! 474: { ! 475: float32 fa, fb, fr; ! 476: ! 477: fa = s_to_float32(a); ! 478: fb = s_to_float32(b); ! 479: fr = float32_div(fa, fb, &FP_STATUS); ! 480: return float32_to_s(fr); ! 481: } ! 482: ! 483: uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a) ! 484: { ! 485: float32 fa, fr; ! 486: ! 487: fa = s_to_float32(a); ! 488: fr = float32_sqrt(fa, &FP_STATUS); ! 489: return float32_to_s(fr); ! 490: } ! 491: ! 492: ! 493: /* T floating (double) */ ! 494: static inline float64 t_to_float64(uint64_t a) ! 495: { ! 496: /* Memory format is the same as float64 */ ! 497: CPU_DoubleU r; ! 498: r.ll = a; ! 499: return r.d; ! 500: } ! 501: ! 502: static inline uint64_t float64_to_t(float64 fa) ! 503: { ! 504: /* Memory format is the same as float64 */ ! 505: CPU_DoubleU r; ! 506: r.d = fa; ! 507: return r.ll; ! 508: } ! 509: ! 510: uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b) ! 511: { ! 512: float64 fa, fb, fr; ! 513: ! 514: fa = t_to_float64(a); ! 515: fb = t_to_float64(b); ! 516: fr = float64_add(fa, fb, &FP_STATUS); ! 517: return float64_to_t(fr); ! 518: } ! 519: ! 520: uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b) ! 521: { ! 522: float64 fa, fb, fr; ! 523: ! 524: fa = t_to_float64(a); ! 525: fb = t_to_float64(b); ! 526: fr = float64_sub(fa, fb, &FP_STATUS); ! 527: return float64_to_t(fr); ! 528: } ! 529: ! 530: uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b) ! 531: { ! 532: float64 fa, fb, fr; ! 533: ! 534: fa = t_to_float64(a); ! 535: fb = t_to_float64(b); ! 536: fr = float64_mul(fa, fb, &FP_STATUS); ! 537: return float64_to_t(fr); ! 538: } ! 539: ! 540: uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b) ! 541: { ! 542: float64 fa, fb, fr; ! 543: ! 544: fa = t_to_float64(a); ! 545: fb = t_to_float64(b); ! 546: fr = float64_div(fa, fb, &FP_STATUS); ! 547: return float64_to_t(fr); ! 548: } ! 549: ! 550: uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a) ! 551: { ! 552: float64 fa, fr; ! 553: ! 554: fa = t_to_float64(a); ! 555: fr = float64_sqrt(fa, &FP_STATUS); ! 556: return float64_to_t(fr); ! 557: } ! 558: ! 559: /* Comparisons */ ! 560: uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b) ! 561: { ! 562: float64 fa, fb; ! 563: ! 564: fa = t_to_float64(a); ! 565: fb = t_to_float64(b); ! 566: ! 567: if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { ! 568: return 0x4000000000000000ULL; ! 569: } else { ! 570: return 0; ! 571: } ! 572: } ! 573: ! 574: uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b) ! 575: { ! 576: float64 fa, fb; ! 577: ! 578: fa = t_to_float64(a); ! 579: fb = t_to_float64(b); ! 580: ! 581: if (float64_eq_quiet(fa, fb, &FP_STATUS)) { ! 582: return 0x4000000000000000ULL; ! 583: } else { ! 584: return 0; ! 585: } ! 586: } ! 587: ! 588: uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b) ! 589: { ! 590: float64 fa, fb; ! 591: ! 592: fa = t_to_float64(a); ! 593: fb = t_to_float64(b); ! 594: ! 595: if (float64_le(fa, fb, &FP_STATUS)) { ! 596: return 0x4000000000000000ULL; ! 597: } else { ! 598: return 0; ! 599: } ! 600: } ! 601: ! 602: uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b) ! 603: { ! 604: float64 fa, fb; ! 605: ! 606: fa = t_to_float64(a); ! 607: fb = t_to_float64(b); ! 608: ! 609: if (float64_lt(fa, fb, &FP_STATUS)) { ! 610: return 0x4000000000000000ULL; ! 611: } else { ! 612: return 0; ! 613: } ! 614: } ! 615: ! 616: uint64_t helper_cmpgeq(CPUAlphaState *env, uint64_t a, uint64_t b) ! 617: { ! 618: float64 fa, fb; ! 619: ! 620: fa = g_to_float64(env, GETPC(), a); ! 621: fb = g_to_float64(env, GETPC(), b); ! 622: ! 623: if (float64_eq_quiet(fa, fb, &FP_STATUS)) { ! 624: return 0x4000000000000000ULL; ! 625: } else { ! 626: return 0; ! 627: } ! 628: } ! 629: ! 630: uint64_t helper_cmpgle(CPUAlphaState *env, uint64_t a, uint64_t b) ! 631: { ! 632: float64 fa, fb; ! 633: ! 634: fa = g_to_float64(env, GETPC(), a); ! 635: fb = g_to_float64(env, GETPC(), b); ! 636: ! 637: if (float64_le(fa, fb, &FP_STATUS)) { ! 638: return 0x4000000000000000ULL; ! 639: } else { ! 640: return 0; ! 641: } ! 642: } ! 643: ! 644: uint64_t helper_cmpglt(CPUAlphaState *env, uint64_t a, uint64_t b) ! 645: { ! 646: float64 fa, fb; ! 647: ! 648: fa = g_to_float64(env, GETPC(), a); ! 649: fb = g_to_float64(env, GETPC(), b); ! 650: ! 651: if (float64_lt(fa, fb, &FP_STATUS)) { ! 652: return 0x4000000000000000ULL; ! 653: } else { ! 654: return 0; ! 655: } ! 656: } ! 657: ! 658: /* Floating point format conversion */ ! 659: uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a) ! 660: { ! 661: float64 fa; ! 662: float32 fr; ! 663: ! 664: fa = t_to_float64(a); ! 665: fr = float64_to_float32(fa, &FP_STATUS); ! 666: return float32_to_s(fr); ! 667: } ! 668: ! 669: uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a) ! 670: { ! 671: float32 fa; ! 672: float64 fr; ! 673: ! 674: fa = s_to_float32(a); ! 675: fr = float32_to_float64(fa, &FP_STATUS); ! 676: return float64_to_t(fr); ! 677: } ! 678: ! 679: uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a) ! 680: { ! 681: float32 fr = int64_to_float32(a, &FP_STATUS); ! 682: return float32_to_s(fr); ! 683: } ! 684: ! 685: /* Implement float64 to uint64 conversion without saturation -- we must ! 686: supply the truncated result. This behaviour is used by the compiler ! 687: to get unsigned conversion for free with the same instruction. ! 688: ! 689: The VI flag is set when overflow or inexact exceptions should be raised. */ ! 690: ! 691: static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a, ! 692: int roundmode, int VI) ! 693: { ! 694: uint64_t frac, ret = 0; ! 695: uint32_t exp, sign, exc = 0; ! 696: int shift; ! 697: ! 698: sign = (a >> 63); ! 699: exp = (uint32_t)(a >> 52) & 0x7ff; ! 700: frac = a & 0xfffffffffffffull; ! 701: ! 702: if (exp == 0) { ! 703: if (unlikely(frac != 0)) { ! 704: goto do_underflow; ! 705: } ! 706: } else if (exp == 0x7ff) { ! 707: exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0); ! 708: } else { ! 709: /* Restore implicit bit. */ ! 710: frac |= 0x10000000000000ull; ! 711: ! 712: shift = exp - 1023 - 52; ! 713: if (shift >= 0) { ! 714: /* In this case the number is so large that we must shift ! 715: the fraction left. There is no rounding to do. */ ! 716: if (shift < 63) { ! 717: ret = frac << shift; ! 718: if (VI && (ret >> shift) != frac) { ! 719: exc = float_flag_overflow; ! 720: } ! 721: } ! 722: } else { ! 723: uint64_t round; ! 724: ! 725: /* In this case the number is smaller than the fraction as ! 726: represented by the 52 bit number. Here we must think ! 727: about rounding the result. Handle this by shifting the ! 728: fractional part of the number into the high bits of ROUND. ! 729: This will let us efficiently handle round-to-nearest. */ ! 730: shift = -shift; ! 731: if (shift < 63) { ! 732: ret = frac >> shift; ! 733: round = frac << (64 - shift); ! 734: } else { ! 735: /* The exponent is so small we shift out everything. ! 736: Leave a sticky bit for proper rounding below. */ ! 737: do_underflow: ! 738: round = 1; ! 739: } ! 740: ! 741: if (round) { ! 742: exc = (VI ? float_flag_inexact : 0); ! 743: switch (roundmode) { ! 744: case float_round_nearest_even: ! 745: if (round == (1ull << 63)) { ! 746: /* Fraction is exactly 0.5; round to even. */ ! 747: ret += (ret & 1); ! 748: } else if (round > (1ull << 63)) { ! 749: ret += 1; ! 750: } ! 751: break; ! 752: case float_round_to_zero: ! 753: break; ! 754: case float_round_up: ! 755: ret += 1 - sign; ! 756: break; ! 757: case float_round_down: ! 758: ret += sign; ! 759: break; ! 760: } ! 761: } ! 762: } ! 763: if (sign) { ! 764: ret = -ret; ! 765: } ! 766: } ! 767: if (unlikely(exc)) { ! 768: float_raise(exc, &FP_STATUS); ! 769: } ! 770: ! 771: return ret; ! 772: } ! 773: ! 774: uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a) ! 775: { ! 776: return inline_cvttq(env, a, FP_STATUS.float_rounding_mode, 1); ! 777: } ! 778: ! 779: uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a) ! 780: { ! 781: return inline_cvttq(env, a, float_round_to_zero, 0); ! 782: } ! 783: ! 784: uint64_t helper_cvttq_svic(CPUAlphaState *env, uint64_t a) ! 785: { ! 786: return inline_cvttq(env, a, float_round_to_zero, 1); ! 787: } ! 788: ! 789: uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a) ! 790: { ! 791: float64 fr = int64_to_float64(a, &FP_STATUS); ! 792: return float64_to_t(fr); ! 793: } ! 794: ! 795: uint64_t helper_cvtqf(CPUAlphaState *env, uint64_t a) ! 796: { ! 797: float32 fr = int64_to_float32(a, &FP_STATUS); ! 798: return float32_to_f(fr); ! 799: } ! 800: ! 801: uint64_t helper_cvtgf(CPUAlphaState *env, uint64_t a) ! 802: { ! 803: float64 fa; ! 804: float32 fr; ! 805: ! 806: fa = g_to_float64(env, GETPC(), a); ! 807: fr = float64_to_float32(fa, &FP_STATUS); ! 808: return float32_to_f(fr); ! 809: } ! 810: ! 811: uint64_t helper_cvtgq(CPUAlphaState *env, uint64_t a) ! 812: { ! 813: float64 fa = g_to_float64(env, GETPC(), a); ! 814: return float64_to_int64_round_to_zero(fa, &FP_STATUS); ! 815: } ! 816: ! 817: uint64_t helper_cvtqg(CPUAlphaState *env, uint64_t a) ! 818: { ! 819: float64 fr; ! 820: fr = int64_to_float64(a, &FP_STATUS); ! 821: return float64_to_g(fr); ! 822: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.