xref: /qemu/target/alpha/fpu_helper.c (revision c24a8a0b6dad5a33d84f5fb846edb28c43312c71)
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 
37f3d3aad4SRichard Henderson #define CONVERT_BIT(X, SRC, DST) \
38f3d3aad4SRichard Henderson     (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
39f3d3aad4SRichard Henderson 
40f3d3aad4SRichard Henderson static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
414a58aedfSRichard Henderson {
42f3d3aad4SRichard Henderson     uint8_t exc = get_float_exception_flags(&FP_STATUS);
43f3d3aad4SRichard Henderson     uint32_t ret = 0;
44f3d3aad4SRichard Henderson 
45f3d3aad4SRichard Henderson     if (unlikely(exc)) {
464a58aedfSRichard Henderson         set_float_exception_flags(0, &FP_STATUS);
47f3d3aad4SRichard Henderson         ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV);
48f3d3aad4SRichard Henderson         ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE);
49f3d3aad4SRichard Henderson         ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF);
50f3d3aad4SRichard Henderson         ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF);
51f3d3aad4SRichard Henderson         ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE);
524a58aedfSRichard Henderson     }
534a58aedfSRichard Henderson 
54f3d3aad4SRichard Henderson     return ret;
554a58aedfSRichard Henderson }
564a58aedfSRichard Henderson 
57f3d3aad4SRichard Henderson static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
58f6b6b7b8SRichard Henderson                           uint32_t exc, uint32_t regno, uint32_t hw_exc)
594a58aedfSRichard Henderson {
60f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
61f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
62f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
63f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
64f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
65f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
664a58aedfSRichard Henderson 
674a58aedfSRichard Henderson     arith_excp(env, retaddr, hw_exc, 1ull << regno);
684a58aedfSRichard Henderson }
694a58aedfSRichard Henderson 
704a58aedfSRichard Henderson /* Raise exceptions for ieee fp insns without software completion.
714a58aedfSRichard Henderson    In that case there are no exceptions that don't trap; the mask
724a58aedfSRichard Henderson    doesn't apply.  */
73f3d3aad4SRichard Henderson void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
744a58aedfSRichard Henderson {
75471d4930SRichard Henderson     uint32_t exc = env->error_code;
76471d4930SRichard Henderson     if (exc) {
77471d4930SRichard Henderson         env->fpcr |= exc;
78471d4930SRichard Henderson         exc &= ~ignore;
79471d4930SRichard Henderson         if (exc) {
80f6b6b7b8SRichard Henderson             fp_exc_raise1(env, GETPC(), exc, regno, 0);
814a58aedfSRichard Henderson         }
82471d4930SRichard Henderson     }
83471d4930SRichard Henderson }
844a58aedfSRichard Henderson 
854a58aedfSRichard Henderson /* Raise exceptions for ieee fp insns with software completion.  */
86f3d3aad4SRichard Henderson void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
874a58aedfSRichard Henderson {
88f3d3aad4SRichard Henderson     uint32_t exc = env->error_code & ~ignore;
894a58aedfSRichard Henderson     if (exc) {
90f3d3aad4SRichard Henderson         env->fpcr |= exc;
91471d4930SRichard Henderson         exc &= ~ignore;
92471d4930SRichard Henderson         if (exc) {
93f3d3aad4SRichard Henderson             exc &= env->fpcr_exc_enable;
94f6b6b7b8SRichard Henderson             fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
954a58aedfSRichard Henderson         }
964a58aedfSRichard Henderson     }
97471d4930SRichard Henderson }
984a58aedfSRichard Henderson 
9974343409SRichard Henderson /* Input handing without software completion.  Trap for all
10074343409SRichard Henderson    non-finite numbers.  */
10174343409SRichard Henderson void helper_ieee_input(CPUAlphaState *env, uint64_t val)
1024a58aedfSRichard Henderson {
1034a58aedfSRichard Henderson     uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
1044a58aedfSRichard Henderson     uint64_t frac = val & 0xfffffffffffffull;
1054a58aedfSRichard Henderson 
1064a58aedfSRichard Henderson     if (exp == 0) {
10774343409SRichard Henderson         /* Denormals without DNZ set raise an exception.  */
10874343409SRichard Henderson         if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
1094a58aedfSRichard Henderson             arith_excp(env, GETPC(), EXC_M_UNF, 0);
1104a58aedfSRichard Henderson         }
1114a58aedfSRichard Henderson     } else if (exp == 0x7ff) {
1124a58aedfSRichard Henderson         /* Infinity or NaN.  */
1134a58aedfSRichard Henderson         /* ??? I'm not sure these exception bit flags are correct.  I do
1144a58aedfSRichard Henderson            know that the Linux kernel, at least, doesn't rely on them and
1154a58aedfSRichard Henderson            just emulates the insn to figure out what exception to use.  */
1164a58aedfSRichard Henderson         arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
1174a58aedfSRichard Henderson     }
1184a58aedfSRichard Henderson }
1194a58aedfSRichard Henderson 
1204a58aedfSRichard Henderson /* Similar, but does not trap for infinities.  Used for comparisons.  */
12174343409SRichard Henderson void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
1224a58aedfSRichard Henderson {
1234a58aedfSRichard Henderson     uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
1244a58aedfSRichard Henderson     uint64_t frac = val & 0xfffffffffffffull;
1254a58aedfSRichard Henderson 
1264a58aedfSRichard Henderson     if (exp == 0) {
12774343409SRichard Henderson         /* Denormals without DNZ set raise an exception.  */
12874343409SRichard Henderson         if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
1294a58aedfSRichard Henderson             arith_excp(env, GETPC(), EXC_M_UNF, 0);
1304a58aedfSRichard Henderson         }
1314a58aedfSRichard Henderson     } else if (exp == 0x7ff && frac) {
1324a58aedfSRichard Henderson         /* NaN.  */
1334a58aedfSRichard Henderson         arith_excp(env, GETPC(), EXC_M_INV, 0);
1344a58aedfSRichard Henderson     }
1354a58aedfSRichard Henderson }
1364a58aedfSRichard Henderson 
1374a58aedfSRichard Henderson 
1384a58aedfSRichard Henderson /* S floating (single) */
1394a58aedfSRichard Henderson 
1404a58aedfSRichard Henderson /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg.  */
1414a58aedfSRichard Henderson static inline uint64_t float32_to_s_int(uint32_t fi)
1424a58aedfSRichard Henderson {
1434a58aedfSRichard Henderson     uint32_t frac = fi & 0x7fffff;
1444a58aedfSRichard Henderson     uint32_t sign = fi >> 31;
1454a58aedfSRichard Henderson     uint32_t exp_msb = (fi >> 30) & 1;
1464a58aedfSRichard Henderson     uint32_t exp_low = (fi >> 23) & 0x7f;
1474a58aedfSRichard Henderson     uint32_t exp;
1484a58aedfSRichard Henderson 
1494a58aedfSRichard Henderson     exp = (exp_msb << 10) | exp_low;
1504a58aedfSRichard Henderson     if (exp_msb) {
1514a58aedfSRichard Henderson         if (exp_low == 0x7f) {
1524a58aedfSRichard Henderson             exp = 0x7ff;
1534a58aedfSRichard Henderson         }
1544a58aedfSRichard Henderson     } else {
1554a58aedfSRichard Henderson         if (exp_low != 0x00) {
1564a58aedfSRichard Henderson             exp |= 0x380;
1574a58aedfSRichard Henderson         }
1584a58aedfSRichard Henderson     }
1594a58aedfSRichard Henderson 
1604a58aedfSRichard Henderson     return (((uint64_t)sign << 63)
1614a58aedfSRichard Henderson             | ((uint64_t)exp << 52)
1624a58aedfSRichard Henderson             | ((uint64_t)frac << 29));
1634a58aedfSRichard Henderson }
1644a58aedfSRichard Henderson 
1654a58aedfSRichard Henderson static inline uint64_t float32_to_s(float32 fa)
1664a58aedfSRichard Henderson {
1674a58aedfSRichard Henderson     CPU_FloatU a;
1684a58aedfSRichard Henderson     a.f = fa;
1694a58aedfSRichard Henderson     return float32_to_s_int(a.l);
1704a58aedfSRichard Henderson }
1714a58aedfSRichard Henderson 
1724a58aedfSRichard Henderson static inline uint32_t s_to_float32_int(uint64_t a)
1734a58aedfSRichard Henderson {
1744a58aedfSRichard Henderson     return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
1754a58aedfSRichard Henderson }
1764a58aedfSRichard Henderson 
1774a58aedfSRichard Henderson static inline float32 s_to_float32(uint64_t a)
1784a58aedfSRichard Henderson {
1794a58aedfSRichard Henderson     CPU_FloatU r;
1804a58aedfSRichard Henderson     r.l = s_to_float32_int(a);
1814a58aedfSRichard Henderson     return r.f;
1824a58aedfSRichard Henderson }
1834a58aedfSRichard Henderson 
1844a58aedfSRichard Henderson uint32_t helper_s_to_memory(uint64_t a)
1854a58aedfSRichard Henderson {
1864a58aedfSRichard Henderson     return s_to_float32_int(a);
1874a58aedfSRichard Henderson }
1884a58aedfSRichard Henderson 
1894a58aedfSRichard Henderson uint64_t helper_memory_to_s(uint32_t a)
1904a58aedfSRichard Henderson {
1914a58aedfSRichard Henderson     return float32_to_s_int(a);
1924a58aedfSRichard Henderson }
1934a58aedfSRichard Henderson 
1944a58aedfSRichard Henderson uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
1954a58aedfSRichard Henderson {
1964a58aedfSRichard Henderson     float32 fa, fb, fr;
1974a58aedfSRichard Henderson 
1984a58aedfSRichard Henderson     fa = s_to_float32(a);
1994a58aedfSRichard Henderson     fb = s_to_float32(b);
2004a58aedfSRichard Henderson     fr = float32_add(fa, fb, &FP_STATUS);
201f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
202f3d3aad4SRichard Henderson 
2034a58aedfSRichard Henderson     return float32_to_s(fr);
2044a58aedfSRichard Henderson }
2054a58aedfSRichard Henderson 
2064a58aedfSRichard Henderson uint64_t helper_subs(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_sub(fa, fb, &FP_STATUS);
213f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
214f3d3aad4SRichard Henderson 
2154a58aedfSRichard Henderson     return float32_to_s(fr);
2164a58aedfSRichard Henderson }
2174a58aedfSRichard Henderson 
2184a58aedfSRichard Henderson uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
2194a58aedfSRichard Henderson {
2204a58aedfSRichard Henderson     float32 fa, fb, fr;
2214a58aedfSRichard Henderson 
2224a58aedfSRichard Henderson     fa = s_to_float32(a);
2234a58aedfSRichard Henderson     fb = s_to_float32(b);
2244a58aedfSRichard Henderson     fr = float32_mul(fa, fb, &FP_STATUS);
225f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
226f3d3aad4SRichard Henderson 
2274a58aedfSRichard Henderson     return float32_to_s(fr);
2284a58aedfSRichard Henderson }
2294a58aedfSRichard Henderson 
2304a58aedfSRichard Henderson uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
2314a58aedfSRichard Henderson {
2324a58aedfSRichard Henderson     float32 fa, fb, fr;
2334a58aedfSRichard Henderson 
2344a58aedfSRichard Henderson     fa = s_to_float32(a);
2354a58aedfSRichard Henderson     fb = s_to_float32(b);
2364a58aedfSRichard Henderson     fr = float32_div(fa, fb, &FP_STATUS);
237f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
238f3d3aad4SRichard Henderson 
2394a58aedfSRichard Henderson     return float32_to_s(fr);
2404a58aedfSRichard Henderson }
2414a58aedfSRichard Henderson 
2424a58aedfSRichard Henderson uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
2434a58aedfSRichard Henderson {
2444a58aedfSRichard Henderson     float32 fa, fr;
2454a58aedfSRichard Henderson 
2464a58aedfSRichard Henderson     fa = s_to_float32(a);
2474a58aedfSRichard Henderson     fr = float32_sqrt(fa, &FP_STATUS);
248f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
249f3d3aad4SRichard Henderson 
2504a58aedfSRichard Henderson     return float32_to_s(fr);
2514a58aedfSRichard Henderson }
2524a58aedfSRichard Henderson 
2534a58aedfSRichard Henderson 
2544a58aedfSRichard Henderson /* T floating (double) */
2554a58aedfSRichard Henderson static inline float64 t_to_float64(uint64_t a)
2564a58aedfSRichard Henderson {
2574a58aedfSRichard Henderson     /* Memory format is the same as float64 */
2584a58aedfSRichard Henderson     CPU_DoubleU r;
2594a58aedfSRichard Henderson     r.ll = a;
2604a58aedfSRichard Henderson     return r.d;
2614a58aedfSRichard Henderson }
2624a58aedfSRichard Henderson 
2634a58aedfSRichard Henderson static inline uint64_t float64_to_t(float64 fa)
2644a58aedfSRichard Henderson {
2654a58aedfSRichard Henderson     /* Memory format is the same as float64 */
2664a58aedfSRichard Henderson     CPU_DoubleU r;
2674a58aedfSRichard Henderson     r.d = fa;
2684a58aedfSRichard Henderson     return r.ll;
2694a58aedfSRichard Henderson }
2704a58aedfSRichard Henderson 
2714a58aedfSRichard Henderson uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
2724a58aedfSRichard Henderson {
2734a58aedfSRichard Henderson     float64 fa, fb, fr;
2744a58aedfSRichard Henderson 
2754a58aedfSRichard Henderson     fa = t_to_float64(a);
2764a58aedfSRichard Henderson     fb = t_to_float64(b);
2774a58aedfSRichard Henderson     fr = float64_add(fa, fb, &FP_STATUS);
278f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
279f3d3aad4SRichard Henderson 
2804a58aedfSRichard Henderson     return float64_to_t(fr);
2814a58aedfSRichard Henderson }
2824a58aedfSRichard Henderson 
2834a58aedfSRichard Henderson uint64_t helper_subt(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_sub(fa, fb, &FP_STATUS);
290f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
291f3d3aad4SRichard Henderson 
2924a58aedfSRichard Henderson     return float64_to_t(fr);
2934a58aedfSRichard Henderson }
2944a58aedfSRichard Henderson 
2954a58aedfSRichard Henderson uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
2964a58aedfSRichard Henderson {
2974a58aedfSRichard Henderson     float64 fa, fb, fr;
2984a58aedfSRichard Henderson 
2994a58aedfSRichard Henderson     fa = t_to_float64(a);
3004a58aedfSRichard Henderson     fb = t_to_float64(b);
3014a58aedfSRichard Henderson     fr = float64_mul(fa, fb, &FP_STATUS);
302f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
303f3d3aad4SRichard Henderson 
3044a58aedfSRichard Henderson     return float64_to_t(fr);
3054a58aedfSRichard Henderson }
3064a58aedfSRichard Henderson 
3074a58aedfSRichard Henderson uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
3084a58aedfSRichard Henderson {
3094a58aedfSRichard Henderson     float64 fa, fb, fr;
3104a58aedfSRichard Henderson 
3114a58aedfSRichard Henderson     fa = t_to_float64(a);
3124a58aedfSRichard Henderson     fb = t_to_float64(b);
3134a58aedfSRichard Henderson     fr = float64_div(fa, fb, &FP_STATUS);
314f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
315f3d3aad4SRichard Henderson 
3164a58aedfSRichard Henderson     return float64_to_t(fr);
3174a58aedfSRichard Henderson }
3184a58aedfSRichard Henderson 
3194a58aedfSRichard Henderson uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
3204a58aedfSRichard Henderson {
3214a58aedfSRichard Henderson     float64 fa, fr;
3224a58aedfSRichard Henderson 
3234a58aedfSRichard Henderson     fa = t_to_float64(a);
3244a58aedfSRichard Henderson     fr = float64_sqrt(fa, &FP_STATUS);
325f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
326f3d3aad4SRichard Henderson 
3274a58aedfSRichard Henderson     return float64_to_t(fr);
3284a58aedfSRichard Henderson }
3294a58aedfSRichard Henderson 
3304a58aedfSRichard Henderson /* Comparisons */
3314a58aedfSRichard Henderson uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
3324a58aedfSRichard Henderson {
3334a58aedfSRichard Henderson     float64 fa, fb;
334f3d3aad4SRichard Henderson     uint64_t ret = 0;
3354a58aedfSRichard Henderson 
3364a58aedfSRichard Henderson     fa = t_to_float64(a);
3374a58aedfSRichard Henderson     fb = t_to_float64(b);
3384a58aedfSRichard Henderson 
3394a58aedfSRichard Henderson     if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
340f3d3aad4SRichard Henderson         ret = 0x4000000000000000ULL;
3414a58aedfSRichard Henderson     }
342f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
343f3d3aad4SRichard Henderson 
344f3d3aad4SRichard Henderson     return ret;
3454a58aedfSRichard Henderson }
3464a58aedfSRichard Henderson 
3474a58aedfSRichard Henderson uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
3484a58aedfSRichard Henderson {
3494a58aedfSRichard Henderson     float64 fa, fb;
350f3d3aad4SRichard Henderson     uint64_t ret = 0;
3514a58aedfSRichard Henderson 
3524a58aedfSRichard Henderson     fa = t_to_float64(a);
3534a58aedfSRichard Henderson     fb = t_to_float64(b);
3544a58aedfSRichard Henderson 
3554a58aedfSRichard Henderson     if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
356f3d3aad4SRichard Henderson         ret = 0x4000000000000000ULL;
3574a58aedfSRichard Henderson     }
358f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
359f3d3aad4SRichard Henderson 
360f3d3aad4SRichard Henderson     return ret;
3614a58aedfSRichard Henderson }
3624a58aedfSRichard Henderson 
3634a58aedfSRichard Henderson uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
3644a58aedfSRichard Henderson {
3654a58aedfSRichard Henderson     float64 fa, fb;
366f3d3aad4SRichard Henderson     uint64_t ret = 0;
3674a58aedfSRichard Henderson 
3684a58aedfSRichard Henderson     fa = t_to_float64(a);
3694a58aedfSRichard Henderson     fb = t_to_float64(b);
3704a58aedfSRichard Henderson 
3714a58aedfSRichard Henderson     if (float64_le(fa, fb, &FP_STATUS)) {
372f3d3aad4SRichard Henderson         ret = 0x4000000000000000ULL;
3734a58aedfSRichard Henderson     }
374f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
375f3d3aad4SRichard Henderson 
376f3d3aad4SRichard Henderson     return ret;
3774a58aedfSRichard Henderson }
3784a58aedfSRichard Henderson 
3794a58aedfSRichard Henderson uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
3804a58aedfSRichard Henderson {
3814a58aedfSRichard Henderson     float64 fa, fb;
382f3d3aad4SRichard Henderson     uint64_t ret = 0;
3834a58aedfSRichard Henderson 
3844a58aedfSRichard Henderson     fa = t_to_float64(a);
3854a58aedfSRichard Henderson     fb = t_to_float64(b);
3864a58aedfSRichard Henderson 
3874a58aedfSRichard Henderson     if (float64_lt(fa, fb, &FP_STATUS)) {
388f3d3aad4SRichard Henderson         ret = 0x4000000000000000ULL;
3894a58aedfSRichard Henderson     }
390f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
391f3d3aad4SRichard Henderson 
392f3d3aad4SRichard Henderson     return ret;
3934a58aedfSRichard Henderson }
3944a58aedfSRichard Henderson 
3954a58aedfSRichard Henderson /* Floating point format conversion */
3964a58aedfSRichard Henderson uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
3974a58aedfSRichard Henderson {
3984a58aedfSRichard Henderson     float64 fa;
3994a58aedfSRichard Henderson     float32 fr;
4004a58aedfSRichard Henderson 
4014a58aedfSRichard Henderson     fa = t_to_float64(a);
4024a58aedfSRichard Henderson     fr = float64_to_float32(fa, &FP_STATUS);
403f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
404f3d3aad4SRichard Henderson 
4054a58aedfSRichard Henderson     return float32_to_s(fr);
4064a58aedfSRichard Henderson }
4074a58aedfSRichard Henderson 
4084a58aedfSRichard Henderson uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
4094a58aedfSRichard Henderson {
4104a58aedfSRichard Henderson     float32 fa;
4114a58aedfSRichard Henderson     float64 fr;
4124a58aedfSRichard Henderson 
4134a58aedfSRichard Henderson     fa = s_to_float32(a);
4144a58aedfSRichard Henderson     fr = float32_to_float64(fa, &FP_STATUS);
415f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
416f3d3aad4SRichard Henderson 
4174a58aedfSRichard Henderson     return float64_to_t(fr);
4184a58aedfSRichard Henderson }
4194a58aedfSRichard Henderson 
4204a58aedfSRichard Henderson uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
4214a58aedfSRichard Henderson {
4224a58aedfSRichard Henderson     float32 fr = int64_to_float32(a, &FP_STATUS);
423f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
424f3d3aad4SRichard Henderson 
4254a58aedfSRichard Henderson     return float32_to_s(fr);
4264a58aedfSRichard Henderson }
4274a58aedfSRichard Henderson 
4284a58aedfSRichard Henderson /* Implement float64 to uint64 conversion without saturation -- we must
4294a58aedfSRichard Henderson    supply the truncated result.  This behaviour is used by the compiler
430c24a8a0bSRichard Henderson    to get unsigned conversion for free with the same instruction.  */
4314a58aedfSRichard Henderson 
432c24a8a0bSRichard Henderson static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode)
4334a58aedfSRichard Henderson {
4344a58aedfSRichard Henderson     uint64_t frac, ret = 0;
4354a58aedfSRichard Henderson     uint32_t exp, sign, exc = 0;
4364a58aedfSRichard Henderson     int shift;
4374a58aedfSRichard Henderson 
4384a58aedfSRichard Henderson     sign = (a >> 63);
4394a58aedfSRichard Henderson     exp = (uint32_t)(a >> 52) & 0x7ff;
4404a58aedfSRichard Henderson     frac = a & 0xfffffffffffffull;
4414a58aedfSRichard Henderson 
4424a58aedfSRichard Henderson     if (exp == 0) {
4434a58aedfSRichard Henderson         if (unlikely(frac != 0)) {
4444a58aedfSRichard Henderson             goto do_underflow;
4454a58aedfSRichard Henderson         }
4464a58aedfSRichard Henderson     } else if (exp == 0x7ff) {
447c24a8a0bSRichard Henderson         exc = (frac ? FPCR_INV : FPCR_IOV | FPCR_INE);
4484a58aedfSRichard Henderson     } else {
4494a58aedfSRichard Henderson         /* Restore implicit bit.  */
4504a58aedfSRichard Henderson         frac |= 0x10000000000000ull;
4514a58aedfSRichard Henderson 
4524a58aedfSRichard Henderson         shift = exp - 1023 - 52;
4534a58aedfSRichard Henderson         if (shift >= 0) {
4544a58aedfSRichard Henderson             /* In this case the number is so large that we must shift
4554a58aedfSRichard Henderson                the fraction left.  There is no rounding to do.  */
456c24a8a0bSRichard Henderson             exc = FPCR_IOV | FPCR_INE;
4574a58aedfSRichard Henderson             if (shift < 63) {
4584a58aedfSRichard Henderson                 ret = frac << shift;
459c24a8a0bSRichard Henderson                 if ((ret >> shift) == frac) {
460c24a8a0bSRichard Henderson                     exc = 0;
4614a58aedfSRichard Henderson                 }
4624a58aedfSRichard Henderson             }
4634a58aedfSRichard Henderson         } else {
4644a58aedfSRichard Henderson             uint64_t round;
4654a58aedfSRichard Henderson 
4664a58aedfSRichard Henderson             /* In this case the number is smaller than the fraction as
4674a58aedfSRichard Henderson                represented by the 52 bit number.  Here we must think
4684a58aedfSRichard Henderson                about rounding the result.  Handle this by shifting the
4694a58aedfSRichard Henderson                fractional part of the number into the high bits of ROUND.
4704a58aedfSRichard Henderson                This will let us efficiently handle round-to-nearest.  */
4714a58aedfSRichard Henderson             shift = -shift;
4724a58aedfSRichard Henderson             if (shift < 63) {
4734a58aedfSRichard Henderson                 ret = frac >> shift;
4744a58aedfSRichard Henderson                 round = frac << (64 - shift);
4754a58aedfSRichard Henderson             } else {
4764a58aedfSRichard Henderson                 /* The exponent is so small we shift out everything.
4774a58aedfSRichard Henderson                    Leave a sticky bit for proper rounding below.  */
4784a58aedfSRichard Henderson             do_underflow:
4794a58aedfSRichard Henderson                 round = 1;
4804a58aedfSRichard Henderson             }
4814a58aedfSRichard Henderson 
4824a58aedfSRichard Henderson             if (round) {
483c24a8a0bSRichard Henderson                 exc = FPCR_INE;
4844a58aedfSRichard Henderson                 switch (roundmode) {
4854a58aedfSRichard Henderson                 case float_round_nearest_even:
4864a58aedfSRichard Henderson                     if (round == (1ull << 63)) {
4874a58aedfSRichard Henderson                         /* Fraction is exactly 0.5; round to even.  */
4884a58aedfSRichard Henderson                         ret += (ret & 1);
4894a58aedfSRichard Henderson                     } else if (round > (1ull << 63)) {
4904a58aedfSRichard Henderson                         ret += 1;
4914a58aedfSRichard Henderson                     }
4924a58aedfSRichard Henderson                     break;
4934a58aedfSRichard Henderson                 case float_round_to_zero:
4944a58aedfSRichard Henderson                     break;
4954a58aedfSRichard Henderson                 case float_round_up:
4964a58aedfSRichard Henderson                     ret += 1 - sign;
4974a58aedfSRichard Henderson                     break;
4984a58aedfSRichard Henderson                 case float_round_down:
4994a58aedfSRichard Henderson                     ret += sign;
5004a58aedfSRichard Henderson                     break;
5014a58aedfSRichard Henderson                 }
5024a58aedfSRichard Henderson             }
5034a58aedfSRichard Henderson         }
5044a58aedfSRichard Henderson         if (sign) {
5054a58aedfSRichard Henderson             ret = -ret;
5064a58aedfSRichard Henderson         }
5074a58aedfSRichard Henderson     }
508f3d3aad4SRichard Henderson     env->error_code = exc;
5094a58aedfSRichard Henderson 
5104a58aedfSRichard Henderson     return ret;
5114a58aedfSRichard Henderson }
5124a58aedfSRichard Henderson 
5134a58aedfSRichard Henderson uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
5144a58aedfSRichard Henderson {
515c24a8a0bSRichard Henderson     return do_cvttq(env, a, FP_STATUS.float_rounding_mode);
5164a58aedfSRichard Henderson }
5174a58aedfSRichard Henderson 
5184a58aedfSRichard Henderson uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
5194a58aedfSRichard Henderson {
520c24a8a0bSRichard Henderson     return do_cvttq(env, a, float_round_to_zero);
5214a58aedfSRichard Henderson }
5224a58aedfSRichard Henderson 
5234a58aedfSRichard Henderson uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
5244a58aedfSRichard Henderson {
5254a58aedfSRichard Henderson     float64 fr = int64_to_float64(a, &FP_STATUS);
526f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
5274a58aedfSRichard Henderson     return float64_to_t(fr);
5284a58aedfSRichard Henderson }
5294a58aedfSRichard Henderson 
5303da653faSRichard Henderson void helper_cvtql_v_input(CPUAlphaState *env, uint64_t val)
531e8d8fef4SRichard Henderson {
532e8d8fef4SRichard Henderson     if (val != (int32_t)val) {
533e8d8fef4SRichard Henderson         arith_excp(env, GETPC(), EXC_M_IOV, 0);
534e8d8fef4SRichard Henderson     }
535e8d8fef4SRichard Henderson }
536