13a0eae85SDavid Hildenbrand /* 23a0eae85SDavid Hildenbrand * QEMU TCG support -- s390x vector floating point instruction support 33a0eae85SDavid Hildenbrand * 43a0eae85SDavid Hildenbrand * Copyright (C) 2019 Red Hat Inc 53a0eae85SDavid Hildenbrand * 63a0eae85SDavid Hildenbrand * Authors: 73a0eae85SDavid Hildenbrand * David Hildenbrand <david@redhat.com> 83a0eae85SDavid Hildenbrand * 93a0eae85SDavid Hildenbrand * This work is licensed under the terms of the GNU GPL, version 2 or later. 103a0eae85SDavid Hildenbrand * See the COPYING file in the top-level directory. 113a0eae85SDavid Hildenbrand */ 123a0eae85SDavid Hildenbrand #include "qemu/osdep.h" 133a0eae85SDavid Hildenbrand #include "qemu-common.h" 143a0eae85SDavid Hildenbrand #include "cpu.h" 153a0eae85SDavid Hildenbrand #include "internal.h" 163a0eae85SDavid Hildenbrand #include "vec.h" 173a0eae85SDavid Hildenbrand #include "tcg_s390x.h" 183a0eae85SDavid Hildenbrand #include "tcg/tcg-gvec-desc.h" 193a0eae85SDavid Hildenbrand #include "exec/exec-all.h" 203a0eae85SDavid Hildenbrand #include "exec/helper-proto.h" 213a0eae85SDavid Hildenbrand #include "fpu/softfloat.h" 223a0eae85SDavid Hildenbrand 233a0eae85SDavid Hildenbrand #define VIC_INVALID 0x1 243a0eae85SDavid Hildenbrand #define VIC_DIVBYZERO 0x2 253a0eae85SDavid Hildenbrand #define VIC_OVERFLOW 0x3 263a0eae85SDavid Hildenbrand #define VIC_UNDERFLOW 0x4 273a0eae85SDavid Hildenbrand #define VIC_INEXACT 0x5 283a0eae85SDavid Hildenbrand 293a0eae85SDavid Hildenbrand /* returns the VEX. If the VEX is 0, there is no trap */ 303a0eae85SDavid Hildenbrand static uint8_t check_ieee_exc(CPUS390XState *env, uint8_t enr, bool XxC, 313a0eae85SDavid Hildenbrand uint8_t *vec_exc) 323a0eae85SDavid Hildenbrand { 333a0eae85SDavid Hildenbrand uint8_t vece_exc = 0, trap_exc; 343a0eae85SDavid Hildenbrand unsigned qemu_exc; 353a0eae85SDavid Hildenbrand 363a0eae85SDavid Hildenbrand /* Retrieve and clear the softfloat exceptions */ 373a0eae85SDavid Hildenbrand qemu_exc = env->fpu_status.float_exception_flags; 383a0eae85SDavid Hildenbrand if (qemu_exc == 0) { 393a0eae85SDavid Hildenbrand return 0; 403a0eae85SDavid Hildenbrand } 413a0eae85SDavid Hildenbrand env->fpu_status.float_exception_flags = 0; 423a0eae85SDavid Hildenbrand 433a0eae85SDavid Hildenbrand vece_exc = s390_softfloat_exc_to_ieee(qemu_exc); 443a0eae85SDavid Hildenbrand 453a0eae85SDavid Hildenbrand /* Add them to the vector-wide s390x exception bits */ 463a0eae85SDavid Hildenbrand *vec_exc |= vece_exc; 473a0eae85SDavid Hildenbrand 483a0eae85SDavid Hildenbrand /* Check for traps and construct the VXC */ 493a0eae85SDavid Hildenbrand trap_exc = vece_exc & env->fpc >> 24; 503a0eae85SDavid Hildenbrand if (trap_exc) { 513a0eae85SDavid Hildenbrand if (trap_exc & S390_IEEE_MASK_INVALID) { 523a0eae85SDavid Hildenbrand return enr << 4 | VIC_INVALID; 533a0eae85SDavid Hildenbrand } else if (trap_exc & S390_IEEE_MASK_DIVBYZERO) { 543a0eae85SDavid Hildenbrand return enr << 4 | VIC_DIVBYZERO; 553a0eae85SDavid Hildenbrand } else if (trap_exc & S390_IEEE_MASK_OVERFLOW) { 563a0eae85SDavid Hildenbrand return enr << 4 | VIC_OVERFLOW; 573a0eae85SDavid Hildenbrand } else if (trap_exc & S390_IEEE_MASK_UNDERFLOW) { 583a0eae85SDavid Hildenbrand return enr << 4 | VIC_UNDERFLOW; 593a0eae85SDavid Hildenbrand } else if (!XxC) { 603a0eae85SDavid Hildenbrand g_assert(trap_exc & S390_IEEE_MASK_INEXACT); 613a0eae85SDavid Hildenbrand /* inexact has lowest priority on traps */ 623a0eae85SDavid Hildenbrand return enr << 4 | VIC_INEXACT; 633a0eae85SDavid Hildenbrand } 643a0eae85SDavid Hildenbrand } 653a0eae85SDavid Hildenbrand return 0; 663a0eae85SDavid Hildenbrand } 673a0eae85SDavid Hildenbrand 683a0eae85SDavid Hildenbrand static void handle_ieee_exc(CPUS390XState *env, uint8_t vxc, uint8_t vec_exc, 693a0eae85SDavid Hildenbrand uintptr_t retaddr) 703a0eae85SDavid Hildenbrand { 713a0eae85SDavid Hildenbrand if (vxc) { 723a0eae85SDavid Hildenbrand /* on traps, the fpc flags are not updated, instruction is suppressed */ 733a0eae85SDavid Hildenbrand tcg_s390_vector_exception(env, vxc, retaddr); 743a0eae85SDavid Hildenbrand } 753a0eae85SDavid Hildenbrand if (vec_exc) { 763a0eae85SDavid Hildenbrand /* indicate exceptions for all elements combined */ 773a0eae85SDavid Hildenbrand env->fpc |= vec_exc << 16; 783a0eae85SDavid Hildenbrand } 793a0eae85SDavid Hildenbrand } 803a0eae85SDavid Hildenbrand 81863b9507SDavid Hildenbrand static float64 s390_vec_read_float64(const S390Vector *v, uint8_t enr) 82863b9507SDavid Hildenbrand { 83863b9507SDavid Hildenbrand return make_float64(s390_vec_read_element64(v, enr)); 84863b9507SDavid Hildenbrand } 85863b9507SDavid Hildenbrand 86863b9507SDavid Hildenbrand static void s390_vec_write_float64(S390Vector *v, uint8_t enr, float64 data) 87863b9507SDavid Hildenbrand { 88863b9507SDavid Hildenbrand return s390_vec_write_element64(v, enr, data); 89863b9507SDavid Hildenbrand } 90863b9507SDavid Hildenbrand 9121bd6ea2SDavid Hildenbrand typedef float64 (*vop64_2_fn)(float64 a, float_status *s); 92bb03fd84SDavid Hildenbrand static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 93bb03fd84SDavid Hildenbrand bool s, bool XxC, uint8_t erm, vop64_2_fn fn, 94bb03fd84SDavid Hildenbrand uintptr_t retaddr) 95bb03fd84SDavid Hildenbrand { 96bb03fd84SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 97bb03fd84SDavid Hildenbrand S390Vector tmp = {}; 98bb03fd84SDavid Hildenbrand int i, old_mode; 99bb03fd84SDavid Hildenbrand 100bb03fd84SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 101bb03fd84SDavid Hildenbrand for (i = 0; i < 2; i++) { 10221bd6ea2SDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 103bb03fd84SDavid Hildenbrand 10421bd6ea2SDavid Hildenbrand s390_vec_write_float64(&tmp, i, fn(a, &env->fpu_status)); 105bb03fd84SDavid Hildenbrand vxc = check_ieee_exc(env, i, XxC, &vec_exc); 106bb03fd84SDavid Hildenbrand if (s || vxc) { 107bb03fd84SDavid Hildenbrand break; 108bb03fd84SDavid Hildenbrand } 109bb03fd84SDavid Hildenbrand } 110bb03fd84SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 111bb03fd84SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 112bb03fd84SDavid Hildenbrand *v1 = tmp; 113bb03fd84SDavid Hildenbrand } 114bb03fd84SDavid Hildenbrand 11521bd6ea2SDavid Hildenbrand static float64 vcdg64(float64 a, float_status *s) 11621bd6ea2SDavid Hildenbrand { 11721bd6ea2SDavid Hildenbrand return int64_to_float64(a, s); 11821bd6ea2SDavid Hildenbrand } 11921bd6ea2SDavid Hildenbrand 12021bd6ea2SDavid Hildenbrand static float64 vcdlg64(float64 a, float_status *s) 12121bd6ea2SDavid Hildenbrand { 12221bd6ea2SDavid Hildenbrand return uint64_to_float64(a, s); 12321bd6ea2SDavid Hildenbrand } 12421bd6ea2SDavid Hildenbrand 12521bd6ea2SDavid Hildenbrand static float64 vcgd64(float64 a, float_status *s) 12621bd6ea2SDavid Hildenbrand { 12721bd6ea2SDavid Hildenbrand const float64 tmp = float64_to_int64(a, s); 12821bd6ea2SDavid Hildenbrand 12921bd6ea2SDavid Hildenbrand return float64_is_any_nan(a) ? INT64_MIN : tmp; 13021bd6ea2SDavid Hildenbrand } 13121bd6ea2SDavid Hildenbrand 13221bd6ea2SDavid Hildenbrand static float64 vclgd64(float64 a, float_status *s) 13321bd6ea2SDavid Hildenbrand { 13421bd6ea2SDavid Hildenbrand const float64 tmp = float64_to_uint64(a, s); 13521bd6ea2SDavid Hildenbrand 13621bd6ea2SDavid Hildenbrand return float64_is_any_nan(a) ? 0 : tmp; 13721bd6ea2SDavid Hildenbrand } 13821bd6ea2SDavid Hildenbrand 13921bd6ea2SDavid Hildenbrand #define DEF_GVEC_VOP2_FN(NAME, FN, BITS) \ 14021bd6ea2SDavid Hildenbrand void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, CPUS390XState *env, \ 14121bd6ea2SDavid Hildenbrand uint32_t desc) \ 14221bd6ea2SDavid Hildenbrand { \ 14321bd6ea2SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); \ 14421bd6ea2SDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 14521bd6ea2SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); \ 14621bd6ea2SDavid Hildenbrand \ 14721bd6ea2SDavid Hildenbrand vop##BITS##_2(v1, v2, env, se, XxC, erm, FN, GETPC()); \ 14821bd6ea2SDavid Hildenbrand } 14921bd6ea2SDavid Hildenbrand 15021bd6ea2SDavid Hildenbrand #define DEF_GVEC_VOP2_64(NAME) \ 15121bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_FN(NAME, NAME##64, 64) 15221bd6ea2SDavid Hildenbrand 15321bd6ea2SDavid Hildenbrand #define DEF_GVEC_VOP2(NAME, OP) \ 15421bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64) 15521bd6ea2SDavid Hildenbrand 15621bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_64(vcdg) 15721bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_64(vcdlg) 15821bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_64(vcgd) 15921bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_64(vclgd) 16021bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2(vfi, round_to_int) 16121bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2(vfsq, sqrt) 16221bd6ea2SDavid Hildenbrand 163863b9507SDavid Hildenbrand typedef float64 (*vop64_3_fn)(float64 a, float64 b, float_status *s); 1643a0eae85SDavid Hildenbrand static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 1653a0eae85SDavid Hildenbrand CPUS390XState *env, bool s, vop64_3_fn fn, 1663a0eae85SDavid Hildenbrand uintptr_t retaddr) 1673a0eae85SDavid Hildenbrand { 1683a0eae85SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 1693a0eae85SDavid Hildenbrand S390Vector tmp = {}; 1703a0eae85SDavid Hildenbrand int i; 1713a0eae85SDavid Hildenbrand 1723a0eae85SDavid Hildenbrand for (i = 0; i < 2; i++) { 173863b9507SDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 174863b9507SDavid Hildenbrand const float64 b = s390_vec_read_float64(v3, i); 1753a0eae85SDavid Hildenbrand 176863b9507SDavid Hildenbrand s390_vec_write_float64(&tmp, i, fn(a, b, &env->fpu_status)); 1773a0eae85SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 1783a0eae85SDavid Hildenbrand if (s || vxc) { 1793a0eae85SDavid Hildenbrand break; 1803a0eae85SDavid Hildenbrand } 1813a0eae85SDavid Hildenbrand } 1823a0eae85SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 1833a0eae85SDavid Hildenbrand *v1 = tmp; 1843a0eae85SDavid Hildenbrand } 1853a0eae85SDavid Hildenbrand 186863b9507SDavid Hildenbrand #define DEF_GVEC_VOP3(NAME, OP) \ 187863b9507SDavid Hildenbrand void HELPER(gvec_##NAME##64)(void *v1, const void *v2, const void *v3, \ 188863b9507SDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 189863b9507SDavid Hildenbrand { \ 190863b9507SDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 191863b9507SDavid Hildenbrand \ 192863b9507SDavid Hildenbrand vop64_3(v1, v2, v3, env, se, float64_##OP, GETPC()); \ 1933a0eae85SDavid Hildenbrand } 1943a0eae85SDavid Hildenbrand 195863b9507SDavid Hildenbrand DEF_GVEC_VOP3(vfa, add) 196863b9507SDavid Hildenbrand DEF_GVEC_VOP3(vfs, sub) 197863b9507SDavid Hildenbrand DEF_GVEC_VOP3(vfd, div) 198863b9507SDavid Hildenbrand DEF_GVEC_VOP3(vfm, mul) 1995b89f0fbSDavid Hildenbrand 2005b89f0fbSDavid Hildenbrand static int wfc64(const S390Vector *v1, const S390Vector *v2, 2015b89f0fbSDavid Hildenbrand CPUS390XState *env, bool signal, uintptr_t retaddr) 2025b89f0fbSDavid Hildenbrand { 2035b89f0fbSDavid Hildenbrand /* only the zero-indexed elements are compared */ 2045b89f0fbSDavid Hildenbrand const float64 a = s390_vec_read_element64(v1, 0); 2055b89f0fbSDavid Hildenbrand const float64 b = s390_vec_read_element64(v2, 0); 2065b89f0fbSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 2075b89f0fbSDavid Hildenbrand int cmp; 2085b89f0fbSDavid Hildenbrand 2095b89f0fbSDavid Hildenbrand if (signal) { 2105b89f0fbSDavid Hildenbrand cmp = float64_compare(a, b, &env->fpu_status); 2115b89f0fbSDavid Hildenbrand } else { 2125b89f0fbSDavid Hildenbrand cmp = float64_compare_quiet(a, b, &env->fpu_status); 2135b89f0fbSDavid Hildenbrand } 2145b89f0fbSDavid Hildenbrand vxc = check_ieee_exc(env, 0, false, &vec_exc); 2155b89f0fbSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 2165b89f0fbSDavid Hildenbrand 2175b89f0fbSDavid Hildenbrand return float_comp_to_cc(env, cmp); 2185b89f0fbSDavid Hildenbrand } 2195b89f0fbSDavid Hildenbrand 2205b89f0fbSDavid Hildenbrand void HELPER(gvec_wfc64)(const void *v1, const void *v2, CPUS390XState *env, 2215b89f0fbSDavid Hildenbrand uint32_t desc) 2225b89f0fbSDavid Hildenbrand { 2235b89f0fbSDavid Hildenbrand env->cc_op = wfc64(v1, v2, env, false, GETPC()); 2245b89f0fbSDavid Hildenbrand } 2255b89f0fbSDavid Hildenbrand 2265b89f0fbSDavid Hildenbrand void HELPER(gvec_wfk64)(const void *v1, const void *v2, CPUS390XState *env, 2275b89f0fbSDavid Hildenbrand uint32_t desc) 2285b89f0fbSDavid Hildenbrand { 2295b89f0fbSDavid Hildenbrand env->cc_op = wfc64(v1, v2, env, true, GETPC()); 2305b89f0fbSDavid Hildenbrand } 2312c806ab4SDavid Hildenbrand 2320673ecdfSRichard Henderson typedef bool (*vfc64_fn)(float64 a, float64 b, float_status *status); 2332c806ab4SDavid Hildenbrand static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 2342c806ab4SDavid Hildenbrand CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr) 2352c806ab4SDavid Hildenbrand { 2362c806ab4SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 2372c806ab4SDavid Hildenbrand S390Vector tmp = {}; 2382c806ab4SDavid Hildenbrand int match = 0; 2392c806ab4SDavid Hildenbrand int i; 2402c806ab4SDavid Hildenbrand 2412c806ab4SDavid Hildenbrand for (i = 0; i < 2; i++) { 242*64deb65aSDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 243*64deb65aSDavid Hildenbrand const float64 b = s390_vec_read_float64(v3, i); 2442c806ab4SDavid Hildenbrand 2452c806ab4SDavid Hildenbrand /* swap the order of the parameters, so we can use existing functions */ 2462c806ab4SDavid Hildenbrand if (fn(b, a, &env->fpu_status)) { 2472c806ab4SDavid Hildenbrand match++; 2482c806ab4SDavid Hildenbrand s390_vec_write_element64(&tmp, i, -1ull); 2492c806ab4SDavid Hildenbrand } 2502c806ab4SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 2512c806ab4SDavid Hildenbrand if (s || vxc) { 2522c806ab4SDavid Hildenbrand break; 2532c806ab4SDavid Hildenbrand } 2542c806ab4SDavid Hildenbrand } 2552c806ab4SDavid Hildenbrand 2562c806ab4SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 2572c806ab4SDavid Hildenbrand *v1 = tmp; 2582c806ab4SDavid Hildenbrand if (match) { 2592c806ab4SDavid Hildenbrand return s || match == 2 ? 0 : 1; 2602c806ab4SDavid Hildenbrand } 2612c806ab4SDavid Hildenbrand return 3; 2622c806ab4SDavid Hildenbrand } 2632c806ab4SDavid Hildenbrand 264*64deb65aSDavid Hildenbrand #define DEF_GVEC_VFC_B(NAME, OP, BITS) \ 265*64deb65aSDavid Hildenbrand void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ 266*64deb65aSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 267*64deb65aSDavid Hildenbrand { \ 268*64deb65aSDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 269*64deb65aSDavid Hildenbrand vfc##BITS##_fn fn = float##BITS##_##OP##_quiet; \ 270*64deb65aSDavid Hildenbrand \ 271*64deb65aSDavid Hildenbrand vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ 272*64deb65aSDavid Hildenbrand } \ 273*64deb65aSDavid Hildenbrand \ 274*64deb65aSDavid Hildenbrand void HELPER(gvec_##NAME##BITS##_cc)(void *v1, const void *v2, const void *v3, \ 275*64deb65aSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 276*64deb65aSDavid Hildenbrand { \ 277*64deb65aSDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 278*64deb65aSDavid Hildenbrand vfc##BITS##_fn fn = float##BITS##_##OP##_quiet; \ 279*64deb65aSDavid Hildenbrand \ 280*64deb65aSDavid Hildenbrand env->cc_op = vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ 2812c806ab4SDavid Hildenbrand } 2822c806ab4SDavid Hildenbrand 283*64deb65aSDavid Hildenbrand #define DEF_GVEC_VFC(NAME, OP) \ 284*64deb65aSDavid Hildenbrand DEF_GVEC_VFC_B(NAME, OP, 64) 2852c806ab4SDavid Hildenbrand 286*64deb65aSDavid Hildenbrand DEF_GVEC_VFC(vfce, eq) 287*64deb65aSDavid Hildenbrand DEF_GVEC_VFC(vfch, lt) 288*64deb65aSDavid Hildenbrand DEF_GVEC_VFC(vfche, le) 289bb03fd84SDavid Hildenbrand 2901a76e59dSDavid Hildenbrand static void vfll32(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 2911a76e59dSDavid Hildenbrand bool s, uintptr_t retaddr) 2921a76e59dSDavid Hildenbrand { 2931a76e59dSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 2941a76e59dSDavid Hildenbrand S390Vector tmp = {}; 2951a76e59dSDavid Hildenbrand int i; 2961a76e59dSDavid Hildenbrand 2971a76e59dSDavid Hildenbrand for (i = 0; i < 2; i++) { 2981a76e59dSDavid Hildenbrand /* load from even element */ 2991a76e59dSDavid Hildenbrand const float32 a = s390_vec_read_element32(v2, i * 2); 3001a76e59dSDavid Hildenbrand const uint64_t ret = float32_to_float64(a, &env->fpu_status); 3011a76e59dSDavid Hildenbrand 3021a76e59dSDavid Hildenbrand s390_vec_write_element64(&tmp, i, ret); 3031a76e59dSDavid Hildenbrand /* indicate the source element */ 3041a76e59dSDavid Hildenbrand vxc = check_ieee_exc(env, i * 2, false, &vec_exc); 3051a76e59dSDavid Hildenbrand if (s || vxc) { 3061a76e59dSDavid Hildenbrand break; 3071a76e59dSDavid Hildenbrand } 3081a76e59dSDavid Hildenbrand } 3091a76e59dSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 3101a76e59dSDavid Hildenbrand *v1 = tmp; 3111a76e59dSDavid Hildenbrand } 3121a76e59dSDavid Hildenbrand 3131a76e59dSDavid Hildenbrand void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env, 3141a76e59dSDavid Hildenbrand uint32_t desc) 3151a76e59dSDavid Hildenbrand { 3161a76e59dSDavid Hildenbrand vfll32(v1, v2, env, false, GETPC()); 3171a76e59dSDavid Hildenbrand } 3181a76e59dSDavid Hildenbrand 3191a76e59dSDavid Hildenbrand void HELPER(gvec_vfll32s)(void *v1, const void *v2, CPUS390XState *env, 3201a76e59dSDavid Hildenbrand uint32_t desc) 3211a76e59dSDavid Hildenbrand { 3221a76e59dSDavid Hildenbrand vfll32(v1, v2, env, true, GETPC()); 3231a76e59dSDavid Hildenbrand } 3244500ede4SDavid Hildenbrand 3254500ede4SDavid Hildenbrand static void vflr64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 3264500ede4SDavid Hildenbrand bool s, bool XxC, uint8_t erm, uintptr_t retaddr) 3274500ede4SDavid Hildenbrand { 3284500ede4SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 3294500ede4SDavid Hildenbrand S390Vector tmp = {}; 3304500ede4SDavid Hildenbrand int i, old_mode; 3314500ede4SDavid Hildenbrand 3324500ede4SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 3334500ede4SDavid Hildenbrand for (i = 0; i < 2; i++) { 3344500ede4SDavid Hildenbrand float64 a = s390_vec_read_element64(v2, i); 3354500ede4SDavid Hildenbrand uint32_t ret = float64_to_float32(a, &env->fpu_status); 3364500ede4SDavid Hildenbrand 3374500ede4SDavid Hildenbrand /* place at even element */ 3384500ede4SDavid Hildenbrand s390_vec_write_element32(&tmp, i * 2, ret); 3394500ede4SDavid Hildenbrand /* indicate the source element */ 3404500ede4SDavid Hildenbrand vxc = check_ieee_exc(env, i, XxC, &vec_exc); 3414500ede4SDavid Hildenbrand if (s || vxc) { 3424500ede4SDavid Hildenbrand break; 3434500ede4SDavid Hildenbrand } 3444500ede4SDavid Hildenbrand } 3454500ede4SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 3464500ede4SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 3474500ede4SDavid Hildenbrand *v1 = tmp; 3484500ede4SDavid Hildenbrand } 3494500ede4SDavid Hildenbrand 3504500ede4SDavid Hildenbrand void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env, 3514500ede4SDavid Hildenbrand uint32_t desc) 3524500ede4SDavid Hildenbrand { 3534500ede4SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 3544500ede4SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 3554500ede4SDavid Hildenbrand 3564500ede4SDavid Hildenbrand vflr64(v1, v2, env, false, XxC, erm, GETPC()); 3574500ede4SDavid Hildenbrand } 3584500ede4SDavid Hildenbrand 3594500ede4SDavid Hildenbrand void HELPER(gvec_vflr64s)(void *v1, const void *v2, CPUS390XState *env, 3604500ede4SDavid Hildenbrand uint32_t desc) 3614500ede4SDavid Hildenbrand { 3624500ede4SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 3634500ede4SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 3644500ede4SDavid Hildenbrand 3654500ede4SDavid Hildenbrand vflr64(v1, v2, env, true, XxC, erm, GETPC()); 3664500ede4SDavid Hildenbrand } 3678d47d4d2SDavid Hildenbrand 368c64c5984SDavid Hildenbrand static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 369c64c5984SDavid Hildenbrand const S390Vector *v4, CPUS390XState *env, bool s, int flags, 370c64c5984SDavid Hildenbrand uintptr_t retaddr) 371c64c5984SDavid Hildenbrand { 372c64c5984SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 373c64c5984SDavid Hildenbrand S390Vector tmp = {}; 374c64c5984SDavid Hildenbrand int i; 375c64c5984SDavid Hildenbrand 376c64c5984SDavid Hildenbrand for (i = 0; i < 2; i++) { 377c64c5984SDavid Hildenbrand const uint64_t a = s390_vec_read_element64(v2, i); 378c64c5984SDavid Hildenbrand const uint64_t b = s390_vec_read_element64(v3, i); 379c64c5984SDavid Hildenbrand const uint64_t c = s390_vec_read_element64(v4, i); 380c64c5984SDavid Hildenbrand uint64_t ret = float64_muladd(a, b, c, flags, &env->fpu_status); 381c64c5984SDavid Hildenbrand 382c64c5984SDavid Hildenbrand s390_vec_write_element64(&tmp, i, ret); 383c64c5984SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 384c64c5984SDavid Hildenbrand if (s || vxc) { 385c64c5984SDavid Hildenbrand break; 386c64c5984SDavid Hildenbrand } 387c64c5984SDavid Hildenbrand } 388c64c5984SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 389c64c5984SDavid Hildenbrand *v1 = tmp; 390c64c5984SDavid Hildenbrand } 391c64c5984SDavid Hildenbrand 392c64c5984SDavid Hildenbrand void HELPER(gvec_vfma64)(void *v1, const void *v2, const void *v3, 393c64c5984SDavid Hildenbrand const void *v4, CPUS390XState *env, uint32_t desc) 394c64c5984SDavid Hildenbrand { 395c64c5984SDavid Hildenbrand vfma64(v1, v2, v3, v4, env, false, 0, GETPC()); 396c64c5984SDavid Hildenbrand } 397c64c5984SDavid Hildenbrand 398c64c5984SDavid Hildenbrand void HELPER(gvec_vfma64s)(void *v1, const void *v2, const void *v3, 399c64c5984SDavid Hildenbrand const void *v4, CPUS390XState *env, uint32_t desc) 400c64c5984SDavid Hildenbrand { 401c64c5984SDavid Hildenbrand vfma64(v1, v2, v3, v4, env, true, 0, GETPC()); 402c64c5984SDavid Hildenbrand } 403c64c5984SDavid Hildenbrand 404c64c5984SDavid Hildenbrand void HELPER(gvec_vfms64)(void *v1, const void *v2, const void *v3, 405c64c5984SDavid Hildenbrand const void *v4, CPUS390XState *env, uint32_t desc) 406c64c5984SDavid Hildenbrand { 407c64c5984SDavid Hildenbrand vfma64(v1, v2, v3, v4, env, false, float_muladd_negate_c, GETPC()); 408c64c5984SDavid Hildenbrand } 409c64c5984SDavid Hildenbrand 410c64c5984SDavid Hildenbrand void HELPER(gvec_vfms64s)(void *v1, const void *v2, const void *v3, 411c64c5984SDavid Hildenbrand const void *v4, CPUS390XState *env, uint32_t desc) 412c64c5984SDavid Hildenbrand { 413c64c5984SDavid Hildenbrand vfma64(v1, v2, v3, v4, env, true, float_muladd_negate_c, GETPC()); 414c64c5984SDavid Hildenbrand } 4155938f20cSDavid Hildenbrand 41683b955f9SDavid Hildenbrand static int vftci64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 41783b955f9SDavid Hildenbrand bool s, uint16_t i3) 41883b955f9SDavid Hildenbrand { 41983b955f9SDavid Hildenbrand int i, match = 0; 42083b955f9SDavid Hildenbrand 42183b955f9SDavid Hildenbrand for (i = 0; i < 2; i++) { 42283b955f9SDavid Hildenbrand float64 a = s390_vec_read_element64(v2, i); 42383b955f9SDavid Hildenbrand 42483b955f9SDavid Hildenbrand if (float64_dcmask(env, a) & i3) { 42583b955f9SDavid Hildenbrand match++; 42683b955f9SDavid Hildenbrand s390_vec_write_element64(v1, i, -1ull); 42783b955f9SDavid Hildenbrand } else { 42883b955f9SDavid Hildenbrand s390_vec_write_element64(v1, i, 0); 42983b955f9SDavid Hildenbrand } 43083b955f9SDavid Hildenbrand if (s) { 43183b955f9SDavid Hildenbrand break; 43283b955f9SDavid Hildenbrand } 43383b955f9SDavid Hildenbrand } 43483b955f9SDavid Hildenbrand 43583b955f9SDavid Hildenbrand if (match) { 43683b955f9SDavid Hildenbrand return s || match == 2 ? 0 : 1; 43783b955f9SDavid Hildenbrand } 43883b955f9SDavid Hildenbrand return 3; 43983b955f9SDavid Hildenbrand } 44083b955f9SDavid Hildenbrand 44183b955f9SDavid Hildenbrand void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env, 44283b955f9SDavid Hildenbrand uint32_t desc) 44383b955f9SDavid Hildenbrand { 44483b955f9SDavid Hildenbrand env->cc_op = vftci64(v1, v2, env, false, simd_data(desc)); 44583b955f9SDavid Hildenbrand } 44683b955f9SDavid Hildenbrand 44783b955f9SDavid Hildenbrand void HELPER(gvec_vftci64s)(void *v1, const void *v2, CPUS390XState *env, 44883b955f9SDavid Hildenbrand uint32_t desc) 44983b955f9SDavid Hildenbrand { 45083b955f9SDavid Hildenbrand env->cc_op = vftci64(v1, v2, env, true, simd_data(desc)); 45183b955f9SDavid Hildenbrand } 452