137356079SRichard Henderson /* 237356079SRichard Henderson * ARM VFP floating-point operations 337356079SRichard Henderson * 437356079SRichard Henderson * Copyright (c) 2003 Fabrice Bellard 537356079SRichard Henderson * 637356079SRichard Henderson * This library is free software; you can redistribute it and/or 737356079SRichard Henderson * modify it under the terms of the GNU Lesser General Public 837356079SRichard Henderson * License as published by the Free Software Foundation; either 937356079SRichard Henderson * version 2.1 of the License, or (at your option) any later version. 1037356079SRichard Henderson * 1137356079SRichard Henderson * This library is distributed in the hope that it will be useful, 1237356079SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of 1337356079SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1437356079SRichard Henderson * Lesser General Public License for more details. 1537356079SRichard Henderson * 1637356079SRichard Henderson * You should have received a copy of the GNU Lesser General Public 1737356079SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1837356079SRichard Henderson */ 1937356079SRichard Henderson 2037356079SRichard Henderson #include "qemu/osdep.h" 2137356079SRichard Henderson #include "cpu.h" 2237356079SRichard Henderson #include "exec/helper-proto.h" 2337356079SRichard Henderson #include "internals.h" 245a534314SPeter Maydell #include "cpu-features.h" 254a15527cSPhilippe Mathieu-Daudé #ifdef CONFIG_TCG 264a15527cSPhilippe Mathieu-Daudé #include "qemu/log.h" 274a15527cSPhilippe Mathieu-Daudé #include "fpu/softfloat.h" 284a15527cSPhilippe Mathieu-Daudé #endif 2937356079SRichard Henderson 3037356079SRichard Henderson /* VFP support. We follow the convention used for VFP instructions: 3137356079SRichard Henderson Single precision routines have a "s" suffix, double precision a 3237356079SRichard Henderson "d" suffix. */ 3337356079SRichard Henderson 344a15527cSPhilippe Mathieu-Daudé #ifdef CONFIG_TCG 354a15527cSPhilippe Mathieu-Daudé 3637356079SRichard Henderson /* Convert host exception flags to vfp form. */ 3737356079SRichard Henderson static inline int vfp_exceptbits_from_host(int host_bits) 3837356079SRichard Henderson { 3937356079SRichard Henderson int target_bits = 0; 4037356079SRichard Henderson 419798ac71SPhilippe Mathieu-Daudé if (host_bits & float_flag_invalid) { 4237356079SRichard Henderson target_bits |= 1; 439798ac71SPhilippe Mathieu-Daudé } 449798ac71SPhilippe Mathieu-Daudé if (host_bits & float_flag_divbyzero) { 4537356079SRichard Henderson target_bits |= 2; 469798ac71SPhilippe Mathieu-Daudé } 479798ac71SPhilippe Mathieu-Daudé if (host_bits & float_flag_overflow) { 4837356079SRichard Henderson target_bits |= 4; 499798ac71SPhilippe Mathieu-Daudé } 509798ac71SPhilippe Mathieu-Daudé if (host_bits & (float_flag_underflow | float_flag_output_denormal)) { 5137356079SRichard Henderson target_bits |= 8; 529798ac71SPhilippe Mathieu-Daudé } 539798ac71SPhilippe Mathieu-Daudé if (host_bits & float_flag_inexact) { 5437356079SRichard Henderson target_bits |= 0x10; 559798ac71SPhilippe Mathieu-Daudé } 569798ac71SPhilippe Mathieu-Daudé if (host_bits & float_flag_input_denormal) { 5737356079SRichard Henderson target_bits |= 0x80; 589798ac71SPhilippe Mathieu-Daudé } 5937356079SRichard Henderson return target_bits; 6037356079SRichard Henderson } 6137356079SRichard Henderson 6237356079SRichard Henderson /* Convert vfp exception flags to target form. */ 6337356079SRichard Henderson static inline int vfp_exceptbits_to_host(int target_bits) 6437356079SRichard Henderson { 6537356079SRichard Henderson int host_bits = 0; 6637356079SRichard Henderson 679798ac71SPhilippe Mathieu-Daudé if (target_bits & 1) { 6837356079SRichard Henderson host_bits |= float_flag_invalid; 699798ac71SPhilippe Mathieu-Daudé } 709798ac71SPhilippe Mathieu-Daudé if (target_bits & 2) { 7137356079SRichard Henderson host_bits |= float_flag_divbyzero; 729798ac71SPhilippe Mathieu-Daudé } 739798ac71SPhilippe Mathieu-Daudé if (target_bits & 4) { 7437356079SRichard Henderson host_bits |= float_flag_overflow; 759798ac71SPhilippe Mathieu-Daudé } 769798ac71SPhilippe Mathieu-Daudé if (target_bits & 8) { 7737356079SRichard Henderson host_bits |= float_flag_underflow; 789798ac71SPhilippe Mathieu-Daudé } 799798ac71SPhilippe Mathieu-Daudé if (target_bits & 0x10) { 8037356079SRichard Henderson host_bits |= float_flag_inexact; 819798ac71SPhilippe Mathieu-Daudé } 829798ac71SPhilippe Mathieu-Daudé if (target_bits & 0x80) { 8337356079SRichard Henderson host_bits |= float_flag_input_denormal; 849798ac71SPhilippe Mathieu-Daudé } 8537356079SRichard Henderson return host_bits; 8637356079SRichard Henderson } 8737356079SRichard Henderson 880c6ad948SPhilippe Mathieu-Daudé static uint32_t vfp_get_fpscr_from_host(CPUARMState *env) 890c6ad948SPhilippe Mathieu-Daudé { 900c6ad948SPhilippe Mathieu-Daudé uint32_t i; 910c6ad948SPhilippe Mathieu-Daudé 920c6ad948SPhilippe Mathieu-Daudé i = get_float_exception_flags(&env->vfp.fp_status); 930c6ad948SPhilippe Mathieu-Daudé i |= get_float_exception_flags(&env->vfp.standard_fp_status); 940c6ad948SPhilippe Mathieu-Daudé /* FZ16 does not generate an input denormal exception. */ 950c6ad948SPhilippe Mathieu-Daudé i |= (get_float_exception_flags(&env->vfp.fp_status_f16) 960c6ad948SPhilippe Mathieu-Daudé & ~float_flag_input_denormal); 97aaae563bSPeter Maydell i |= (get_float_exception_flags(&env->vfp.standard_fp_status_f16) 98aaae563bSPeter Maydell & ~float_flag_input_denormal); 990c6ad948SPhilippe Mathieu-Daudé return vfp_exceptbits_from_host(i); 1000c6ad948SPhilippe Mathieu-Daudé } 1010c6ad948SPhilippe Mathieu-Daudé 102e9d65282SPhilippe Mathieu-Daudé static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val) 10337356079SRichard Henderson { 10437356079SRichard Henderson int i; 10537356079SRichard Henderson uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR]; 10637356079SRichard Henderson 10737356079SRichard Henderson changed ^= val; 10837356079SRichard Henderson if (changed & (3 << 22)) { 10937356079SRichard Henderson i = (val >> 22) & 3; 11037356079SRichard Henderson switch (i) { 11137356079SRichard Henderson case FPROUNDING_TIEEVEN: 11237356079SRichard Henderson i = float_round_nearest_even; 11337356079SRichard Henderson break; 11437356079SRichard Henderson case FPROUNDING_POSINF: 11537356079SRichard Henderson i = float_round_up; 11637356079SRichard Henderson break; 11737356079SRichard Henderson case FPROUNDING_NEGINF: 11837356079SRichard Henderson i = float_round_down; 11937356079SRichard Henderson break; 12037356079SRichard Henderson case FPROUNDING_ZERO: 12137356079SRichard Henderson i = float_round_to_zero; 12237356079SRichard Henderson break; 12337356079SRichard Henderson } 12437356079SRichard Henderson set_float_rounding_mode(i, &env->vfp.fp_status); 12537356079SRichard Henderson set_float_rounding_mode(i, &env->vfp.fp_status_f16); 12637356079SRichard Henderson } 12737356079SRichard Henderson if (changed & FPCR_FZ16) { 12837356079SRichard Henderson bool ftz_enabled = val & FPCR_FZ16; 12937356079SRichard Henderson set_flush_to_zero(ftz_enabled, &env->vfp.fp_status_f16); 130aaae563bSPeter Maydell set_flush_to_zero(ftz_enabled, &env->vfp.standard_fp_status_f16); 13137356079SRichard Henderson set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status_f16); 132aaae563bSPeter Maydell set_flush_inputs_to_zero(ftz_enabled, &env->vfp.standard_fp_status_f16); 13337356079SRichard Henderson } 13437356079SRichard Henderson if (changed & FPCR_FZ) { 13537356079SRichard Henderson bool ftz_enabled = val & FPCR_FZ; 13637356079SRichard Henderson set_flush_to_zero(ftz_enabled, &env->vfp.fp_status); 13737356079SRichard Henderson set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status); 13837356079SRichard Henderson } 13937356079SRichard Henderson if (changed & FPCR_DN) { 14037356079SRichard Henderson bool dnan_enabled = val & FPCR_DN; 14137356079SRichard Henderson set_default_nan_mode(dnan_enabled, &env->vfp.fp_status); 14237356079SRichard Henderson set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16); 14337356079SRichard Henderson } 14437356079SRichard Henderson 1459a223097SPhilippe Mathieu-Daudé /* 1469a223097SPhilippe Mathieu-Daudé * The exception flags are ORed together when we read fpscr so we 14737356079SRichard Henderson * only need to preserve the current state in one of our 14837356079SRichard Henderson * float_status values. 14937356079SRichard Henderson */ 15037356079SRichard Henderson i = vfp_exceptbits_to_host(val); 15137356079SRichard Henderson set_float_exception_flags(i, &env->vfp.fp_status); 15237356079SRichard Henderson set_float_exception_flags(0, &env->vfp.fp_status_f16); 15337356079SRichard Henderson set_float_exception_flags(0, &env->vfp.standard_fp_status); 154aaae563bSPeter Maydell set_float_exception_flags(0, &env->vfp.standard_fp_status_f16); 15537356079SRichard Henderson } 15637356079SRichard Henderson 1574a15527cSPhilippe Mathieu-Daudé #else 1584a15527cSPhilippe Mathieu-Daudé 1594a15527cSPhilippe Mathieu-Daudé static uint32_t vfp_get_fpscr_from_host(CPUARMState *env) 1604a15527cSPhilippe Mathieu-Daudé { 1614a15527cSPhilippe Mathieu-Daudé return 0; 1624a15527cSPhilippe Mathieu-Daudé } 1634a15527cSPhilippe Mathieu-Daudé 1644a15527cSPhilippe Mathieu-Daudé static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val) 1654a15527cSPhilippe Mathieu-Daudé { 1664a15527cSPhilippe Mathieu-Daudé } 1674a15527cSPhilippe Mathieu-Daudé 1684a15527cSPhilippe Mathieu-Daudé #endif 1694a15527cSPhilippe Mathieu-Daudé 170e9d65282SPhilippe Mathieu-Daudé uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env) 171e9d65282SPhilippe Mathieu-Daudé { 172e9d65282SPhilippe Mathieu-Daudé uint32_t i, fpscr; 173e9d65282SPhilippe Mathieu-Daudé 174e9d65282SPhilippe Mathieu-Daudé fpscr = env->vfp.xregs[ARM_VFP_FPSCR] 175e9d65282SPhilippe Mathieu-Daudé | (env->vfp.vec_len << 16) 176e9d65282SPhilippe Mathieu-Daudé | (env->vfp.vec_stride << 20); 177e9d65282SPhilippe Mathieu-Daudé 1788128c8e8SPeter Maydell /* 1798128c8e8SPeter Maydell * M-profile LTPSIZE overlaps A-profile Stride; whichever of the 1808128c8e8SPeter Maydell * two is not applicable to this CPU will always be zero. 1818128c8e8SPeter Maydell */ 1828128c8e8SPeter Maydell fpscr |= env->v7m.ltpsize << 16; 1838128c8e8SPeter Maydell 1840c6ad948SPhilippe Mathieu-Daudé fpscr |= vfp_get_fpscr_from_host(env); 185e9d65282SPhilippe Mathieu-Daudé 186e9d65282SPhilippe Mathieu-Daudé i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3]; 187e9d65282SPhilippe Mathieu-Daudé fpscr |= i ? FPCR_QC : 0; 188e9d65282SPhilippe Mathieu-Daudé 189e9d65282SPhilippe Mathieu-Daudé return fpscr; 190e9d65282SPhilippe Mathieu-Daudé } 191e9d65282SPhilippe Mathieu-Daudé 192e9d65282SPhilippe Mathieu-Daudé uint32_t vfp_get_fpscr(CPUARMState *env) 193e9d65282SPhilippe Mathieu-Daudé { 194e9d65282SPhilippe Mathieu-Daudé return HELPER(vfp_get_fpscr)(env); 195e9d65282SPhilippe Mathieu-Daudé } 196e9d65282SPhilippe Mathieu-Daudé 197e9d65282SPhilippe Mathieu-Daudé void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val) 198e9d65282SPhilippe Mathieu-Daudé { 199b26b5629SPeter Maydell ARMCPU *cpu = env_archcpu(env); 200b26b5629SPeter Maydell 201e9d65282SPhilippe Mathieu-Daudé /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */ 202b26b5629SPeter Maydell if (!cpu_isar_feature(any_fp16, cpu)) { 203e9d65282SPhilippe Mathieu-Daudé val &= ~FPCR_FZ16; 204e9d65282SPhilippe Mathieu-Daudé } 205e9d65282SPhilippe Mathieu-Daudé 20685795187SPhilippe Mathieu-Daudé vfp_set_fpscr_to_host(env, val); 20785795187SPhilippe Mathieu-Daudé 208d31e2ce6SPeter Maydell if (!arm_feature(env, ARM_FEATURE_M)) { 209e9d65282SPhilippe Mathieu-Daudé /* 210d31e2ce6SPeter Maydell * Short-vector length and stride; on M-profile these bits 211d31e2ce6SPeter Maydell * are used for different purposes. 212d31e2ce6SPeter Maydell * We can't make this conditional be "if MVFR0.FPShVec != 0", 213d31e2ce6SPeter Maydell * because in v7A no-short-vector-support cores still had to 214d31e2ce6SPeter Maydell * allow Stride/Len to be written with the only effect that 215d31e2ce6SPeter Maydell * some insns are required to UNDEF if the guest sets them. 216e9d65282SPhilippe Mathieu-Daudé */ 217d31e2ce6SPeter Maydell env->vfp.vec_len = extract32(val, 16, 3); 218d31e2ce6SPeter Maydell env->vfp.vec_stride = extract32(val, 20, 2); 219b26b5629SPeter Maydell } else if (cpu_isar_feature(aa32_mve, cpu)) { 220b26b5629SPeter Maydell env->v7m.ltpsize = extract32(val, FPCR_LTPSIZE_SHIFT, 221b26b5629SPeter Maydell FPCR_LTPSIZE_LENGTH); 222d31e2ce6SPeter Maydell } 223e9d65282SPhilippe Mathieu-Daudé 224c485ce2cSPeter Maydell if (arm_feature(env, ARM_FEATURE_NEON) || 225c485ce2cSPeter Maydell cpu_isar_feature(aa32_mve, cpu)) { 226e9d65282SPhilippe Mathieu-Daudé /* 227e9d65282SPhilippe Mathieu-Daudé * The bit we set within fpscr_q is arbitrary; the register as a 228e9d65282SPhilippe Mathieu-Daudé * whole being zero/non-zero is what counts. 229d31e2ce6SPeter Maydell * TODO: M-profile MVE also has a QC bit. 230e9d65282SPhilippe Mathieu-Daudé */ 231e9d65282SPhilippe Mathieu-Daudé env->vfp.qc[0] = val & FPCR_QC; 232e9d65282SPhilippe Mathieu-Daudé env->vfp.qc[1] = 0; 233e9d65282SPhilippe Mathieu-Daudé env->vfp.qc[2] = 0; 234e9d65282SPhilippe Mathieu-Daudé env->vfp.qc[3] = 0; 235e9d65282SPhilippe Mathieu-Daudé } 236e9d65282SPhilippe Mathieu-Daudé 237d31e2ce6SPeter Maydell /* 238d31e2ce6SPeter Maydell * We don't implement trapped exception handling, so the 239d31e2ce6SPeter Maydell * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!) 240d31e2ce6SPeter Maydell * 241d31e2ce6SPeter Maydell * The exception flags IOC|DZC|OFC|UFC|IXC|IDC are stored in 242d31e2ce6SPeter Maydell * fp_status; QC, Len and Stride are stored separately earlier. 243d31e2ce6SPeter Maydell * Clear out all of those and the RES0 bits: only NZCV, AHP, DN, 244d31e2ce6SPeter Maydell * FZ, RMode and FZ16 are kept in vfp.xregs[FPSCR]. 245d31e2ce6SPeter Maydell */ 246d31e2ce6SPeter Maydell env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000; 247d31e2ce6SPeter Maydell } 248d31e2ce6SPeter Maydell 24937356079SRichard Henderson void vfp_set_fpscr(CPUARMState *env, uint32_t val) 25037356079SRichard Henderson { 25137356079SRichard Henderson HELPER(vfp_set_fpscr)(env, val); 25237356079SRichard Henderson } 25337356079SRichard Henderson 2544a15527cSPhilippe Mathieu-Daudé #ifdef CONFIG_TCG 2554a15527cSPhilippe Mathieu-Daudé 25637356079SRichard Henderson #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) 25737356079SRichard Henderson 25837356079SRichard Henderson #define VFP_BINOP(name) \ 259120a0eb3SPeter Maydell dh_ctype_f16 VFP_HELPER(name, h)(dh_ctype_f16 a, dh_ctype_f16 b, void *fpstp) \ 260120a0eb3SPeter Maydell { \ 261120a0eb3SPeter Maydell float_status *fpst = fpstp; \ 262120a0eb3SPeter Maydell return float16_ ## name(a, b, fpst); \ 263120a0eb3SPeter Maydell } \ 26437356079SRichard Henderson float32 VFP_HELPER(name, s)(float32 a, float32 b, void *fpstp) \ 26537356079SRichard Henderson { \ 26637356079SRichard Henderson float_status *fpst = fpstp; \ 26737356079SRichard Henderson return float32_ ## name(a, b, fpst); \ 26837356079SRichard Henderson } \ 26937356079SRichard Henderson float64 VFP_HELPER(name, d)(float64 a, float64 b, void *fpstp) \ 27037356079SRichard Henderson { \ 27137356079SRichard Henderson float_status *fpst = fpstp; \ 27237356079SRichard Henderson return float64_ ## name(a, b, fpst); \ 27337356079SRichard Henderson } 27437356079SRichard Henderson VFP_BINOP(add) 27537356079SRichard Henderson VFP_BINOP(sub) 27637356079SRichard Henderson VFP_BINOP(mul) 27737356079SRichard Henderson VFP_BINOP(div) 27837356079SRichard Henderson VFP_BINOP(min) 27937356079SRichard Henderson VFP_BINOP(max) 28037356079SRichard Henderson VFP_BINOP(minnum) 28137356079SRichard Henderson VFP_BINOP(maxnum) 28237356079SRichard Henderson #undef VFP_BINOP 28337356079SRichard Henderson 284e7cb0dedSPeter Maydell dh_ctype_f16 VFP_HELPER(neg, h)(dh_ctype_f16 a) 285e7cb0dedSPeter Maydell { 286e7cb0dedSPeter Maydell return float16_chs(a); 287e7cb0dedSPeter Maydell } 288e7cb0dedSPeter Maydell 28937356079SRichard Henderson float32 VFP_HELPER(neg, s)(float32 a) 29037356079SRichard Henderson { 29137356079SRichard Henderson return float32_chs(a); 29237356079SRichard Henderson } 29337356079SRichard Henderson 29437356079SRichard Henderson float64 VFP_HELPER(neg, d)(float64 a) 29537356079SRichard Henderson { 29637356079SRichard Henderson return float64_chs(a); 29737356079SRichard Henderson } 29837356079SRichard Henderson 299ce2d65a5SPeter Maydell dh_ctype_f16 VFP_HELPER(abs, h)(dh_ctype_f16 a) 300ce2d65a5SPeter Maydell { 301ce2d65a5SPeter Maydell return float16_abs(a); 302ce2d65a5SPeter Maydell } 303ce2d65a5SPeter Maydell 30437356079SRichard Henderson float32 VFP_HELPER(abs, s)(float32 a) 30537356079SRichard Henderson { 30637356079SRichard Henderson return float32_abs(a); 30737356079SRichard Henderson } 30837356079SRichard Henderson 30937356079SRichard Henderson float64 VFP_HELPER(abs, d)(float64 a) 31037356079SRichard Henderson { 31137356079SRichard Henderson return float64_abs(a); 31237356079SRichard Henderson } 31337356079SRichard Henderson 314ce2d65a5SPeter Maydell dh_ctype_f16 VFP_HELPER(sqrt, h)(dh_ctype_f16 a, CPUARMState *env) 315ce2d65a5SPeter Maydell { 316ce2d65a5SPeter Maydell return float16_sqrt(a, &env->vfp.fp_status_f16); 317ce2d65a5SPeter Maydell } 318ce2d65a5SPeter Maydell 31937356079SRichard Henderson float32 VFP_HELPER(sqrt, s)(float32 a, CPUARMState *env) 32037356079SRichard Henderson { 32137356079SRichard Henderson return float32_sqrt(a, &env->vfp.fp_status); 32237356079SRichard Henderson } 32337356079SRichard Henderson 32437356079SRichard Henderson float64 VFP_HELPER(sqrt, d)(float64 a, CPUARMState *env) 32537356079SRichard Henderson { 32637356079SRichard Henderson return float64_sqrt(a, &env->vfp.fp_status); 32737356079SRichard Henderson } 32837356079SRichard Henderson 32971bfd65cSRichard Henderson static void softfloat_to_vfp_compare(CPUARMState *env, FloatRelation cmp) 33037356079SRichard Henderson { 33137356079SRichard Henderson uint32_t flags; 33237356079SRichard Henderson switch (cmp) { 33337356079SRichard Henderson case float_relation_equal: 33437356079SRichard Henderson flags = 0x6; 33537356079SRichard Henderson break; 33637356079SRichard Henderson case float_relation_less: 33737356079SRichard Henderson flags = 0x8; 33837356079SRichard Henderson break; 33937356079SRichard Henderson case float_relation_greater: 34037356079SRichard Henderson flags = 0x2; 34137356079SRichard Henderson break; 34237356079SRichard Henderson case float_relation_unordered: 34337356079SRichard Henderson flags = 0x3; 34437356079SRichard Henderson break; 34537356079SRichard Henderson default: 34637356079SRichard Henderson g_assert_not_reached(); 34737356079SRichard Henderson } 34837356079SRichard Henderson env->vfp.xregs[ARM_VFP_FPSCR] = 34937356079SRichard Henderson deposit32(env->vfp.xregs[ARM_VFP_FPSCR], 28, 4, flags); 35037356079SRichard Henderson } 35137356079SRichard Henderson 35237356079SRichard Henderson /* XXX: check quiet/signaling case */ 3531b88b054SPeter Maydell #define DO_VFP_cmp(P, FLOATTYPE, ARGTYPE, FPST) \ 3541b88b054SPeter Maydell void VFP_HELPER(cmp, P)(ARGTYPE a, ARGTYPE b, CPUARMState *env) \ 35537356079SRichard Henderson { \ 35637356079SRichard Henderson softfloat_to_vfp_compare(env, \ 3571b88b054SPeter Maydell FLOATTYPE ## _compare_quiet(a, b, &env->vfp.FPST)); \ 35837356079SRichard Henderson } \ 3591b88b054SPeter Maydell void VFP_HELPER(cmpe, P)(ARGTYPE a, ARGTYPE b, CPUARMState *env) \ 36037356079SRichard Henderson { \ 36137356079SRichard Henderson softfloat_to_vfp_compare(env, \ 3621b88b054SPeter Maydell FLOATTYPE ## _compare(a, b, &env->vfp.FPST)); \ 36337356079SRichard Henderson } 3641b88b054SPeter Maydell DO_VFP_cmp(h, float16, dh_ctype_f16, fp_status_f16) 3651b88b054SPeter Maydell DO_VFP_cmp(s, float32, float32, fp_status) 3661b88b054SPeter Maydell DO_VFP_cmp(d, float64, float64, fp_status) 36737356079SRichard Henderson #undef DO_VFP_cmp 36837356079SRichard Henderson 36937356079SRichard Henderson /* Integer to float and float to integer conversions */ 37037356079SRichard Henderson 37137356079SRichard Henderson #define CONV_ITOF(name, ftype, fsz, sign) \ 37237356079SRichard Henderson ftype HELPER(name)(uint32_t x, void *fpstp) \ 37337356079SRichard Henderson { \ 37437356079SRichard Henderson float_status *fpst = fpstp; \ 37537356079SRichard Henderson return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \ 37637356079SRichard Henderson } 37737356079SRichard Henderson 37837356079SRichard Henderson #define CONV_FTOI(name, ftype, fsz, sign, round) \ 37937356079SRichard Henderson sign##int32_t HELPER(name)(ftype x, void *fpstp) \ 38037356079SRichard Henderson { \ 38137356079SRichard Henderson float_status *fpst = fpstp; \ 38237356079SRichard Henderson if (float##fsz##_is_any_nan(x)) { \ 38337356079SRichard Henderson float_raise(float_flag_invalid, fpst); \ 38437356079SRichard Henderson return 0; \ 38537356079SRichard Henderson } \ 38637356079SRichard Henderson return float##fsz##_to_##sign##int32##round(x, fpst); \ 38737356079SRichard Henderson } 38837356079SRichard Henderson 38937356079SRichard Henderson #define FLOAT_CONVS(name, p, ftype, fsz, sign) \ 39037356079SRichard Henderson CONV_ITOF(vfp_##name##to##p, ftype, fsz, sign) \ 39137356079SRichard Henderson CONV_FTOI(vfp_to##name##p, ftype, fsz, sign, ) \ 39237356079SRichard Henderson CONV_FTOI(vfp_to##name##z##p, ftype, fsz, sign, _round_to_zero) 39337356079SRichard Henderson 39437356079SRichard Henderson FLOAT_CONVS(si, h, uint32_t, 16, ) 39537356079SRichard Henderson FLOAT_CONVS(si, s, float32, 32, ) 39637356079SRichard Henderson FLOAT_CONVS(si, d, float64, 64, ) 39737356079SRichard Henderson FLOAT_CONVS(ui, h, uint32_t, 16, u) 39837356079SRichard Henderson FLOAT_CONVS(ui, s, float32, 32, u) 39937356079SRichard Henderson FLOAT_CONVS(ui, d, float64, 64, u) 40037356079SRichard Henderson 40137356079SRichard Henderson #undef CONV_ITOF 40237356079SRichard Henderson #undef CONV_FTOI 40337356079SRichard Henderson #undef FLOAT_CONVS 40437356079SRichard Henderson 40537356079SRichard Henderson /* floating point conversion */ 40637356079SRichard Henderson float64 VFP_HELPER(fcvtd, s)(float32 x, CPUARMState *env) 40737356079SRichard Henderson { 40837356079SRichard Henderson return float32_to_float64(x, &env->vfp.fp_status); 40937356079SRichard Henderson } 41037356079SRichard Henderson 41137356079SRichard Henderson float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env) 41237356079SRichard Henderson { 41337356079SRichard Henderson return float64_to_float32(x, &env->vfp.fp_status); 41437356079SRichard Henderson } 41537356079SRichard Henderson 4163a98ac40SRichard Henderson uint32_t HELPER(bfcvt)(float32 x, void *status) 4173a98ac40SRichard Henderson { 4183a98ac40SRichard Henderson return float32_to_bfloat16(x, status); 4193a98ac40SRichard Henderson } 4203a98ac40SRichard Henderson 421d29b17caSRichard Henderson uint32_t HELPER(bfcvt_pair)(uint64_t pair, void *status) 422d29b17caSRichard Henderson { 423d29b17caSRichard Henderson bfloat16 lo = float32_to_bfloat16(extract64(pair, 0, 32), status); 424d29b17caSRichard Henderson bfloat16 hi = float32_to_bfloat16(extract64(pair, 32, 32), status); 425d29b17caSRichard Henderson return deposit32(lo, 16, 16, hi); 426d29b17caSRichard Henderson } 427d29b17caSRichard Henderson 42861db12d9SPeter Maydell /* 42961db12d9SPeter Maydell * VFP3 fixed point conversion. The AArch32 versions of fix-to-float 43061db12d9SPeter Maydell * must always round-to-nearest; the AArch64 ones honour the FPSCR 43161db12d9SPeter Maydell * rounding mode. (For AArch32 Neon the standard-FPSCR is set to 43261db12d9SPeter Maydell * round-to-nearest so either helper will work.) AArch32 float-to-fix 43361db12d9SPeter Maydell * must round-to-zero. 43461db12d9SPeter Maydell */ 4355366f6adSPeter Maydell #define VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \ 4365366f6adSPeter Maydell ftype HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \ 43737356079SRichard Henderson void *fpstp) \ 43837356079SRichard Henderson { return itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); } 43937356079SRichard Henderson 44061db12d9SPeter Maydell #define VFP_CONV_FIX_FLOAT_ROUND(name, p, fsz, ftype, isz, itype) \ 44161db12d9SPeter Maydell ftype HELPER(vfp_##name##to##p##_round_to_nearest)(uint##isz##_t x, \ 44261db12d9SPeter Maydell uint32_t shift, \ 44361db12d9SPeter Maydell void *fpstp) \ 44461db12d9SPeter Maydell { \ 44561db12d9SPeter Maydell ftype ret; \ 44661db12d9SPeter Maydell float_status *fpst = fpstp; \ 44761db12d9SPeter Maydell FloatRoundMode oldmode = fpst->float_rounding_mode; \ 44861db12d9SPeter Maydell fpst->float_rounding_mode = float_round_nearest_even; \ 44961db12d9SPeter Maydell ret = itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); \ 45061db12d9SPeter Maydell fpst->float_rounding_mode = oldmode; \ 45161db12d9SPeter Maydell return ret; \ 45261db12d9SPeter Maydell } 45361db12d9SPeter Maydell 4545366f6adSPeter Maydell #define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, ROUND, suff) \ 4555366f6adSPeter Maydell uint##isz##_t HELPER(vfp_to##name##p##suff)(ftype x, uint32_t shift, \ 45637356079SRichard Henderson void *fpst) \ 45737356079SRichard Henderson { \ 45837356079SRichard Henderson if (unlikely(float##fsz##_is_any_nan(x))) { \ 45937356079SRichard Henderson float_raise(float_flag_invalid, fpst); \ 46037356079SRichard Henderson return 0; \ 46137356079SRichard Henderson } \ 46237356079SRichard Henderson return float##fsz##_to_##itype##_scalbn(x, ROUND, shift, fpst); \ 46337356079SRichard Henderson } 46437356079SRichard Henderson 4655366f6adSPeter Maydell #define VFP_CONV_FIX(name, p, fsz, ftype, isz, itype) \ 4665366f6adSPeter Maydell VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \ 46761db12d9SPeter Maydell VFP_CONV_FIX_FLOAT_ROUND(name, p, fsz, ftype, isz, itype) \ 4685366f6adSPeter Maydell VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \ 46937356079SRichard Henderson float_round_to_zero, _round_to_zero) \ 4705366f6adSPeter Maydell VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \ 47137356079SRichard Henderson get_float_rounding_mode(fpst), ) 47237356079SRichard Henderson 4735366f6adSPeter Maydell #define VFP_CONV_FIX_A64(name, p, fsz, ftype, isz, itype) \ 4745366f6adSPeter Maydell VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \ 4755366f6adSPeter Maydell VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \ 47637356079SRichard Henderson get_float_rounding_mode(fpst), ) 47737356079SRichard Henderson 4785366f6adSPeter Maydell VFP_CONV_FIX(sh, d, 64, float64, 64, int16) 4795366f6adSPeter Maydell VFP_CONV_FIX(sl, d, 64, float64, 64, int32) 4805366f6adSPeter Maydell VFP_CONV_FIX_A64(sq, d, 64, float64, 64, int64) 4815366f6adSPeter Maydell VFP_CONV_FIX(uh, d, 64, float64, 64, uint16) 4825366f6adSPeter Maydell VFP_CONV_FIX(ul, d, 64, float64, 64, uint32) 4835366f6adSPeter Maydell VFP_CONV_FIX_A64(uq, d, 64, float64, 64, uint64) 4845366f6adSPeter Maydell VFP_CONV_FIX(sh, s, 32, float32, 32, int16) 4855366f6adSPeter Maydell VFP_CONV_FIX(sl, s, 32, float32, 32, int32) 4865366f6adSPeter Maydell VFP_CONV_FIX_A64(sq, s, 32, float32, 64, int64) 4875366f6adSPeter Maydell VFP_CONV_FIX(uh, s, 32, float32, 32, uint16) 4885366f6adSPeter Maydell VFP_CONV_FIX(ul, s, 32, float32, 32, uint32) 4895366f6adSPeter Maydell VFP_CONV_FIX_A64(uq, s, 32, float32, 64, uint64) 490414ba270SPeter Maydell VFP_CONV_FIX(sh, h, 16, dh_ctype_f16, 32, int16) 491414ba270SPeter Maydell VFP_CONV_FIX(sl, h, 16, dh_ctype_f16, 32, int32) 492414ba270SPeter Maydell VFP_CONV_FIX_A64(sq, h, 16, dh_ctype_f16, 64, int64) 493414ba270SPeter Maydell VFP_CONV_FIX(uh, h, 16, dh_ctype_f16, 32, uint16) 494414ba270SPeter Maydell VFP_CONV_FIX(ul, h, 16, dh_ctype_f16, 32, uint32) 495414ba270SPeter Maydell VFP_CONV_FIX_A64(uq, h, 16, dh_ctype_f16, 64, uint64) 49637356079SRichard Henderson 49737356079SRichard Henderson #undef VFP_CONV_FIX 49837356079SRichard Henderson #undef VFP_CONV_FIX_FLOAT 49937356079SRichard Henderson #undef VFP_CONV_FLOAT_FIX_ROUND 50037356079SRichard Henderson #undef VFP_CONV_FIX_A64 50137356079SRichard Henderson 50237356079SRichard Henderson /* Set the current fp rounding mode and return the old one. 50337356079SRichard Henderson * The argument is a softfloat float_round_ value. 50437356079SRichard Henderson */ 50537356079SRichard Henderson uint32_t HELPER(set_rmode)(uint32_t rmode, void *fpstp) 50637356079SRichard Henderson { 50737356079SRichard Henderson float_status *fp_status = fpstp; 50837356079SRichard Henderson 50937356079SRichard Henderson uint32_t prev_rmode = get_float_rounding_mode(fp_status); 51037356079SRichard Henderson set_float_rounding_mode(rmode, fp_status); 51137356079SRichard Henderson 51237356079SRichard Henderson return prev_rmode; 51337356079SRichard Henderson } 51437356079SRichard Henderson 51537356079SRichard Henderson /* Half precision conversions. */ 51637356079SRichard Henderson float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, void *fpstp, uint32_t ahp_mode) 51737356079SRichard Henderson { 51837356079SRichard Henderson /* Squash FZ16 to 0 for the duration of conversion. In this case, 51937356079SRichard Henderson * it would affect flushing input denormals. 52037356079SRichard Henderson */ 52137356079SRichard Henderson float_status *fpst = fpstp; 522c120391cSRichard Henderson bool save = get_flush_inputs_to_zero(fpst); 52337356079SRichard Henderson set_flush_inputs_to_zero(false, fpst); 52437356079SRichard Henderson float32 r = float16_to_float32(a, !ahp_mode, fpst); 52537356079SRichard Henderson set_flush_inputs_to_zero(save, fpst); 52637356079SRichard Henderson return r; 52737356079SRichard Henderson } 52837356079SRichard Henderson 52937356079SRichard Henderson uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode) 53037356079SRichard Henderson { 53137356079SRichard Henderson /* Squash FZ16 to 0 for the duration of conversion. In this case, 53237356079SRichard Henderson * it would affect flushing output denormals. 53337356079SRichard Henderson */ 53437356079SRichard Henderson float_status *fpst = fpstp; 535c120391cSRichard Henderson bool save = get_flush_to_zero(fpst); 53637356079SRichard Henderson set_flush_to_zero(false, fpst); 53737356079SRichard Henderson float16 r = float32_to_float16(a, !ahp_mode, fpst); 53837356079SRichard Henderson set_flush_to_zero(save, fpst); 53937356079SRichard Henderson return r; 54037356079SRichard Henderson } 54137356079SRichard Henderson 54237356079SRichard Henderson float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, void *fpstp, uint32_t ahp_mode) 54337356079SRichard Henderson { 54437356079SRichard Henderson /* Squash FZ16 to 0 for the duration of conversion. In this case, 54537356079SRichard Henderson * it would affect flushing input denormals. 54637356079SRichard Henderson */ 54737356079SRichard Henderson float_status *fpst = fpstp; 548c120391cSRichard Henderson bool save = get_flush_inputs_to_zero(fpst); 54937356079SRichard Henderson set_flush_inputs_to_zero(false, fpst); 55037356079SRichard Henderson float64 r = float16_to_float64(a, !ahp_mode, fpst); 55137356079SRichard Henderson set_flush_inputs_to_zero(save, fpst); 55237356079SRichard Henderson return r; 55337356079SRichard Henderson } 55437356079SRichard Henderson 55537356079SRichard Henderson uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode) 55637356079SRichard Henderson { 55737356079SRichard Henderson /* Squash FZ16 to 0 for the duration of conversion. In this case, 55837356079SRichard Henderson * it would affect flushing output denormals. 55937356079SRichard Henderson */ 56037356079SRichard Henderson float_status *fpst = fpstp; 561c120391cSRichard Henderson bool save = get_flush_to_zero(fpst); 56237356079SRichard Henderson set_flush_to_zero(false, fpst); 56337356079SRichard Henderson float16 r = float64_to_float16(a, !ahp_mode, fpst); 56437356079SRichard Henderson set_flush_to_zero(save, fpst); 56537356079SRichard Henderson return r; 56637356079SRichard Henderson } 56737356079SRichard Henderson 56837356079SRichard Henderson /* NEON helpers. */ 56937356079SRichard Henderson 57037356079SRichard Henderson /* Constants 256 and 512 are used in some helpers; we avoid relying on 57137356079SRichard Henderson * int->float conversions at run-time. */ 57237356079SRichard Henderson #define float64_256 make_float64(0x4070000000000000LL) 57337356079SRichard Henderson #define float64_512 make_float64(0x4080000000000000LL) 57437356079SRichard Henderson #define float16_maxnorm make_float16(0x7bff) 57537356079SRichard Henderson #define float32_maxnorm make_float32(0x7f7fffff) 57637356079SRichard Henderson #define float64_maxnorm make_float64(0x7fefffffffffffffLL) 57737356079SRichard Henderson 57837356079SRichard Henderson /* Reciprocal functions 57937356079SRichard Henderson * 58037356079SRichard Henderson * The algorithm that must be used to calculate the estimate 58137356079SRichard Henderson * is specified by the ARM ARM, see FPRecipEstimate()/RecipEstimate 58237356079SRichard Henderson */ 58337356079SRichard Henderson 58437356079SRichard Henderson /* See RecipEstimate() 58537356079SRichard Henderson * 58637356079SRichard Henderson * input is a 9 bit fixed point number 58737356079SRichard Henderson * input range 256 .. 511 for a number from 0.5 <= x < 1.0. 58837356079SRichard Henderson * result range 256 .. 511 for a number from 1.0 to 511/256. 58937356079SRichard Henderson */ 59037356079SRichard Henderson 59137356079SRichard Henderson static int recip_estimate(int input) 59237356079SRichard Henderson { 59337356079SRichard Henderson int a, b, r; 59437356079SRichard Henderson assert(256 <= input && input < 512); 59537356079SRichard Henderson a = (input * 2) + 1; 59637356079SRichard Henderson b = (1 << 19) / a; 59737356079SRichard Henderson r = (b + 1) >> 1; 59837356079SRichard Henderson assert(256 <= r && r < 512); 59937356079SRichard Henderson return r; 60037356079SRichard Henderson } 60137356079SRichard Henderson 60237356079SRichard Henderson /* 60337356079SRichard Henderson * Common wrapper to call recip_estimate 60437356079SRichard Henderson * 60537356079SRichard Henderson * The parameters are exponent and 64 bit fraction (without implicit 60637356079SRichard Henderson * bit) where the binary point is nominally at bit 52. Returns a 60737356079SRichard Henderson * float64 which can then be rounded to the appropriate size by the 60837356079SRichard Henderson * callee. 60937356079SRichard Henderson */ 61037356079SRichard Henderson 61137356079SRichard Henderson static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac) 61237356079SRichard Henderson { 61337356079SRichard Henderson uint32_t scaled, estimate; 61437356079SRichard Henderson uint64_t result_frac; 61537356079SRichard Henderson int result_exp; 61637356079SRichard Henderson 61737356079SRichard Henderson /* Handle sub-normals */ 61837356079SRichard Henderson if (*exp == 0) { 61937356079SRichard Henderson if (extract64(frac, 51, 1) == 0) { 62037356079SRichard Henderson *exp = -1; 62137356079SRichard Henderson frac <<= 2; 62237356079SRichard Henderson } else { 62337356079SRichard Henderson frac <<= 1; 62437356079SRichard Henderson } 62537356079SRichard Henderson } 62637356079SRichard Henderson 62737356079SRichard Henderson /* scaled = UInt('1':fraction<51:44>) */ 62837356079SRichard Henderson scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); 62937356079SRichard Henderson estimate = recip_estimate(scaled); 63037356079SRichard Henderson 63137356079SRichard Henderson result_exp = exp_off - *exp; 63237356079SRichard Henderson result_frac = deposit64(0, 44, 8, estimate); 63337356079SRichard Henderson if (result_exp == 0) { 63437356079SRichard Henderson result_frac = deposit64(result_frac >> 1, 51, 1, 1); 63537356079SRichard Henderson } else if (result_exp == -1) { 63637356079SRichard Henderson result_frac = deposit64(result_frac >> 2, 50, 2, 1); 63737356079SRichard Henderson result_exp = 0; 63837356079SRichard Henderson } 63937356079SRichard Henderson 64037356079SRichard Henderson *exp = result_exp; 64137356079SRichard Henderson 64237356079SRichard Henderson return result_frac; 64337356079SRichard Henderson } 64437356079SRichard Henderson 64537356079SRichard Henderson static bool round_to_inf(float_status *fpst, bool sign_bit) 64637356079SRichard Henderson { 64737356079SRichard Henderson switch (fpst->float_rounding_mode) { 64837356079SRichard Henderson case float_round_nearest_even: /* Round to Nearest */ 64937356079SRichard Henderson return true; 65037356079SRichard Henderson case float_round_up: /* Round to +Inf */ 65137356079SRichard Henderson return !sign_bit; 65237356079SRichard Henderson case float_round_down: /* Round to -Inf */ 65337356079SRichard Henderson return sign_bit; 65437356079SRichard Henderson case float_round_to_zero: /* Round to Zero */ 65537356079SRichard Henderson return false; 6563dede407SRichard Henderson default: 65737356079SRichard Henderson g_assert_not_reached(); 65837356079SRichard Henderson } 6593dede407SRichard Henderson } 66037356079SRichard Henderson 66137356079SRichard Henderson uint32_t HELPER(recpe_f16)(uint32_t input, void *fpstp) 66237356079SRichard Henderson { 66337356079SRichard Henderson float_status *fpst = fpstp; 66437356079SRichard Henderson float16 f16 = float16_squash_input_denormal(input, fpst); 66537356079SRichard Henderson uint32_t f16_val = float16_val(f16); 66637356079SRichard Henderson uint32_t f16_sign = float16_is_neg(f16); 66737356079SRichard Henderson int f16_exp = extract32(f16_val, 10, 5); 66837356079SRichard Henderson uint32_t f16_frac = extract32(f16_val, 0, 10); 66937356079SRichard Henderson uint64_t f64_frac; 67037356079SRichard Henderson 67137356079SRichard Henderson if (float16_is_any_nan(f16)) { 67237356079SRichard Henderson float16 nan = f16; 67337356079SRichard Henderson if (float16_is_signaling_nan(f16, fpst)) { 67437356079SRichard Henderson float_raise(float_flag_invalid, fpst); 675103e7579SJoe Komlodi if (!fpst->default_nan_mode) { 67637356079SRichard Henderson nan = float16_silence_nan(f16, fpst); 67737356079SRichard Henderson } 678103e7579SJoe Komlodi } 67937356079SRichard Henderson if (fpst->default_nan_mode) { 68037356079SRichard Henderson nan = float16_default_nan(fpst); 68137356079SRichard Henderson } 68237356079SRichard Henderson return nan; 68337356079SRichard Henderson } else if (float16_is_infinity(f16)) { 68437356079SRichard Henderson return float16_set_sign(float16_zero, float16_is_neg(f16)); 68537356079SRichard Henderson } else if (float16_is_zero(f16)) { 68637356079SRichard Henderson float_raise(float_flag_divbyzero, fpst); 68737356079SRichard Henderson return float16_set_sign(float16_infinity, float16_is_neg(f16)); 68837356079SRichard Henderson } else if (float16_abs(f16) < (1 << 8)) { 68937356079SRichard Henderson /* Abs(value) < 2.0^-16 */ 69037356079SRichard Henderson float_raise(float_flag_overflow | float_flag_inexact, fpst); 69137356079SRichard Henderson if (round_to_inf(fpst, f16_sign)) { 69237356079SRichard Henderson return float16_set_sign(float16_infinity, f16_sign); 69337356079SRichard Henderson } else { 69437356079SRichard Henderson return float16_set_sign(float16_maxnorm, f16_sign); 69537356079SRichard Henderson } 69637356079SRichard Henderson } else if (f16_exp >= 29 && fpst->flush_to_zero) { 69737356079SRichard Henderson float_raise(float_flag_underflow, fpst); 69837356079SRichard Henderson return float16_set_sign(float16_zero, float16_is_neg(f16)); 69937356079SRichard Henderson } 70037356079SRichard Henderson 70137356079SRichard Henderson f64_frac = call_recip_estimate(&f16_exp, 29, 70237356079SRichard Henderson ((uint64_t) f16_frac) << (52 - 10)); 70337356079SRichard Henderson 70437356079SRichard Henderson /* result = sign : result_exp<4:0> : fraction<51:42> */ 70537356079SRichard Henderson f16_val = deposit32(0, 15, 1, f16_sign); 70637356079SRichard Henderson f16_val = deposit32(f16_val, 10, 5, f16_exp); 70737356079SRichard Henderson f16_val = deposit32(f16_val, 0, 10, extract64(f64_frac, 52 - 10, 10)); 70837356079SRichard Henderson return make_float16(f16_val); 70937356079SRichard Henderson } 71037356079SRichard Henderson 71137356079SRichard Henderson float32 HELPER(recpe_f32)(float32 input, void *fpstp) 71237356079SRichard Henderson { 71337356079SRichard Henderson float_status *fpst = fpstp; 71437356079SRichard Henderson float32 f32 = float32_squash_input_denormal(input, fpst); 71537356079SRichard Henderson uint32_t f32_val = float32_val(f32); 71637356079SRichard Henderson bool f32_sign = float32_is_neg(f32); 71737356079SRichard Henderson int f32_exp = extract32(f32_val, 23, 8); 71837356079SRichard Henderson uint32_t f32_frac = extract32(f32_val, 0, 23); 71937356079SRichard Henderson uint64_t f64_frac; 72037356079SRichard Henderson 72137356079SRichard Henderson if (float32_is_any_nan(f32)) { 72237356079SRichard Henderson float32 nan = f32; 72337356079SRichard Henderson if (float32_is_signaling_nan(f32, fpst)) { 72437356079SRichard Henderson float_raise(float_flag_invalid, fpst); 725103e7579SJoe Komlodi if (!fpst->default_nan_mode) { 72637356079SRichard Henderson nan = float32_silence_nan(f32, fpst); 72737356079SRichard Henderson } 728103e7579SJoe Komlodi } 72937356079SRichard Henderson if (fpst->default_nan_mode) { 73037356079SRichard Henderson nan = float32_default_nan(fpst); 73137356079SRichard Henderson } 73237356079SRichard Henderson return nan; 73337356079SRichard Henderson } else if (float32_is_infinity(f32)) { 73437356079SRichard Henderson return float32_set_sign(float32_zero, float32_is_neg(f32)); 73537356079SRichard Henderson } else if (float32_is_zero(f32)) { 73637356079SRichard Henderson float_raise(float_flag_divbyzero, fpst); 73737356079SRichard Henderson return float32_set_sign(float32_infinity, float32_is_neg(f32)); 73837356079SRichard Henderson } else if (float32_abs(f32) < (1ULL << 21)) { 73937356079SRichard Henderson /* Abs(value) < 2.0^-128 */ 74037356079SRichard Henderson float_raise(float_flag_overflow | float_flag_inexact, fpst); 74137356079SRichard Henderson if (round_to_inf(fpst, f32_sign)) { 74237356079SRichard Henderson return float32_set_sign(float32_infinity, f32_sign); 74337356079SRichard Henderson } else { 74437356079SRichard Henderson return float32_set_sign(float32_maxnorm, f32_sign); 74537356079SRichard Henderson } 74637356079SRichard Henderson } else if (f32_exp >= 253 && fpst->flush_to_zero) { 74737356079SRichard Henderson float_raise(float_flag_underflow, fpst); 74837356079SRichard Henderson return float32_set_sign(float32_zero, float32_is_neg(f32)); 74937356079SRichard Henderson } 75037356079SRichard Henderson 75137356079SRichard Henderson f64_frac = call_recip_estimate(&f32_exp, 253, 75237356079SRichard Henderson ((uint64_t) f32_frac) << (52 - 23)); 75337356079SRichard Henderson 75437356079SRichard Henderson /* result = sign : result_exp<7:0> : fraction<51:29> */ 75537356079SRichard Henderson f32_val = deposit32(0, 31, 1, f32_sign); 75637356079SRichard Henderson f32_val = deposit32(f32_val, 23, 8, f32_exp); 75737356079SRichard Henderson f32_val = deposit32(f32_val, 0, 23, extract64(f64_frac, 52 - 23, 23)); 75837356079SRichard Henderson return make_float32(f32_val); 75937356079SRichard Henderson } 76037356079SRichard Henderson 76137356079SRichard Henderson float64 HELPER(recpe_f64)(float64 input, void *fpstp) 76237356079SRichard Henderson { 76337356079SRichard Henderson float_status *fpst = fpstp; 76437356079SRichard Henderson float64 f64 = float64_squash_input_denormal(input, fpst); 76537356079SRichard Henderson uint64_t f64_val = float64_val(f64); 76637356079SRichard Henderson bool f64_sign = float64_is_neg(f64); 76737356079SRichard Henderson int f64_exp = extract64(f64_val, 52, 11); 76837356079SRichard Henderson uint64_t f64_frac = extract64(f64_val, 0, 52); 76937356079SRichard Henderson 77037356079SRichard Henderson /* Deal with any special cases */ 77137356079SRichard Henderson if (float64_is_any_nan(f64)) { 77237356079SRichard Henderson float64 nan = f64; 77337356079SRichard Henderson if (float64_is_signaling_nan(f64, fpst)) { 77437356079SRichard Henderson float_raise(float_flag_invalid, fpst); 775103e7579SJoe Komlodi if (!fpst->default_nan_mode) { 77637356079SRichard Henderson nan = float64_silence_nan(f64, fpst); 77737356079SRichard Henderson } 778103e7579SJoe Komlodi } 77937356079SRichard Henderson if (fpst->default_nan_mode) { 78037356079SRichard Henderson nan = float64_default_nan(fpst); 78137356079SRichard Henderson } 78237356079SRichard Henderson return nan; 78337356079SRichard Henderson } else if (float64_is_infinity(f64)) { 78437356079SRichard Henderson return float64_set_sign(float64_zero, float64_is_neg(f64)); 78537356079SRichard Henderson } else if (float64_is_zero(f64)) { 78637356079SRichard Henderson float_raise(float_flag_divbyzero, fpst); 78737356079SRichard Henderson return float64_set_sign(float64_infinity, float64_is_neg(f64)); 78837356079SRichard Henderson } else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) { 78937356079SRichard Henderson /* Abs(value) < 2.0^-1024 */ 79037356079SRichard Henderson float_raise(float_flag_overflow | float_flag_inexact, fpst); 79137356079SRichard Henderson if (round_to_inf(fpst, f64_sign)) { 79237356079SRichard Henderson return float64_set_sign(float64_infinity, f64_sign); 79337356079SRichard Henderson } else { 79437356079SRichard Henderson return float64_set_sign(float64_maxnorm, f64_sign); 79537356079SRichard Henderson } 79637356079SRichard Henderson } else if (f64_exp >= 2045 && fpst->flush_to_zero) { 79737356079SRichard Henderson float_raise(float_flag_underflow, fpst); 79837356079SRichard Henderson return float64_set_sign(float64_zero, float64_is_neg(f64)); 79937356079SRichard Henderson } 80037356079SRichard Henderson 80137356079SRichard Henderson f64_frac = call_recip_estimate(&f64_exp, 2045, f64_frac); 80237356079SRichard Henderson 80337356079SRichard Henderson /* result = sign : result_exp<10:0> : fraction<51:0>; */ 80437356079SRichard Henderson f64_val = deposit64(0, 63, 1, f64_sign); 80537356079SRichard Henderson f64_val = deposit64(f64_val, 52, 11, f64_exp); 80637356079SRichard Henderson f64_val = deposit64(f64_val, 0, 52, f64_frac); 80737356079SRichard Henderson return make_float64(f64_val); 80837356079SRichard Henderson } 80937356079SRichard Henderson 81037356079SRichard Henderson /* The algorithm that must be used to calculate the estimate 81137356079SRichard Henderson * is specified by the ARM ARM. 81237356079SRichard Henderson */ 81337356079SRichard Henderson 81437356079SRichard Henderson static int do_recip_sqrt_estimate(int a) 81537356079SRichard Henderson { 81637356079SRichard Henderson int b, estimate; 81737356079SRichard Henderson 81837356079SRichard Henderson assert(128 <= a && a < 512); 81937356079SRichard Henderson if (a < 256) { 82037356079SRichard Henderson a = a * 2 + 1; 82137356079SRichard Henderson } else { 82237356079SRichard Henderson a = (a >> 1) << 1; 82337356079SRichard Henderson a = (a + 1) * 2; 82437356079SRichard Henderson } 82537356079SRichard Henderson b = 512; 82637356079SRichard Henderson while (a * (b + 1) * (b + 1) < (1 << 28)) { 82737356079SRichard Henderson b += 1; 82837356079SRichard Henderson } 82937356079SRichard Henderson estimate = (b + 1) / 2; 83037356079SRichard Henderson assert(256 <= estimate && estimate < 512); 83137356079SRichard Henderson 83237356079SRichard Henderson return estimate; 83337356079SRichard Henderson } 83437356079SRichard Henderson 83537356079SRichard Henderson 83637356079SRichard Henderson static uint64_t recip_sqrt_estimate(int *exp , int exp_off, uint64_t frac) 83737356079SRichard Henderson { 83837356079SRichard Henderson int estimate; 83937356079SRichard Henderson uint32_t scaled; 84037356079SRichard Henderson 84137356079SRichard Henderson if (*exp == 0) { 84237356079SRichard Henderson while (extract64(frac, 51, 1) == 0) { 84337356079SRichard Henderson frac = frac << 1; 84437356079SRichard Henderson *exp -= 1; 84537356079SRichard Henderson } 84637356079SRichard Henderson frac = extract64(frac, 0, 51) << 1; 84737356079SRichard Henderson } 84837356079SRichard Henderson 84937356079SRichard Henderson if (*exp & 1) { 85037356079SRichard Henderson /* scaled = UInt('01':fraction<51:45>) */ 85137356079SRichard Henderson scaled = deposit32(1 << 7, 0, 7, extract64(frac, 45, 7)); 85237356079SRichard Henderson } else { 85337356079SRichard Henderson /* scaled = UInt('1':fraction<51:44>) */ 85437356079SRichard Henderson scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); 85537356079SRichard Henderson } 85637356079SRichard Henderson estimate = do_recip_sqrt_estimate(scaled); 85737356079SRichard Henderson 85837356079SRichard Henderson *exp = (exp_off - *exp) / 2; 85937356079SRichard Henderson return extract64(estimate, 0, 8) << 44; 86037356079SRichard Henderson } 86137356079SRichard Henderson 86237356079SRichard Henderson uint32_t HELPER(rsqrte_f16)(uint32_t input, void *fpstp) 86337356079SRichard Henderson { 86437356079SRichard Henderson float_status *s = fpstp; 86537356079SRichard Henderson float16 f16 = float16_squash_input_denormal(input, s); 86637356079SRichard Henderson uint16_t val = float16_val(f16); 86737356079SRichard Henderson bool f16_sign = float16_is_neg(f16); 86837356079SRichard Henderson int f16_exp = extract32(val, 10, 5); 86937356079SRichard Henderson uint16_t f16_frac = extract32(val, 0, 10); 87037356079SRichard Henderson uint64_t f64_frac; 87137356079SRichard Henderson 87237356079SRichard Henderson if (float16_is_any_nan(f16)) { 87337356079SRichard Henderson float16 nan = f16; 87437356079SRichard Henderson if (float16_is_signaling_nan(f16, s)) { 87537356079SRichard Henderson float_raise(float_flag_invalid, s); 876103e7579SJoe Komlodi if (!s->default_nan_mode) { 877103e7579SJoe Komlodi nan = float16_silence_nan(f16, fpstp); 878103e7579SJoe Komlodi } 87937356079SRichard Henderson } 88037356079SRichard Henderson if (s->default_nan_mode) { 88137356079SRichard Henderson nan = float16_default_nan(s); 88237356079SRichard Henderson } 88337356079SRichard Henderson return nan; 88437356079SRichard Henderson } else if (float16_is_zero(f16)) { 88537356079SRichard Henderson float_raise(float_flag_divbyzero, s); 88637356079SRichard Henderson return float16_set_sign(float16_infinity, f16_sign); 88737356079SRichard Henderson } else if (f16_sign) { 88837356079SRichard Henderson float_raise(float_flag_invalid, s); 88937356079SRichard Henderson return float16_default_nan(s); 89037356079SRichard Henderson } else if (float16_is_infinity(f16)) { 89137356079SRichard Henderson return float16_zero; 89237356079SRichard Henderson } 89337356079SRichard Henderson 89437356079SRichard Henderson /* Scale and normalize to a double-precision value between 0.25 and 1.0, 89537356079SRichard Henderson * preserving the parity of the exponent. */ 89637356079SRichard Henderson 89737356079SRichard Henderson f64_frac = ((uint64_t) f16_frac) << (52 - 10); 89837356079SRichard Henderson 89937356079SRichard Henderson f64_frac = recip_sqrt_estimate(&f16_exp, 44, f64_frac); 90037356079SRichard Henderson 90137356079SRichard Henderson /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(2) */ 90237356079SRichard Henderson val = deposit32(0, 15, 1, f16_sign); 90337356079SRichard Henderson val = deposit32(val, 10, 5, f16_exp); 90437356079SRichard Henderson val = deposit32(val, 2, 8, extract64(f64_frac, 52 - 8, 8)); 90537356079SRichard Henderson return make_float16(val); 90637356079SRichard Henderson } 90737356079SRichard Henderson 90837356079SRichard Henderson float32 HELPER(rsqrte_f32)(float32 input, void *fpstp) 90937356079SRichard Henderson { 91037356079SRichard Henderson float_status *s = fpstp; 91137356079SRichard Henderson float32 f32 = float32_squash_input_denormal(input, s); 91237356079SRichard Henderson uint32_t val = float32_val(f32); 91337356079SRichard Henderson uint32_t f32_sign = float32_is_neg(f32); 91437356079SRichard Henderson int f32_exp = extract32(val, 23, 8); 91537356079SRichard Henderson uint32_t f32_frac = extract32(val, 0, 23); 91637356079SRichard Henderson uint64_t f64_frac; 91737356079SRichard Henderson 91837356079SRichard Henderson if (float32_is_any_nan(f32)) { 91937356079SRichard Henderson float32 nan = f32; 92037356079SRichard Henderson if (float32_is_signaling_nan(f32, s)) { 92137356079SRichard Henderson float_raise(float_flag_invalid, s); 922103e7579SJoe Komlodi if (!s->default_nan_mode) { 923103e7579SJoe Komlodi nan = float32_silence_nan(f32, fpstp); 924103e7579SJoe Komlodi } 92537356079SRichard Henderson } 92637356079SRichard Henderson if (s->default_nan_mode) { 92737356079SRichard Henderson nan = float32_default_nan(s); 92837356079SRichard Henderson } 92937356079SRichard Henderson return nan; 93037356079SRichard Henderson } else if (float32_is_zero(f32)) { 93137356079SRichard Henderson float_raise(float_flag_divbyzero, s); 93237356079SRichard Henderson return float32_set_sign(float32_infinity, float32_is_neg(f32)); 93337356079SRichard Henderson } else if (float32_is_neg(f32)) { 93437356079SRichard Henderson float_raise(float_flag_invalid, s); 93537356079SRichard Henderson return float32_default_nan(s); 93637356079SRichard Henderson } else if (float32_is_infinity(f32)) { 93737356079SRichard Henderson return float32_zero; 93837356079SRichard Henderson } 93937356079SRichard Henderson 94037356079SRichard Henderson /* Scale and normalize to a double-precision value between 0.25 and 1.0, 94137356079SRichard Henderson * preserving the parity of the exponent. */ 94237356079SRichard Henderson 94337356079SRichard Henderson f64_frac = ((uint64_t) f32_frac) << 29; 94437356079SRichard Henderson 94537356079SRichard Henderson f64_frac = recip_sqrt_estimate(&f32_exp, 380, f64_frac); 94637356079SRichard Henderson 94737356079SRichard Henderson /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(15) */ 94837356079SRichard Henderson val = deposit32(0, 31, 1, f32_sign); 94937356079SRichard Henderson val = deposit32(val, 23, 8, f32_exp); 95037356079SRichard Henderson val = deposit32(val, 15, 8, extract64(f64_frac, 52 - 8, 8)); 95137356079SRichard Henderson return make_float32(val); 95237356079SRichard Henderson } 95337356079SRichard Henderson 95437356079SRichard Henderson float64 HELPER(rsqrte_f64)(float64 input, void *fpstp) 95537356079SRichard Henderson { 95637356079SRichard Henderson float_status *s = fpstp; 95737356079SRichard Henderson float64 f64 = float64_squash_input_denormal(input, s); 95837356079SRichard Henderson uint64_t val = float64_val(f64); 95937356079SRichard Henderson bool f64_sign = float64_is_neg(f64); 96037356079SRichard Henderson int f64_exp = extract64(val, 52, 11); 96137356079SRichard Henderson uint64_t f64_frac = extract64(val, 0, 52); 96237356079SRichard Henderson 96337356079SRichard Henderson if (float64_is_any_nan(f64)) { 96437356079SRichard Henderson float64 nan = f64; 96537356079SRichard Henderson if (float64_is_signaling_nan(f64, s)) { 96637356079SRichard Henderson float_raise(float_flag_invalid, s); 967103e7579SJoe Komlodi if (!s->default_nan_mode) { 968103e7579SJoe Komlodi nan = float64_silence_nan(f64, fpstp); 969103e7579SJoe Komlodi } 97037356079SRichard Henderson } 97137356079SRichard Henderson if (s->default_nan_mode) { 97237356079SRichard Henderson nan = float64_default_nan(s); 97337356079SRichard Henderson } 97437356079SRichard Henderson return nan; 97537356079SRichard Henderson } else if (float64_is_zero(f64)) { 97637356079SRichard Henderson float_raise(float_flag_divbyzero, s); 97737356079SRichard Henderson return float64_set_sign(float64_infinity, float64_is_neg(f64)); 97837356079SRichard Henderson } else if (float64_is_neg(f64)) { 97937356079SRichard Henderson float_raise(float_flag_invalid, s); 98037356079SRichard Henderson return float64_default_nan(s); 98137356079SRichard Henderson } else if (float64_is_infinity(f64)) { 98237356079SRichard Henderson return float64_zero; 98337356079SRichard Henderson } 98437356079SRichard Henderson 98537356079SRichard Henderson f64_frac = recip_sqrt_estimate(&f64_exp, 3068, f64_frac); 98637356079SRichard Henderson 98737356079SRichard Henderson /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(44) */ 98837356079SRichard Henderson val = deposit64(0, 61, 1, f64_sign); 98937356079SRichard Henderson val = deposit64(val, 52, 11, f64_exp); 99037356079SRichard Henderson val = deposit64(val, 44, 8, extract64(f64_frac, 52 - 8, 8)); 99137356079SRichard Henderson return make_float64(val); 99237356079SRichard Henderson } 99337356079SRichard Henderson 994fe6fb4beSRichard Henderson uint32_t HELPER(recpe_u32)(uint32_t a) 99537356079SRichard Henderson { 99637356079SRichard Henderson int input, estimate; 99737356079SRichard Henderson 99837356079SRichard Henderson if ((a & 0x80000000) == 0) { 99937356079SRichard Henderson return 0xffffffff; 100037356079SRichard Henderson } 100137356079SRichard Henderson 100237356079SRichard Henderson input = extract32(a, 23, 9); 100337356079SRichard Henderson estimate = recip_estimate(input); 100437356079SRichard Henderson 100537356079SRichard Henderson return deposit32(0, (32 - 9), 9, estimate); 100637356079SRichard Henderson } 100737356079SRichard Henderson 1008fe6fb4beSRichard Henderson uint32_t HELPER(rsqrte_u32)(uint32_t a) 100937356079SRichard Henderson { 101037356079SRichard Henderson int estimate; 101137356079SRichard Henderson 101237356079SRichard Henderson if ((a & 0xc0000000) == 0) { 101337356079SRichard Henderson return 0xffffffff; 101437356079SRichard Henderson } 101537356079SRichard Henderson 101637356079SRichard Henderson estimate = do_recip_sqrt_estimate(extract32(a, 23, 9)); 101737356079SRichard Henderson 101837356079SRichard Henderson return deposit32(0, 23, 9, estimate); 101937356079SRichard Henderson } 102037356079SRichard Henderson 102137356079SRichard Henderson /* VFPv4 fused multiply-accumulate */ 10229886fe28SPeter Maydell dh_ctype_f16 VFP_HELPER(muladd, h)(dh_ctype_f16 a, dh_ctype_f16 b, 10239886fe28SPeter Maydell dh_ctype_f16 c, void *fpstp) 10249886fe28SPeter Maydell { 10259886fe28SPeter Maydell float_status *fpst = fpstp; 10269886fe28SPeter Maydell return float16_muladd(a, b, c, 0, fpst); 10279886fe28SPeter Maydell } 10289886fe28SPeter Maydell 102937356079SRichard Henderson float32 VFP_HELPER(muladd, s)(float32 a, float32 b, float32 c, void *fpstp) 103037356079SRichard Henderson { 103137356079SRichard Henderson float_status *fpst = fpstp; 103237356079SRichard Henderson return float32_muladd(a, b, c, 0, fpst); 103337356079SRichard Henderson } 103437356079SRichard Henderson 103537356079SRichard Henderson float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c, void *fpstp) 103637356079SRichard Henderson { 103737356079SRichard Henderson float_status *fpst = fpstp; 103837356079SRichard Henderson return float64_muladd(a, b, c, 0, fpst); 103937356079SRichard Henderson } 104037356079SRichard Henderson 104137356079SRichard Henderson /* ARMv8 round to integral */ 10420a6f4b4cSPeter Maydell dh_ctype_f16 HELPER(rinth_exact)(dh_ctype_f16 x, void *fp_status) 10430a6f4b4cSPeter Maydell { 10440a6f4b4cSPeter Maydell return float16_round_to_int(x, fp_status); 10450a6f4b4cSPeter Maydell } 10460a6f4b4cSPeter Maydell 104737356079SRichard Henderson float32 HELPER(rints_exact)(float32 x, void *fp_status) 104837356079SRichard Henderson { 104937356079SRichard Henderson return float32_round_to_int(x, fp_status); 105037356079SRichard Henderson } 105137356079SRichard Henderson 105237356079SRichard Henderson float64 HELPER(rintd_exact)(float64 x, void *fp_status) 105337356079SRichard Henderson { 105437356079SRichard Henderson return float64_round_to_int(x, fp_status); 105537356079SRichard Henderson } 105637356079SRichard Henderson 10570a6f4b4cSPeter Maydell dh_ctype_f16 HELPER(rinth)(dh_ctype_f16 x, void *fp_status) 10580a6f4b4cSPeter Maydell { 10590a6f4b4cSPeter Maydell int old_flags = get_float_exception_flags(fp_status), new_flags; 10600a6f4b4cSPeter Maydell float16 ret; 10610a6f4b4cSPeter Maydell 10620a6f4b4cSPeter Maydell ret = float16_round_to_int(x, fp_status); 10630a6f4b4cSPeter Maydell 10640a6f4b4cSPeter Maydell /* Suppress any inexact exceptions the conversion produced */ 10650a6f4b4cSPeter Maydell if (!(old_flags & float_flag_inexact)) { 10660a6f4b4cSPeter Maydell new_flags = get_float_exception_flags(fp_status); 10670a6f4b4cSPeter Maydell set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); 10680a6f4b4cSPeter Maydell } 10690a6f4b4cSPeter Maydell 10700a6f4b4cSPeter Maydell return ret; 10710a6f4b4cSPeter Maydell } 10720a6f4b4cSPeter Maydell 107337356079SRichard Henderson float32 HELPER(rints)(float32 x, void *fp_status) 107437356079SRichard Henderson { 107537356079SRichard Henderson int old_flags = get_float_exception_flags(fp_status), new_flags; 107637356079SRichard Henderson float32 ret; 107737356079SRichard Henderson 107837356079SRichard Henderson ret = float32_round_to_int(x, fp_status); 107937356079SRichard Henderson 108037356079SRichard Henderson /* Suppress any inexact exceptions the conversion produced */ 108137356079SRichard Henderson if (!(old_flags & float_flag_inexact)) { 108237356079SRichard Henderson new_flags = get_float_exception_flags(fp_status); 108337356079SRichard Henderson set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); 108437356079SRichard Henderson } 108537356079SRichard Henderson 108637356079SRichard Henderson return ret; 108737356079SRichard Henderson } 108837356079SRichard Henderson 108937356079SRichard Henderson float64 HELPER(rintd)(float64 x, void *fp_status) 109037356079SRichard Henderson { 109137356079SRichard Henderson int old_flags = get_float_exception_flags(fp_status), new_flags; 109237356079SRichard Henderson float64 ret; 109337356079SRichard Henderson 109437356079SRichard Henderson ret = float64_round_to_int(x, fp_status); 109537356079SRichard Henderson 109637356079SRichard Henderson new_flags = get_float_exception_flags(fp_status); 109737356079SRichard Henderson 109837356079SRichard Henderson /* Suppress any inexact exceptions the conversion produced */ 109937356079SRichard Henderson if (!(old_flags & float_flag_inexact)) { 110037356079SRichard Henderson new_flags = get_float_exception_flags(fp_status); 110137356079SRichard Henderson set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); 110237356079SRichard Henderson } 110337356079SRichard Henderson 110437356079SRichard Henderson return ret; 110537356079SRichard Henderson } 110637356079SRichard Henderson 110737356079SRichard Henderson /* Convert ARM rounding mode to softfloat */ 11086ce21abdSRichard Henderson const FloatRoundMode arm_rmode_to_sf_map[] = { 11096ce21abdSRichard Henderson [FPROUNDING_TIEEVEN] = float_round_nearest_even, 11106ce21abdSRichard Henderson [FPROUNDING_POSINF] = float_round_up, 11116ce21abdSRichard Henderson [FPROUNDING_NEGINF] = float_round_down, 11126ce21abdSRichard Henderson [FPROUNDING_ZERO] = float_round_to_zero, 11136ce21abdSRichard Henderson [FPROUNDING_TIEAWAY] = float_round_ties_away, 11146ce21abdSRichard Henderson [FPROUNDING_ODD] = float_round_to_odd, 11156ce21abdSRichard Henderson }; 11166c1f6f27SRichard Henderson 11176c1f6f27SRichard Henderson /* 11186c1f6f27SRichard Henderson * Implement float64 to int32_t conversion without saturation; 11196c1f6f27SRichard Henderson * the result is supplied modulo 2^32. 11206c1f6f27SRichard Henderson */ 11216c1f6f27SRichard Henderson uint64_t HELPER(fjcvtzs)(float64 value, void *vstatus) 11226c1f6f27SRichard Henderson { 11236c1f6f27SRichard Henderson float_status *status = vstatus; 112434d03ad9SRichard Henderson uint32_t inexact, frac; 112534d03ad9SRichard Henderson uint32_t e_old, e_new; 11266c1f6f27SRichard Henderson 112734d03ad9SRichard Henderson e_old = get_float_exception_flags(status); 112834d03ad9SRichard Henderson set_float_exception_flags(0, status); 112934d03ad9SRichard Henderson frac = float64_to_int32_modulo(value, float_round_to_zero, status); 113034d03ad9SRichard Henderson e_new = get_float_exception_flags(status); 113134d03ad9SRichard Henderson set_float_exception_flags(e_old | e_new, status); 11326c1f6f27SRichard Henderson 113334d03ad9SRichard Henderson if (value == float64_chs(float64_zero)) { 11346c1f6f27SRichard Henderson /* While not inexact for IEEE FP, -0.0 is inexact for JavaScript. */ 11356c1f6f27SRichard Henderson inexact = 1; 11366c1f6f27SRichard Henderson } else { 113734d03ad9SRichard Henderson /* Normal inexact or overflow or NaN */ 113834d03ad9SRichard Henderson inexact = e_new & (float_flag_inexact | float_flag_invalid); 11396c1f6f27SRichard Henderson } 11406c1f6f27SRichard Henderson 11416c1f6f27SRichard Henderson /* Pack the result and the env->ZF representation of Z together. */ 11426c1f6f27SRichard Henderson return deposit64(frac, 32, 32, inexact); 11436c1f6f27SRichard Henderson } 11446c1f6f27SRichard Henderson 11456c1f6f27SRichard Henderson uint32_t HELPER(vjcvt)(float64 value, CPUARMState *env) 11466c1f6f27SRichard Henderson { 11476c1f6f27SRichard Henderson uint64_t pair = HELPER(fjcvtzs)(value, &env->vfp.fp_status); 11486c1f6f27SRichard Henderson uint32_t result = pair; 11496c1f6f27SRichard Henderson uint32_t z = (pair >> 32) == 0; 11506c1f6f27SRichard Henderson 11516c1f6f27SRichard Henderson /* Store Z, clear NCV, in FPSCR.NZCV. */ 11526c1f6f27SRichard Henderson env->vfp.xregs[ARM_VFP_FPSCR] 11536c1f6f27SRichard Henderson = (env->vfp.xregs[ARM_VFP_FPSCR] & ~CPSR_NZCV) | (z * CPSR_Z); 11546c1f6f27SRichard Henderson 11556c1f6f27SRichard Henderson return result; 11566c1f6f27SRichard Henderson } 11576bea2563SRichard Henderson 11586bea2563SRichard Henderson /* Round a float32 to an integer that fits in int32_t or int64_t. */ 11596bea2563SRichard Henderson static float32 frint_s(float32 f, float_status *fpst, int intsize) 11606bea2563SRichard Henderson { 11616bea2563SRichard Henderson int old_flags = get_float_exception_flags(fpst); 11626bea2563SRichard Henderson uint32_t exp = extract32(f, 23, 8); 11636bea2563SRichard Henderson 11646bea2563SRichard Henderson if (unlikely(exp == 0xff)) { 11656bea2563SRichard Henderson /* NaN or Inf. */ 11666bea2563SRichard Henderson goto overflow; 11676bea2563SRichard Henderson } 11686bea2563SRichard Henderson 11696bea2563SRichard Henderson /* Round and re-extract the exponent. */ 11706bea2563SRichard Henderson f = float32_round_to_int(f, fpst); 11716bea2563SRichard Henderson exp = extract32(f, 23, 8); 11726bea2563SRichard Henderson 11736bea2563SRichard Henderson /* Validate the range of the result. */ 11746bea2563SRichard Henderson if (exp < 126 + intsize) { 11756bea2563SRichard Henderson /* abs(F) <= INT{N}_MAX */ 11766bea2563SRichard Henderson return f; 11776bea2563SRichard Henderson } 11786bea2563SRichard Henderson if (exp == 126 + intsize) { 11796bea2563SRichard Henderson uint32_t sign = extract32(f, 31, 1); 11806bea2563SRichard Henderson uint32_t frac = extract32(f, 0, 23); 11816bea2563SRichard Henderson if (sign && frac == 0) { 11826bea2563SRichard Henderson /* F == INT{N}_MIN */ 11836bea2563SRichard Henderson return f; 11846bea2563SRichard Henderson } 11856bea2563SRichard Henderson } 11866bea2563SRichard Henderson 11876bea2563SRichard Henderson overflow: 11886bea2563SRichard Henderson /* 11896bea2563SRichard Henderson * Raise Invalid and return INT{N}_MIN as a float. Revert any 11906bea2563SRichard Henderson * inexact exception float32_round_to_int may have raised. 11916bea2563SRichard Henderson */ 11926bea2563SRichard Henderson set_float_exception_flags(old_flags | float_flag_invalid, fpst); 11936bea2563SRichard Henderson return (0x100u + 126u + intsize) << 23; 11946bea2563SRichard Henderson } 11956bea2563SRichard Henderson 11966bea2563SRichard Henderson float32 HELPER(frint32_s)(float32 f, void *fpst) 11976bea2563SRichard Henderson { 11986bea2563SRichard Henderson return frint_s(f, fpst, 32); 11996bea2563SRichard Henderson } 12006bea2563SRichard Henderson 12016bea2563SRichard Henderson float32 HELPER(frint64_s)(float32 f, void *fpst) 12026bea2563SRichard Henderson { 12036bea2563SRichard Henderson return frint_s(f, fpst, 64); 12046bea2563SRichard Henderson } 12056bea2563SRichard Henderson 12066bea2563SRichard Henderson /* Round a float64 to an integer that fits in int32_t or int64_t. */ 12076bea2563SRichard Henderson static float64 frint_d(float64 f, float_status *fpst, int intsize) 12086bea2563SRichard Henderson { 12096bea2563SRichard Henderson int old_flags = get_float_exception_flags(fpst); 12106bea2563SRichard Henderson uint32_t exp = extract64(f, 52, 11); 12116bea2563SRichard Henderson 12126bea2563SRichard Henderson if (unlikely(exp == 0x7ff)) { 12136bea2563SRichard Henderson /* NaN or Inf. */ 12146bea2563SRichard Henderson goto overflow; 12156bea2563SRichard Henderson } 12166bea2563SRichard Henderson 12176bea2563SRichard Henderson /* Round and re-extract the exponent. */ 12186bea2563SRichard Henderson f = float64_round_to_int(f, fpst); 12196bea2563SRichard Henderson exp = extract64(f, 52, 11); 12206bea2563SRichard Henderson 12216bea2563SRichard Henderson /* Validate the range of the result. */ 12226bea2563SRichard Henderson if (exp < 1022 + intsize) { 12236bea2563SRichard Henderson /* abs(F) <= INT{N}_MAX */ 12246bea2563SRichard Henderson return f; 12256bea2563SRichard Henderson } 12266bea2563SRichard Henderson if (exp == 1022 + intsize) { 12276bea2563SRichard Henderson uint64_t sign = extract64(f, 63, 1); 12286bea2563SRichard Henderson uint64_t frac = extract64(f, 0, 52); 12296bea2563SRichard Henderson if (sign && frac == 0) { 12306bea2563SRichard Henderson /* F == INT{N}_MIN */ 12316bea2563SRichard Henderson return f; 12326bea2563SRichard Henderson } 12336bea2563SRichard Henderson } 12346bea2563SRichard Henderson 12356bea2563SRichard Henderson overflow: 12366bea2563SRichard Henderson /* 12376bea2563SRichard Henderson * Raise Invalid and return INT{N}_MIN as a float. Revert any 12386bea2563SRichard Henderson * inexact exception float64_round_to_int may have raised. 12396bea2563SRichard Henderson */ 12406bea2563SRichard Henderson set_float_exception_flags(old_flags | float_flag_invalid, fpst); 12416bea2563SRichard Henderson return (uint64_t)(0x800 + 1022 + intsize) << 52; 12426bea2563SRichard Henderson } 12436bea2563SRichard Henderson 12446bea2563SRichard Henderson float64 HELPER(frint32_d)(float64 f, void *fpst) 12456bea2563SRichard Henderson { 12466bea2563SRichard Henderson return frint_d(f, fpst, 32); 12476bea2563SRichard Henderson } 12486bea2563SRichard Henderson 12496bea2563SRichard Henderson float64 HELPER(frint64_d)(float64 f, void *fpst) 12506bea2563SRichard Henderson { 12516bea2563SRichard Henderson return frint_d(f, fpst, 64); 12526bea2563SRichard Henderson } 12534a15527cSPhilippe Mathieu-Daudé 12549ca1d776SMarc Zyngier void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg) 12559ca1d776SMarc Zyngier { 12569ca1d776SMarc Zyngier uint32_t syndrome; 12579ca1d776SMarc Zyngier 12589ca1d776SMarc Zyngier switch (reg) { 12599ca1d776SMarc Zyngier case ARM_VFP_MVFR0: 12609ca1d776SMarc Zyngier case ARM_VFP_MVFR1: 12619ca1d776SMarc Zyngier case ARM_VFP_MVFR2: 12629ca1d776SMarc Zyngier if (!(arm_hcr_el2_eff(env) & HCR_TID3)) { 12639ca1d776SMarc Zyngier return; 12649ca1d776SMarc Zyngier } 12659ca1d776SMarc Zyngier break; 12669ca1d776SMarc Zyngier case ARM_VFP_FPSID: 12679ca1d776SMarc Zyngier if (!(arm_hcr_el2_eff(env) & HCR_TID0)) { 12689ca1d776SMarc Zyngier return; 12699ca1d776SMarc Zyngier } 12709ca1d776SMarc Zyngier break; 12719ca1d776SMarc Zyngier default: 12729ca1d776SMarc Zyngier g_assert_not_reached(); 12739ca1d776SMarc Zyngier } 12749ca1d776SMarc Zyngier 12759ca1d776SMarc Zyngier syndrome = ((EC_FPIDTRAP << ARM_EL_EC_SHIFT) 12769ca1d776SMarc Zyngier | ARM_EL_IL 12779ca1d776SMarc Zyngier | (1 << 24) | (0xe << 20) | (7 << 14) 12789ca1d776SMarc Zyngier | (reg << 10) | (rt << 5) | 1); 12799ca1d776SMarc Zyngier 12809ca1d776SMarc Zyngier raise_exception(env, EXCP_HYP_TRAP, syndrome, 2); 12819ca1d776SMarc Zyngier } 12829ca1d776SMarc Zyngier 12834a15527cSPhilippe Mathieu-Daudé #endif 1284