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++) { 24264deb65aSDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 24364deb65aSDavid 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 26464deb65aSDavid Hildenbrand #define DEF_GVEC_VFC_B(NAME, OP, BITS) \ 26564deb65aSDavid Hildenbrand void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ 26664deb65aSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 26764deb65aSDavid Hildenbrand { \ 26864deb65aSDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 26964deb65aSDavid Hildenbrand vfc##BITS##_fn fn = float##BITS##_##OP##_quiet; \ 27064deb65aSDavid Hildenbrand \ 27164deb65aSDavid Hildenbrand vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ 27264deb65aSDavid Hildenbrand } \ 27364deb65aSDavid Hildenbrand \ 27464deb65aSDavid Hildenbrand void HELPER(gvec_##NAME##BITS##_cc)(void *v1, const void *v2, const void *v3, \ 27564deb65aSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 27664deb65aSDavid Hildenbrand { \ 27764deb65aSDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 27864deb65aSDavid Hildenbrand vfc##BITS##_fn fn = float##BITS##_##OP##_quiet; \ 27964deb65aSDavid Hildenbrand \ 28064deb65aSDavid Hildenbrand env->cc_op = vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ 2812c806ab4SDavid Hildenbrand } 2822c806ab4SDavid Hildenbrand 28364deb65aSDavid Hildenbrand #define DEF_GVEC_VFC(NAME, OP) \ 28464deb65aSDavid Hildenbrand DEF_GVEC_VFC_B(NAME, OP, 64) 2852c806ab4SDavid Hildenbrand 28664deb65aSDavid Hildenbrand DEF_GVEC_VFC(vfce, eq) 28764deb65aSDavid Hildenbrand DEF_GVEC_VFC(vfch, lt) 28864deb65aSDavid Hildenbrand DEF_GVEC_VFC(vfche, le) 289bb03fd84SDavid Hildenbrand 290860b707bSDavid Hildenbrand void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env, 291860b707bSDavid Hildenbrand uint32_t desc) 2921a76e59dSDavid Hildenbrand { 293860b707bSDavid Hildenbrand const bool s = extract32(simd_data(desc), 3, 1); 2941a76e59dSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 2951a76e59dSDavid Hildenbrand S390Vector tmp = {}; 2961a76e59dSDavid Hildenbrand int i; 2971a76e59dSDavid Hildenbrand 2981a76e59dSDavid Hildenbrand for (i = 0; i < 2; i++) { 2991a76e59dSDavid Hildenbrand /* load from even element */ 3001a76e59dSDavid Hildenbrand const float32 a = s390_vec_read_element32(v2, i * 2); 3011a76e59dSDavid Hildenbrand const uint64_t ret = float32_to_float64(a, &env->fpu_status); 3021a76e59dSDavid Hildenbrand 3031a76e59dSDavid Hildenbrand s390_vec_write_element64(&tmp, i, ret); 3041a76e59dSDavid Hildenbrand /* indicate the source element */ 3051a76e59dSDavid Hildenbrand vxc = check_ieee_exc(env, i * 2, false, &vec_exc); 3061a76e59dSDavid Hildenbrand if (s || vxc) { 3071a76e59dSDavid Hildenbrand break; 3081a76e59dSDavid Hildenbrand } 3091a76e59dSDavid Hildenbrand } 310860b707bSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, GETPC()); 311860b707bSDavid Hildenbrand *(S390Vector *)v1 = tmp; 3121a76e59dSDavid Hildenbrand } 3134500ede4SDavid Hildenbrand 314*977e43d9SDavid Hildenbrand void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env, 315*977e43d9SDavid Hildenbrand uint32_t desc) 3164500ede4SDavid Hildenbrand { 317*977e43d9SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 318*977e43d9SDavid Hildenbrand const bool s = extract32(simd_data(desc), 3, 1); 319*977e43d9SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 3204500ede4SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 3214500ede4SDavid Hildenbrand S390Vector tmp = {}; 3224500ede4SDavid Hildenbrand int i, old_mode; 3234500ede4SDavid Hildenbrand 3244500ede4SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 3254500ede4SDavid Hildenbrand for (i = 0; i < 2; i++) { 3264500ede4SDavid Hildenbrand float64 a = s390_vec_read_element64(v2, i); 3274500ede4SDavid Hildenbrand uint32_t ret = float64_to_float32(a, &env->fpu_status); 3284500ede4SDavid Hildenbrand 3294500ede4SDavid Hildenbrand /* place at even element */ 3304500ede4SDavid Hildenbrand s390_vec_write_element32(&tmp, i * 2, ret); 3314500ede4SDavid Hildenbrand /* indicate the source element */ 3324500ede4SDavid Hildenbrand vxc = check_ieee_exc(env, i, XxC, &vec_exc); 3334500ede4SDavid Hildenbrand if (s || vxc) { 3344500ede4SDavid Hildenbrand break; 3354500ede4SDavid Hildenbrand } 3364500ede4SDavid Hildenbrand } 3374500ede4SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 338*977e43d9SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, GETPC()); 339*977e43d9SDavid Hildenbrand *(S390Vector *)v1 = tmp; 3404500ede4SDavid Hildenbrand } 3418d47d4d2SDavid Hildenbrand 342c64c5984SDavid Hildenbrand static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 343c64c5984SDavid Hildenbrand const S390Vector *v4, CPUS390XState *env, bool s, int flags, 344c64c5984SDavid Hildenbrand uintptr_t retaddr) 345c64c5984SDavid Hildenbrand { 346c64c5984SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 347c64c5984SDavid Hildenbrand S390Vector tmp = {}; 348c64c5984SDavid Hildenbrand int i; 349c64c5984SDavid Hildenbrand 350c64c5984SDavid Hildenbrand for (i = 0; i < 2; i++) { 35134142ffdSDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 35234142ffdSDavid Hildenbrand const float64 b = s390_vec_read_float64(v3, i); 35334142ffdSDavid Hildenbrand const float64 c = s390_vec_read_float64(v4, i); 35434142ffdSDavid Hildenbrand const float64 ret = float64_muladd(a, b, c, flags, &env->fpu_status); 355c64c5984SDavid Hildenbrand 35634142ffdSDavid Hildenbrand s390_vec_write_float64(&tmp, i, ret); 357c64c5984SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 358c64c5984SDavid Hildenbrand if (s || vxc) { 359c64c5984SDavid Hildenbrand break; 360c64c5984SDavid Hildenbrand } 361c64c5984SDavid Hildenbrand } 362c64c5984SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 363c64c5984SDavid Hildenbrand *v1 = tmp; 364c64c5984SDavid Hildenbrand } 365c64c5984SDavid Hildenbrand 36634142ffdSDavid Hildenbrand #define DEF_GVEC_VFMA_B(NAME, FLAGS, BITS) \ 36734142ffdSDavid Hildenbrand void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ 36834142ffdSDavid Hildenbrand const void *v4, CPUS390XState *env, \ 36934142ffdSDavid Hildenbrand uint32_t desc) \ 37034142ffdSDavid Hildenbrand { \ 37134142ffdSDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 37234142ffdSDavid Hildenbrand \ 37334142ffdSDavid Hildenbrand vfma##BITS(v1, v2, v3, v4, env, se, FLAGS, GETPC()); \ 374c64c5984SDavid Hildenbrand } 375c64c5984SDavid Hildenbrand 37634142ffdSDavid Hildenbrand #define DEF_GVEC_VFMA(NAME, FLAGS) \ 37734142ffdSDavid Hildenbrand DEF_GVEC_VFMA_B(NAME, FLAGS, 64) 378c64c5984SDavid Hildenbrand 37934142ffdSDavid Hildenbrand DEF_GVEC_VFMA(vfma, 0) 38034142ffdSDavid Hildenbrand DEF_GVEC_VFMA(vfms, float_muladd_negate_c) 3815938f20cSDavid Hildenbrand 382622ebe64SDavid Hildenbrand void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env, 383622ebe64SDavid Hildenbrand uint32_t desc) 38483b955f9SDavid Hildenbrand { 385622ebe64SDavid Hildenbrand const uint16_t i3 = extract32(simd_data(desc), 4, 12); 386622ebe64SDavid Hildenbrand const bool s = extract32(simd_data(desc), 3, 1); 38783b955f9SDavid Hildenbrand int i, match = 0; 38883b955f9SDavid Hildenbrand 38983b955f9SDavid Hildenbrand for (i = 0; i < 2; i++) { 390622ebe64SDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 39183b955f9SDavid Hildenbrand 39283b955f9SDavid Hildenbrand if (float64_dcmask(env, a) & i3) { 39383b955f9SDavid Hildenbrand match++; 39483b955f9SDavid Hildenbrand s390_vec_write_element64(v1, i, -1ull); 39583b955f9SDavid Hildenbrand } else { 39683b955f9SDavid Hildenbrand s390_vec_write_element64(v1, i, 0); 39783b955f9SDavid Hildenbrand } 39883b955f9SDavid Hildenbrand if (s) { 39983b955f9SDavid Hildenbrand break; 40083b955f9SDavid Hildenbrand } 40183b955f9SDavid Hildenbrand } 40283b955f9SDavid Hildenbrand 403622ebe64SDavid Hildenbrand if (match == 2 || (s && match)) { 404622ebe64SDavid Hildenbrand env->cc_op = 0; 405622ebe64SDavid Hildenbrand } else if (match) { 406622ebe64SDavid Hildenbrand env->cc_op = 1; 407622ebe64SDavid Hildenbrand } else { 408622ebe64SDavid Hildenbrand env->cc_op = 3; 40983b955f9SDavid Hildenbrand } 41083b955f9SDavid Hildenbrand } 411