xref: /qemu/target/alpha/fpu_helper.c (revision 3da653fa05579579b0ba55a02ffa2aa3d466f01b)
14a58aedfSRichard Henderson /*
24a58aedfSRichard Henderson  *  Helpers for floating point instructions.
34a58aedfSRichard Henderson  *
44a58aedfSRichard Henderson  *  Copyright (c) 2007 Jocelyn Mayer
54a58aedfSRichard Henderson  *
64a58aedfSRichard Henderson  * This library is free software; you can redistribute it and/or
74a58aedfSRichard Henderson  * modify it under the terms of the GNU Lesser General Public
84a58aedfSRichard Henderson  * License as published by the Free Software Foundation; either
94a58aedfSRichard Henderson  * version 2 of the License, or (at your option) any later version.
104a58aedfSRichard Henderson  *
114a58aedfSRichard Henderson  * This library is distributed in the hope that it will be useful,
124a58aedfSRichard Henderson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
134a58aedfSRichard Henderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
144a58aedfSRichard Henderson  * Lesser General Public License for more details.
154a58aedfSRichard Henderson  *
164a58aedfSRichard Henderson  * You should have received a copy of the GNU Lesser General Public
174a58aedfSRichard Henderson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
184a58aedfSRichard Henderson  */
194a58aedfSRichard Henderson 
204a58aedfSRichard Henderson #include "cpu.h"
212ef6175aSRichard Henderson #include "exec/helper-proto.h"
226b4c305cSPaolo Bonzini #include "fpu/softfloat.h"
234a58aedfSRichard Henderson 
244a58aedfSRichard Henderson #define FP_STATUS (env->fp_status)
254a58aedfSRichard Henderson 
264a58aedfSRichard Henderson 
274a58aedfSRichard Henderson void helper_setroundmode(CPUAlphaState *env, uint32_t val)
284a58aedfSRichard Henderson {
294a58aedfSRichard Henderson     set_float_rounding_mode(val, &FP_STATUS);
304a58aedfSRichard Henderson }
314a58aedfSRichard Henderson 
324a58aedfSRichard Henderson void helper_setflushzero(CPUAlphaState *env, uint32_t val)
334a58aedfSRichard Henderson {
344a58aedfSRichard Henderson     set_flush_to_zero(val, &FP_STATUS);
354a58aedfSRichard Henderson }
364a58aedfSRichard Henderson 
374a58aedfSRichard Henderson void helper_fp_exc_clear(CPUAlphaState *env)
384a58aedfSRichard Henderson {
394a58aedfSRichard Henderson     set_float_exception_flags(0, &FP_STATUS);
404a58aedfSRichard Henderson }
414a58aedfSRichard Henderson 
424a58aedfSRichard Henderson uint32_t helper_fp_exc_get(CPUAlphaState *env)
434a58aedfSRichard Henderson {
444a58aedfSRichard Henderson     return get_float_exception_flags(&FP_STATUS);
454a58aedfSRichard Henderson }
464a58aedfSRichard Henderson 
4720503968SBlue Swirl static inline void inline_fp_exc_raise(CPUAlphaState *env, uintptr_t retaddr,
484a58aedfSRichard Henderson                                        uint32_t exc, uint32_t regno)
494a58aedfSRichard Henderson {
504a58aedfSRichard Henderson     if (exc) {
514a58aedfSRichard Henderson         uint32_t hw_exc = 0;
524a58aedfSRichard Henderson 
534a58aedfSRichard Henderson         if (exc & float_flag_invalid) {
544a58aedfSRichard Henderson             hw_exc |= EXC_M_INV;
554a58aedfSRichard Henderson         }
564a58aedfSRichard Henderson         if (exc & float_flag_divbyzero) {
574a58aedfSRichard Henderson             hw_exc |= EXC_M_DZE;
584a58aedfSRichard Henderson         }
594a58aedfSRichard Henderson         if (exc & float_flag_overflow) {
604a58aedfSRichard Henderson             hw_exc |= EXC_M_FOV;
614a58aedfSRichard Henderson         }
624a58aedfSRichard Henderson         if (exc & float_flag_underflow) {
634a58aedfSRichard Henderson             hw_exc |= EXC_M_UNF;
644a58aedfSRichard Henderson         }
654a58aedfSRichard Henderson         if (exc & float_flag_inexact) {
664a58aedfSRichard Henderson             hw_exc |= EXC_M_INE;
674a58aedfSRichard Henderson         }
684a58aedfSRichard Henderson 
694a58aedfSRichard Henderson         arith_excp(env, retaddr, hw_exc, 1ull << regno);
704a58aedfSRichard Henderson     }
714a58aedfSRichard Henderson }
724a58aedfSRichard Henderson 
734a58aedfSRichard Henderson /* Raise exceptions for ieee fp insns without software completion.
744a58aedfSRichard Henderson    In that case there are no exceptions that don't trap; the mask
754a58aedfSRichard Henderson    doesn't apply.  */
764a58aedfSRichard Henderson void helper_fp_exc_raise(CPUAlphaState *env, uint32_t exc, uint32_t regno)
774a58aedfSRichard Henderson {
784a58aedfSRichard Henderson     inline_fp_exc_raise(env, GETPC(), exc, regno);
794a58aedfSRichard Henderson }
804a58aedfSRichard Henderson 
814a58aedfSRichard Henderson /* Raise exceptions for ieee fp insns with software completion.  */
824a58aedfSRichard Henderson void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t exc, uint32_t regno)
834a58aedfSRichard Henderson {
844a58aedfSRichard Henderson     if (exc) {
854a58aedfSRichard Henderson         env->fpcr_exc_status |= exc;
864a58aedfSRichard Henderson         exc &= ~env->fpcr_exc_mask;
874a58aedfSRichard Henderson         inline_fp_exc_raise(env, GETPC(), exc, regno);
884a58aedfSRichard Henderson     }
894a58aedfSRichard Henderson }
904a58aedfSRichard Henderson 
9174343409SRichard Henderson /* Input handing without software completion.  Trap for all
9274343409SRichard Henderson    non-finite numbers.  */
9374343409SRichard Henderson void helper_ieee_input(CPUAlphaState *env, uint64_t val)
944a58aedfSRichard Henderson {
954a58aedfSRichard Henderson     uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
964a58aedfSRichard Henderson     uint64_t frac = val & 0xfffffffffffffull;
974a58aedfSRichard Henderson 
984a58aedfSRichard Henderson     if (exp == 0) {
9974343409SRichard Henderson         /* Denormals without DNZ set raise an exception.  */
10074343409SRichard Henderson         if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
1014a58aedfSRichard Henderson             arith_excp(env, GETPC(), EXC_M_UNF, 0);
1024a58aedfSRichard Henderson         }
1034a58aedfSRichard Henderson     } else if (exp == 0x7ff) {
1044a58aedfSRichard Henderson         /* Infinity or NaN.  */
1054a58aedfSRichard Henderson         /* ??? I'm not sure these exception bit flags are correct.  I do
1064a58aedfSRichard Henderson            know that the Linux kernel, at least, doesn't rely on them and
1074a58aedfSRichard Henderson            just emulates the insn to figure out what exception to use.  */
1084a58aedfSRichard Henderson         arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
1094a58aedfSRichard Henderson     }
1104a58aedfSRichard Henderson }
1114a58aedfSRichard Henderson 
1124a58aedfSRichard Henderson /* Similar, but does not trap for infinities.  Used for comparisons.  */
11374343409SRichard Henderson void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
1144a58aedfSRichard Henderson {
1154a58aedfSRichard Henderson     uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
1164a58aedfSRichard Henderson     uint64_t frac = val & 0xfffffffffffffull;
1174a58aedfSRichard Henderson 
1184a58aedfSRichard Henderson     if (exp == 0) {
11974343409SRichard Henderson         /* Denormals without DNZ set raise an exception.  */
12074343409SRichard Henderson         if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
1214a58aedfSRichard Henderson             arith_excp(env, GETPC(), EXC_M_UNF, 0);
1224a58aedfSRichard Henderson         }
1234a58aedfSRichard Henderson     } else if (exp == 0x7ff && frac) {
1244a58aedfSRichard Henderson         /* NaN.  */
1254a58aedfSRichard Henderson         arith_excp(env, GETPC(), EXC_M_INV, 0);
1264a58aedfSRichard Henderson     }
1274a58aedfSRichard Henderson }
1284a58aedfSRichard Henderson 
1294a58aedfSRichard Henderson 
1304a58aedfSRichard Henderson /* S floating (single) */
1314a58aedfSRichard Henderson 
1324a58aedfSRichard Henderson /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg.  */
1334a58aedfSRichard Henderson static inline uint64_t float32_to_s_int(uint32_t fi)
1344a58aedfSRichard Henderson {
1354a58aedfSRichard Henderson     uint32_t frac = fi & 0x7fffff;
1364a58aedfSRichard Henderson     uint32_t sign = fi >> 31;
1374a58aedfSRichard Henderson     uint32_t exp_msb = (fi >> 30) & 1;
1384a58aedfSRichard Henderson     uint32_t exp_low = (fi >> 23) & 0x7f;
1394a58aedfSRichard Henderson     uint32_t exp;
1404a58aedfSRichard Henderson 
1414a58aedfSRichard Henderson     exp = (exp_msb << 10) | exp_low;
1424a58aedfSRichard Henderson     if (exp_msb) {
1434a58aedfSRichard Henderson         if (exp_low == 0x7f) {
1444a58aedfSRichard Henderson             exp = 0x7ff;
1454a58aedfSRichard Henderson         }
1464a58aedfSRichard Henderson     } else {
1474a58aedfSRichard Henderson         if (exp_low != 0x00) {
1484a58aedfSRichard Henderson             exp |= 0x380;
1494a58aedfSRichard Henderson         }
1504a58aedfSRichard Henderson     }
1514a58aedfSRichard Henderson 
1524a58aedfSRichard Henderson     return (((uint64_t)sign << 63)
1534a58aedfSRichard Henderson             | ((uint64_t)exp << 52)
1544a58aedfSRichard Henderson             | ((uint64_t)frac << 29));
1554a58aedfSRichard Henderson }
1564a58aedfSRichard Henderson 
1574a58aedfSRichard Henderson static inline uint64_t float32_to_s(float32 fa)
1584a58aedfSRichard Henderson {
1594a58aedfSRichard Henderson     CPU_FloatU a;
1604a58aedfSRichard Henderson     a.f = fa;
1614a58aedfSRichard Henderson     return float32_to_s_int(a.l);
1624a58aedfSRichard Henderson }
1634a58aedfSRichard Henderson 
1644a58aedfSRichard Henderson static inline uint32_t s_to_float32_int(uint64_t a)
1654a58aedfSRichard Henderson {
1664a58aedfSRichard Henderson     return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
1674a58aedfSRichard Henderson }
1684a58aedfSRichard Henderson 
1694a58aedfSRichard Henderson static inline float32 s_to_float32(uint64_t a)
1704a58aedfSRichard Henderson {
1714a58aedfSRichard Henderson     CPU_FloatU r;
1724a58aedfSRichard Henderson     r.l = s_to_float32_int(a);
1734a58aedfSRichard Henderson     return r.f;
1744a58aedfSRichard Henderson }
1754a58aedfSRichard Henderson 
1764a58aedfSRichard Henderson uint32_t helper_s_to_memory(uint64_t a)
1774a58aedfSRichard Henderson {
1784a58aedfSRichard Henderson     return s_to_float32_int(a);
1794a58aedfSRichard Henderson }
1804a58aedfSRichard Henderson 
1814a58aedfSRichard Henderson uint64_t helper_memory_to_s(uint32_t a)
1824a58aedfSRichard Henderson {
1834a58aedfSRichard Henderson     return float32_to_s_int(a);
1844a58aedfSRichard Henderson }
1854a58aedfSRichard Henderson 
1864a58aedfSRichard Henderson uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
1874a58aedfSRichard Henderson {
1884a58aedfSRichard Henderson     float32 fa, fb, fr;
1894a58aedfSRichard Henderson 
1904a58aedfSRichard Henderson     fa = s_to_float32(a);
1914a58aedfSRichard Henderson     fb = s_to_float32(b);
1924a58aedfSRichard Henderson     fr = float32_add(fa, fb, &FP_STATUS);
1934a58aedfSRichard Henderson     return float32_to_s(fr);
1944a58aedfSRichard Henderson }
1954a58aedfSRichard Henderson 
1964a58aedfSRichard Henderson uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
1974a58aedfSRichard Henderson {
1984a58aedfSRichard Henderson     float32 fa, fb, fr;
1994a58aedfSRichard Henderson 
2004a58aedfSRichard Henderson     fa = s_to_float32(a);
2014a58aedfSRichard Henderson     fb = s_to_float32(b);
2024a58aedfSRichard Henderson     fr = float32_sub(fa, fb, &FP_STATUS);
2034a58aedfSRichard Henderson     return float32_to_s(fr);
2044a58aedfSRichard Henderson }
2054a58aedfSRichard Henderson 
2064a58aedfSRichard Henderson uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
2074a58aedfSRichard Henderson {
2084a58aedfSRichard Henderson     float32 fa, fb, fr;
2094a58aedfSRichard Henderson 
2104a58aedfSRichard Henderson     fa = s_to_float32(a);
2114a58aedfSRichard Henderson     fb = s_to_float32(b);
2124a58aedfSRichard Henderson     fr = float32_mul(fa, fb, &FP_STATUS);
2134a58aedfSRichard Henderson     return float32_to_s(fr);
2144a58aedfSRichard Henderson }
2154a58aedfSRichard Henderson 
2164a58aedfSRichard Henderson uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
2174a58aedfSRichard Henderson {
2184a58aedfSRichard Henderson     float32 fa, fb, fr;
2194a58aedfSRichard Henderson 
2204a58aedfSRichard Henderson     fa = s_to_float32(a);
2214a58aedfSRichard Henderson     fb = s_to_float32(b);
2224a58aedfSRichard Henderson     fr = float32_div(fa, fb, &FP_STATUS);
2234a58aedfSRichard Henderson     return float32_to_s(fr);
2244a58aedfSRichard Henderson }
2254a58aedfSRichard Henderson 
2264a58aedfSRichard Henderson uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
2274a58aedfSRichard Henderson {
2284a58aedfSRichard Henderson     float32 fa, fr;
2294a58aedfSRichard Henderson 
2304a58aedfSRichard Henderson     fa = s_to_float32(a);
2314a58aedfSRichard Henderson     fr = float32_sqrt(fa, &FP_STATUS);
2324a58aedfSRichard Henderson     return float32_to_s(fr);
2334a58aedfSRichard Henderson }
2344a58aedfSRichard Henderson 
2354a58aedfSRichard Henderson 
2364a58aedfSRichard Henderson /* T floating (double) */
2374a58aedfSRichard Henderson static inline float64 t_to_float64(uint64_t a)
2384a58aedfSRichard Henderson {
2394a58aedfSRichard Henderson     /* Memory format is the same as float64 */
2404a58aedfSRichard Henderson     CPU_DoubleU r;
2414a58aedfSRichard Henderson     r.ll = a;
2424a58aedfSRichard Henderson     return r.d;
2434a58aedfSRichard Henderson }
2444a58aedfSRichard Henderson 
2454a58aedfSRichard Henderson static inline uint64_t float64_to_t(float64 fa)
2464a58aedfSRichard Henderson {
2474a58aedfSRichard Henderson     /* Memory format is the same as float64 */
2484a58aedfSRichard Henderson     CPU_DoubleU r;
2494a58aedfSRichard Henderson     r.d = fa;
2504a58aedfSRichard Henderson     return r.ll;
2514a58aedfSRichard Henderson }
2524a58aedfSRichard Henderson 
2534a58aedfSRichard Henderson uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
2544a58aedfSRichard Henderson {
2554a58aedfSRichard Henderson     float64 fa, fb, fr;
2564a58aedfSRichard Henderson 
2574a58aedfSRichard Henderson     fa = t_to_float64(a);
2584a58aedfSRichard Henderson     fb = t_to_float64(b);
2594a58aedfSRichard Henderson     fr = float64_add(fa, fb, &FP_STATUS);
2604a58aedfSRichard Henderson     return float64_to_t(fr);
2614a58aedfSRichard Henderson }
2624a58aedfSRichard Henderson 
2634a58aedfSRichard Henderson uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
2644a58aedfSRichard Henderson {
2654a58aedfSRichard Henderson     float64 fa, fb, fr;
2664a58aedfSRichard Henderson 
2674a58aedfSRichard Henderson     fa = t_to_float64(a);
2684a58aedfSRichard Henderson     fb = t_to_float64(b);
2694a58aedfSRichard Henderson     fr = float64_sub(fa, fb, &FP_STATUS);
2704a58aedfSRichard Henderson     return float64_to_t(fr);
2714a58aedfSRichard Henderson }
2724a58aedfSRichard Henderson 
2734a58aedfSRichard Henderson uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
2744a58aedfSRichard Henderson {
2754a58aedfSRichard Henderson     float64 fa, fb, fr;
2764a58aedfSRichard Henderson 
2774a58aedfSRichard Henderson     fa = t_to_float64(a);
2784a58aedfSRichard Henderson     fb = t_to_float64(b);
2794a58aedfSRichard Henderson     fr = float64_mul(fa, fb, &FP_STATUS);
2804a58aedfSRichard Henderson     return float64_to_t(fr);
2814a58aedfSRichard Henderson }
2824a58aedfSRichard Henderson 
2834a58aedfSRichard Henderson uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
2844a58aedfSRichard Henderson {
2854a58aedfSRichard Henderson     float64 fa, fb, fr;
2864a58aedfSRichard Henderson 
2874a58aedfSRichard Henderson     fa = t_to_float64(a);
2884a58aedfSRichard Henderson     fb = t_to_float64(b);
2894a58aedfSRichard Henderson     fr = float64_div(fa, fb, &FP_STATUS);
2904a58aedfSRichard Henderson     return float64_to_t(fr);
2914a58aedfSRichard Henderson }
2924a58aedfSRichard Henderson 
2934a58aedfSRichard Henderson uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
2944a58aedfSRichard Henderson {
2954a58aedfSRichard Henderson     float64 fa, fr;
2964a58aedfSRichard Henderson 
2974a58aedfSRichard Henderson     fa = t_to_float64(a);
2984a58aedfSRichard Henderson     fr = float64_sqrt(fa, &FP_STATUS);
2994a58aedfSRichard Henderson     return float64_to_t(fr);
3004a58aedfSRichard Henderson }
3014a58aedfSRichard Henderson 
3024a58aedfSRichard Henderson /* Comparisons */
3034a58aedfSRichard Henderson uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
3044a58aedfSRichard Henderson {
3054a58aedfSRichard Henderson     float64 fa, fb;
3064a58aedfSRichard Henderson 
3074a58aedfSRichard Henderson     fa = t_to_float64(a);
3084a58aedfSRichard Henderson     fb = t_to_float64(b);
3094a58aedfSRichard Henderson 
3104a58aedfSRichard Henderson     if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
3114a58aedfSRichard Henderson         return 0x4000000000000000ULL;
3124a58aedfSRichard Henderson     } else {
3134a58aedfSRichard Henderson         return 0;
3144a58aedfSRichard Henderson     }
3154a58aedfSRichard Henderson }
3164a58aedfSRichard Henderson 
3174a58aedfSRichard Henderson uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
3184a58aedfSRichard Henderson {
3194a58aedfSRichard Henderson     float64 fa, fb;
3204a58aedfSRichard Henderson 
3214a58aedfSRichard Henderson     fa = t_to_float64(a);
3224a58aedfSRichard Henderson     fb = t_to_float64(b);
3234a58aedfSRichard Henderson 
3244a58aedfSRichard Henderson     if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
3254a58aedfSRichard Henderson         return 0x4000000000000000ULL;
3264a58aedfSRichard Henderson     } else {
3274a58aedfSRichard Henderson         return 0;
3284a58aedfSRichard Henderson     }
3294a58aedfSRichard Henderson }
3304a58aedfSRichard Henderson 
3314a58aedfSRichard Henderson uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
3324a58aedfSRichard Henderson {
3334a58aedfSRichard Henderson     float64 fa, fb;
3344a58aedfSRichard Henderson 
3354a58aedfSRichard Henderson     fa = t_to_float64(a);
3364a58aedfSRichard Henderson     fb = t_to_float64(b);
3374a58aedfSRichard Henderson 
3384a58aedfSRichard Henderson     if (float64_le(fa, fb, &FP_STATUS)) {
3394a58aedfSRichard Henderson         return 0x4000000000000000ULL;
3404a58aedfSRichard Henderson     } else {
3414a58aedfSRichard Henderson         return 0;
3424a58aedfSRichard Henderson     }
3434a58aedfSRichard Henderson }
3444a58aedfSRichard Henderson 
3454a58aedfSRichard Henderson uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
3464a58aedfSRichard Henderson {
3474a58aedfSRichard Henderson     float64 fa, fb;
3484a58aedfSRichard Henderson 
3494a58aedfSRichard Henderson     fa = t_to_float64(a);
3504a58aedfSRichard Henderson     fb = t_to_float64(b);
3514a58aedfSRichard Henderson 
3524a58aedfSRichard Henderson     if (float64_lt(fa, fb, &FP_STATUS)) {
3534a58aedfSRichard Henderson         return 0x4000000000000000ULL;
3544a58aedfSRichard Henderson     } else {
3554a58aedfSRichard Henderson         return 0;
3564a58aedfSRichard Henderson     }
3574a58aedfSRichard Henderson }
3584a58aedfSRichard Henderson 
3594a58aedfSRichard Henderson /* Floating point format conversion */
3604a58aedfSRichard Henderson uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
3614a58aedfSRichard Henderson {
3624a58aedfSRichard Henderson     float64 fa;
3634a58aedfSRichard Henderson     float32 fr;
3644a58aedfSRichard Henderson 
3654a58aedfSRichard Henderson     fa = t_to_float64(a);
3664a58aedfSRichard Henderson     fr = float64_to_float32(fa, &FP_STATUS);
3674a58aedfSRichard Henderson     return float32_to_s(fr);
3684a58aedfSRichard Henderson }
3694a58aedfSRichard Henderson 
3704a58aedfSRichard Henderson uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
3714a58aedfSRichard Henderson {
3724a58aedfSRichard Henderson     float32 fa;
3734a58aedfSRichard Henderson     float64 fr;
3744a58aedfSRichard Henderson 
3754a58aedfSRichard Henderson     fa = s_to_float32(a);
3764a58aedfSRichard Henderson     fr = float32_to_float64(fa, &FP_STATUS);
3774a58aedfSRichard Henderson     return float64_to_t(fr);
3784a58aedfSRichard Henderson }
3794a58aedfSRichard Henderson 
3804a58aedfSRichard Henderson uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
3814a58aedfSRichard Henderson {
3824a58aedfSRichard Henderson     float32 fr = int64_to_float32(a, &FP_STATUS);
3834a58aedfSRichard Henderson     return float32_to_s(fr);
3844a58aedfSRichard Henderson }
3854a58aedfSRichard Henderson 
3864a58aedfSRichard Henderson /* Implement float64 to uint64 conversion without saturation -- we must
3874a58aedfSRichard Henderson    supply the truncated result.  This behaviour is used by the compiler
3884a58aedfSRichard Henderson    to get unsigned conversion for free with the same instruction.
3894a58aedfSRichard Henderson 
3904a58aedfSRichard Henderson    The VI flag is set when overflow or inexact exceptions should be raised.  */
3914a58aedfSRichard Henderson 
3924a58aedfSRichard Henderson static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
3934a58aedfSRichard Henderson                                     int roundmode, int VI)
3944a58aedfSRichard Henderson {
3954a58aedfSRichard Henderson     uint64_t frac, ret = 0;
3964a58aedfSRichard Henderson     uint32_t exp, sign, exc = 0;
3974a58aedfSRichard Henderson     int shift;
3984a58aedfSRichard Henderson 
3994a58aedfSRichard Henderson     sign = (a >> 63);
4004a58aedfSRichard Henderson     exp = (uint32_t)(a >> 52) & 0x7ff;
4014a58aedfSRichard Henderson     frac = a & 0xfffffffffffffull;
4024a58aedfSRichard Henderson 
4034a58aedfSRichard Henderson     if (exp == 0) {
4044a58aedfSRichard Henderson         if (unlikely(frac != 0)) {
4054a58aedfSRichard Henderson             goto do_underflow;
4064a58aedfSRichard Henderson         }
4074a58aedfSRichard Henderson     } else if (exp == 0x7ff) {
4084a58aedfSRichard Henderson         exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0);
4094a58aedfSRichard Henderson     } else {
4104a58aedfSRichard Henderson         /* Restore implicit bit.  */
4114a58aedfSRichard Henderson         frac |= 0x10000000000000ull;
4124a58aedfSRichard Henderson 
4134a58aedfSRichard Henderson         shift = exp - 1023 - 52;
4144a58aedfSRichard Henderson         if (shift >= 0) {
4154a58aedfSRichard Henderson             /* In this case the number is so large that we must shift
4164a58aedfSRichard Henderson                the fraction left.  There is no rounding to do.  */
4174a58aedfSRichard Henderson             if (shift < 63) {
4184a58aedfSRichard Henderson                 ret = frac << shift;
4194a58aedfSRichard Henderson                 if (VI && (ret >> shift) != frac) {
4204a58aedfSRichard Henderson                     exc = float_flag_overflow;
4214a58aedfSRichard Henderson                 }
4224a58aedfSRichard Henderson             }
4234a58aedfSRichard Henderson         } else {
4244a58aedfSRichard Henderson             uint64_t round;
4254a58aedfSRichard Henderson 
4264a58aedfSRichard Henderson             /* In this case the number is smaller than the fraction as
4274a58aedfSRichard Henderson                represented by the 52 bit number.  Here we must think
4284a58aedfSRichard Henderson                about rounding the result.  Handle this by shifting the
4294a58aedfSRichard Henderson                fractional part of the number into the high bits of ROUND.
4304a58aedfSRichard Henderson                This will let us efficiently handle round-to-nearest.  */
4314a58aedfSRichard Henderson             shift = -shift;
4324a58aedfSRichard Henderson             if (shift < 63) {
4334a58aedfSRichard Henderson                 ret = frac >> shift;
4344a58aedfSRichard Henderson                 round = frac << (64 - shift);
4354a58aedfSRichard Henderson             } else {
4364a58aedfSRichard Henderson                 /* The exponent is so small we shift out everything.
4374a58aedfSRichard Henderson                    Leave a sticky bit for proper rounding below.  */
4384a58aedfSRichard Henderson             do_underflow:
4394a58aedfSRichard Henderson                 round = 1;
4404a58aedfSRichard Henderson             }
4414a58aedfSRichard Henderson 
4424a58aedfSRichard Henderson             if (round) {
4434a58aedfSRichard Henderson                 exc = (VI ? float_flag_inexact : 0);
4444a58aedfSRichard Henderson                 switch (roundmode) {
4454a58aedfSRichard Henderson                 case float_round_nearest_even:
4464a58aedfSRichard Henderson                     if (round == (1ull << 63)) {
4474a58aedfSRichard Henderson                         /* Fraction is exactly 0.5; round to even.  */
4484a58aedfSRichard Henderson                         ret += (ret & 1);
4494a58aedfSRichard Henderson                     } else if (round > (1ull << 63)) {
4504a58aedfSRichard Henderson                         ret += 1;
4514a58aedfSRichard Henderson                     }
4524a58aedfSRichard Henderson                     break;
4534a58aedfSRichard Henderson                 case float_round_to_zero:
4544a58aedfSRichard Henderson                     break;
4554a58aedfSRichard Henderson                 case float_round_up:
4564a58aedfSRichard Henderson                     ret += 1 - sign;
4574a58aedfSRichard Henderson                     break;
4584a58aedfSRichard Henderson                 case float_round_down:
4594a58aedfSRichard Henderson                     ret += sign;
4604a58aedfSRichard Henderson                     break;
4614a58aedfSRichard Henderson                 }
4624a58aedfSRichard Henderson             }
4634a58aedfSRichard Henderson         }
4644a58aedfSRichard Henderson         if (sign) {
4654a58aedfSRichard Henderson             ret = -ret;
4664a58aedfSRichard Henderson         }
4674a58aedfSRichard Henderson     }
4684a58aedfSRichard Henderson     if (unlikely(exc)) {
4694a58aedfSRichard Henderson         float_raise(exc, &FP_STATUS);
4704a58aedfSRichard Henderson     }
4714a58aedfSRichard Henderson 
4724a58aedfSRichard Henderson     return ret;
4734a58aedfSRichard Henderson }
4744a58aedfSRichard Henderson 
4754a58aedfSRichard Henderson uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
4764a58aedfSRichard Henderson {
4774a58aedfSRichard Henderson     return inline_cvttq(env, a, FP_STATUS.float_rounding_mode, 1);
4784a58aedfSRichard Henderson }
4794a58aedfSRichard Henderson 
4804a58aedfSRichard Henderson uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
4814a58aedfSRichard Henderson {
4824a58aedfSRichard Henderson     return inline_cvttq(env, a, float_round_to_zero, 0);
4834a58aedfSRichard Henderson }
4844a58aedfSRichard Henderson 
4854a58aedfSRichard Henderson uint64_t helper_cvttq_svic(CPUAlphaState *env, uint64_t a)
4864a58aedfSRichard Henderson {
4874a58aedfSRichard Henderson     return inline_cvttq(env, a, float_round_to_zero, 1);
4884a58aedfSRichard Henderson }
4894a58aedfSRichard Henderson 
4904a58aedfSRichard Henderson uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
4914a58aedfSRichard Henderson {
4924a58aedfSRichard Henderson     float64 fr = int64_to_float64(a, &FP_STATUS);
4934a58aedfSRichard Henderson     return float64_to_t(fr);
4944a58aedfSRichard Henderson }
4954a58aedfSRichard Henderson 
4963da653faSRichard Henderson void helper_cvtql_v_input(CPUAlphaState *env, uint64_t val)
497e8d8fef4SRichard Henderson {
498e8d8fef4SRichard Henderson     if (val != (int32_t)val) {
499e8d8fef4SRichard Henderson         arith_excp(env, GETPC(), EXC_M_IOV, 0);
500e8d8fef4SRichard Henderson     }
501e8d8fef4SRichard Henderson }
502