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 810987961dSDavid Hildenbrand static float32 s390_vec_read_float32(const S390Vector *v, uint8_t enr) 820987961dSDavid Hildenbrand { 830987961dSDavid Hildenbrand return make_float32(s390_vec_read_element32(v, enr)); 840987961dSDavid Hildenbrand } 850987961dSDavid Hildenbrand 86863b9507SDavid Hildenbrand static float64 s390_vec_read_float64(const S390Vector *v, uint8_t enr) 87863b9507SDavid Hildenbrand { 88863b9507SDavid Hildenbrand return make_float64(s390_vec_read_element64(v, enr)); 89863b9507SDavid Hildenbrand } 90863b9507SDavid Hildenbrand 910987961dSDavid Hildenbrand static float128 s390_vec_read_float128(const S390Vector *v) 920987961dSDavid Hildenbrand { 930987961dSDavid Hildenbrand return make_float128(s390_vec_read_element64(v, 0), 940987961dSDavid Hildenbrand s390_vec_read_element64(v, 1)); 950987961dSDavid Hildenbrand } 960987961dSDavid Hildenbrand 970987961dSDavid Hildenbrand static void s390_vec_write_float32(S390Vector *v, uint8_t enr, float32 data) 980987961dSDavid Hildenbrand { 990987961dSDavid Hildenbrand return s390_vec_write_element32(v, enr, data); 1000987961dSDavid Hildenbrand } 1010987961dSDavid Hildenbrand 102863b9507SDavid Hildenbrand static void s390_vec_write_float64(S390Vector *v, uint8_t enr, float64 data) 103863b9507SDavid Hildenbrand { 104863b9507SDavid Hildenbrand return s390_vec_write_element64(v, enr, data); 105863b9507SDavid Hildenbrand } 106863b9507SDavid Hildenbrand 1070987961dSDavid Hildenbrand static void s390_vec_write_float128(S390Vector *v, float128 data) 1080987961dSDavid Hildenbrand { 1090987961dSDavid Hildenbrand s390_vec_write_element64(v, 0, data.high); 1100987961dSDavid Hildenbrand s390_vec_write_element64(v, 1, data.low); 1110987961dSDavid Hildenbrand } 1120987961dSDavid Hildenbrand 113acb269a4SDavid Hildenbrand typedef float32 (*vop32_2_fn)(float32 a, float_status *s); 114acb269a4SDavid Hildenbrand static void vop32_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 115acb269a4SDavid Hildenbrand bool s, bool XxC, uint8_t erm, vop32_2_fn fn, 116acb269a4SDavid Hildenbrand uintptr_t retaddr) 117acb269a4SDavid Hildenbrand { 118acb269a4SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 119acb269a4SDavid Hildenbrand S390Vector tmp = {}; 120acb269a4SDavid Hildenbrand int i, old_mode; 121acb269a4SDavid Hildenbrand 122acb269a4SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 123acb269a4SDavid Hildenbrand for (i = 0; i < 4; i++) { 124acb269a4SDavid Hildenbrand const float32 a = s390_vec_read_float32(v2, i); 125acb269a4SDavid Hildenbrand 126acb269a4SDavid Hildenbrand s390_vec_write_float32(&tmp, i, fn(a, &env->fpu_status)); 127acb269a4SDavid Hildenbrand vxc = check_ieee_exc(env, i, XxC, &vec_exc); 128acb269a4SDavid Hildenbrand if (s || vxc) { 129acb269a4SDavid Hildenbrand break; 130acb269a4SDavid Hildenbrand } 131acb269a4SDavid Hildenbrand } 132acb269a4SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 133acb269a4SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 134acb269a4SDavid Hildenbrand *v1 = tmp; 135acb269a4SDavid Hildenbrand } 136acb269a4SDavid Hildenbrand 13721bd6ea2SDavid Hildenbrand typedef float64 (*vop64_2_fn)(float64 a, float_status *s); 138bb03fd84SDavid Hildenbrand static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 139bb03fd84SDavid Hildenbrand bool s, bool XxC, uint8_t erm, vop64_2_fn fn, 140bb03fd84SDavid Hildenbrand uintptr_t retaddr) 141bb03fd84SDavid Hildenbrand { 142bb03fd84SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 143bb03fd84SDavid Hildenbrand S390Vector tmp = {}; 144bb03fd84SDavid Hildenbrand int i, old_mode; 145bb03fd84SDavid Hildenbrand 146bb03fd84SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 147bb03fd84SDavid Hildenbrand for (i = 0; i < 2; i++) { 14821bd6ea2SDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 149bb03fd84SDavid Hildenbrand 15021bd6ea2SDavid Hildenbrand s390_vec_write_float64(&tmp, i, fn(a, &env->fpu_status)); 151bb03fd84SDavid Hildenbrand vxc = check_ieee_exc(env, i, XxC, &vec_exc); 152bb03fd84SDavid Hildenbrand if (s || vxc) { 153bb03fd84SDavid Hildenbrand break; 154bb03fd84SDavid Hildenbrand } 155bb03fd84SDavid Hildenbrand } 156bb03fd84SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 157bb03fd84SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 158bb03fd84SDavid Hildenbrand *v1 = tmp; 159bb03fd84SDavid Hildenbrand } 160bb03fd84SDavid Hildenbrand 161acb269a4SDavid Hildenbrand typedef float128 (*vop128_2_fn)(float128 a, float_status *s); 162acb269a4SDavid Hildenbrand static void vop128_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 163acb269a4SDavid Hildenbrand bool s, bool XxC, uint8_t erm, vop128_2_fn fn, 164acb269a4SDavid Hildenbrand uintptr_t retaddr) 165acb269a4SDavid Hildenbrand { 166acb269a4SDavid Hildenbrand const float128 a = s390_vec_read_float128(v2); 167acb269a4SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 168acb269a4SDavid Hildenbrand S390Vector tmp = {}; 169acb269a4SDavid Hildenbrand int old_mode; 170acb269a4SDavid Hildenbrand 171acb269a4SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 172acb269a4SDavid Hildenbrand s390_vec_write_float128(&tmp, fn(a, &env->fpu_status)); 173acb269a4SDavid Hildenbrand vxc = check_ieee_exc(env, 0, XxC, &vec_exc); 174acb269a4SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 175acb269a4SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 176acb269a4SDavid Hildenbrand *v1 = tmp; 177acb269a4SDavid Hildenbrand } 178acb269a4SDavid Hildenbrand 17921bd6ea2SDavid Hildenbrand static float64 vcdg64(float64 a, float_status *s) 18021bd6ea2SDavid Hildenbrand { 18121bd6ea2SDavid Hildenbrand return int64_to_float64(a, s); 18221bd6ea2SDavid Hildenbrand } 18321bd6ea2SDavid Hildenbrand 18421bd6ea2SDavid Hildenbrand static float64 vcdlg64(float64 a, float_status *s) 18521bd6ea2SDavid Hildenbrand { 18621bd6ea2SDavid Hildenbrand return uint64_to_float64(a, s); 18721bd6ea2SDavid Hildenbrand } 18821bd6ea2SDavid Hildenbrand 18921bd6ea2SDavid Hildenbrand static float64 vcgd64(float64 a, float_status *s) 19021bd6ea2SDavid Hildenbrand { 19121bd6ea2SDavid Hildenbrand const float64 tmp = float64_to_int64(a, s); 19221bd6ea2SDavid Hildenbrand 19321bd6ea2SDavid Hildenbrand return float64_is_any_nan(a) ? INT64_MIN : tmp; 19421bd6ea2SDavid Hildenbrand } 19521bd6ea2SDavid Hildenbrand 19621bd6ea2SDavid Hildenbrand static float64 vclgd64(float64 a, float_status *s) 19721bd6ea2SDavid Hildenbrand { 19821bd6ea2SDavid Hildenbrand const float64 tmp = float64_to_uint64(a, s); 19921bd6ea2SDavid Hildenbrand 20021bd6ea2SDavid Hildenbrand return float64_is_any_nan(a) ? 0 : tmp; 20121bd6ea2SDavid Hildenbrand } 20221bd6ea2SDavid Hildenbrand 20321bd6ea2SDavid Hildenbrand #define DEF_GVEC_VOP2_FN(NAME, FN, BITS) \ 20421bd6ea2SDavid Hildenbrand void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, CPUS390XState *env, \ 20521bd6ea2SDavid Hildenbrand uint32_t desc) \ 20621bd6ea2SDavid Hildenbrand { \ 20721bd6ea2SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); \ 20821bd6ea2SDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 20921bd6ea2SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); \ 21021bd6ea2SDavid Hildenbrand \ 21121bd6ea2SDavid Hildenbrand vop##BITS##_2(v1, v2, env, se, XxC, erm, FN, GETPC()); \ 21221bd6ea2SDavid Hildenbrand } 21321bd6ea2SDavid Hildenbrand 21421bd6ea2SDavid Hildenbrand #define DEF_GVEC_VOP2_64(NAME) \ 21521bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_FN(NAME, NAME##64, 64) 21621bd6ea2SDavid Hildenbrand 21721bd6ea2SDavid Hildenbrand #define DEF_GVEC_VOP2(NAME, OP) \ 218acb269a4SDavid Hildenbrand DEF_GVEC_VOP2_FN(NAME, float32_##OP, 32) \ 219acb269a4SDavid Hildenbrand DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64) \ 220acb269a4SDavid Hildenbrand DEF_GVEC_VOP2_FN(NAME, float128_##OP, 128) 22121bd6ea2SDavid Hildenbrand 22221bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_64(vcdg) 22321bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_64(vcdlg) 22421bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_64(vcgd) 22521bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2_64(vclgd) 22621bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2(vfi, round_to_int) 22721bd6ea2SDavid Hildenbrand DEF_GVEC_VOP2(vfsq, sqrt) 22821bd6ea2SDavid Hildenbrand 2290987961dSDavid Hildenbrand typedef float32 (*vop32_3_fn)(float32 a, float32 b, float_status *s); 2300987961dSDavid Hildenbrand static void vop32_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 2310987961dSDavid Hildenbrand CPUS390XState *env, bool s, vop32_3_fn fn, 2320987961dSDavid Hildenbrand uintptr_t retaddr) 2330987961dSDavid Hildenbrand { 2340987961dSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 2350987961dSDavid Hildenbrand S390Vector tmp = {}; 2360987961dSDavid Hildenbrand int i; 2370987961dSDavid Hildenbrand 2380987961dSDavid Hildenbrand for (i = 0; i < 4; i++) { 2390987961dSDavid Hildenbrand const float32 a = s390_vec_read_float32(v2, i); 2400987961dSDavid Hildenbrand const float32 b = s390_vec_read_float32(v3, i); 2410987961dSDavid Hildenbrand 2420987961dSDavid Hildenbrand s390_vec_write_float32(&tmp, i, fn(a, b, &env->fpu_status)); 2430987961dSDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 2440987961dSDavid Hildenbrand if (s || vxc) { 2450987961dSDavid Hildenbrand break; 2460987961dSDavid Hildenbrand } 2470987961dSDavid Hildenbrand } 2480987961dSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 2490987961dSDavid Hildenbrand *v1 = tmp; 2500987961dSDavid Hildenbrand } 2510987961dSDavid Hildenbrand 252863b9507SDavid Hildenbrand typedef float64 (*vop64_3_fn)(float64 a, float64 b, float_status *s); 2533a0eae85SDavid Hildenbrand static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 2543a0eae85SDavid Hildenbrand CPUS390XState *env, bool s, vop64_3_fn fn, 2553a0eae85SDavid Hildenbrand uintptr_t retaddr) 2563a0eae85SDavid Hildenbrand { 2573a0eae85SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 2583a0eae85SDavid Hildenbrand S390Vector tmp = {}; 2593a0eae85SDavid Hildenbrand int i; 2603a0eae85SDavid Hildenbrand 2613a0eae85SDavid Hildenbrand for (i = 0; i < 2; i++) { 262863b9507SDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 263863b9507SDavid Hildenbrand const float64 b = s390_vec_read_float64(v3, i); 2643a0eae85SDavid Hildenbrand 265863b9507SDavid Hildenbrand s390_vec_write_float64(&tmp, i, fn(a, b, &env->fpu_status)); 2663a0eae85SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 2673a0eae85SDavid Hildenbrand if (s || vxc) { 2683a0eae85SDavid Hildenbrand break; 2693a0eae85SDavid Hildenbrand } 2703a0eae85SDavid Hildenbrand } 2713a0eae85SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 2723a0eae85SDavid Hildenbrand *v1 = tmp; 2733a0eae85SDavid Hildenbrand } 2743a0eae85SDavid Hildenbrand 2750987961dSDavid Hildenbrand typedef float128 (*vop128_3_fn)(float128 a, float128 b, float_status *s); 2760987961dSDavid Hildenbrand static void vop128_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 2770987961dSDavid Hildenbrand CPUS390XState *env, bool s, vop128_3_fn fn, 2780987961dSDavid Hildenbrand uintptr_t retaddr) 2790987961dSDavid Hildenbrand { 2800987961dSDavid Hildenbrand const float128 a = s390_vec_read_float128(v2); 2810987961dSDavid Hildenbrand const float128 b = s390_vec_read_float128(v3); 2820987961dSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 2830987961dSDavid Hildenbrand S390Vector tmp = {}; 2840987961dSDavid Hildenbrand 2850987961dSDavid Hildenbrand s390_vec_write_float128(&tmp, fn(a, b, &env->fpu_status)); 2860987961dSDavid Hildenbrand vxc = check_ieee_exc(env, 0, false, &vec_exc); 2870987961dSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 2880987961dSDavid Hildenbrand *v1 = tmp; 2890987961dSDavid Hildenbrand } 2900987961dSDavid Hildenbrand 2910987961dSDavid Hildenbrand #define DEF_GVEC_VOP3_B(NAME, OP, BITS) \ 2920987961dSDavid Hildenbrand void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ 293863b9507SDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 294863b9507SDavid Hildenbrand { \ 295863b9507SDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 296863b9507SDavid Hildenbrand \ 2970987961dSDavid Hildenbrand vop##BITS##_3(v1, v2, v3, env, se, float##BITS##_##OP, GETPC()); \ 2983a0eae85SDavid Hildenbrand } 2993a0eae85SDavid Hildenbrand 3000987961dSDavid Hildenbrand #define DEF_GVEC_VOP3(NAME, OP) \ 3010987961dSDavid Hildenbrand DEF_GVEC_VOP3_B(NAME, OP, 32) \ 3020987961dSDavid Hildenbrand DEF_GVEC_VOP3_B(NAME, OP, 64) \ 3030987961dSDavid Hildenbrand DEF_GVEC_VOP3_B(NAME, OP, 128) 3040987961dSDavid Hildenbrand 305863b9507SDavid Hildenbrand DEF_GVEC_VOP3(vfa, add) 306863b9507SDavid Hildenbrand DEF_GVEC_VOP3(vfs, sub) 307863b9507SDavid Hildenbrand DEF_GVEC_VOP3(vfd, div) 308863b9507SDavid Hildenbrand DEF_GVEC_VOP3(vfm, mul) 3095b89f0fbSDavid Hildenbrand 3101c6b5b47SDavid Hildenbrand static int wfc32(const S390Vector *v1, const S390Vector *v2, 3111c6b5b47SDavid Hildenbrand CPUS390XState *env, bool signal, uintptr_t retaddr) 3121c6b5b47SDavid Hildenbrand { 3131c6b5b47SDavid Hildenbrand /* only the zero-indexed elements are compared */ 3141c6b5b47SDavid Hildenbrand const float32 a = s390_vec_read_float32(v1, 0); 3151c6b5b47SDavid Hildenbrand const float32 b = s390_vec_read_float32(v2, 0); 3161c6b5b47SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 3171c6b5b47SDavid Hildenbrand int cmp; 3181c6b5b47SDavid Hildenbrand 3191c6b5b47SDavid Hildenbrand if (signal) { 3201c6b5b47SDavid Hildenbrand cmp = float32_compare(a, b, &env->fpu_status); 3211c6b5b47SDavid Hildenbrand } else { 3221c6b5b47SDavid Hildenbrand cmp = float32_compare_quiet(a, b, &env->fpu_status); 3231c6b5b47SDavid Hildenbrand } 3241c6b5b47SDavid Hildenbrand vxc = check_ieee_exc(env, 0, false, &vec_exc); 3251c6b5b47SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 3261c6b5b47SDavid Hildenbrand 3271c6b5b47SDavid Hildenbrand return float_comp_to_cc(env, cmp); 3281c6b5b47SDavid Hildenbrand } 3291c6b5b47SDavid Hildenbrand 3305b89f0fbSDavid Hildenbrand static int wfc64(const S390Vector *v1, const S390Vector *v2, 3315b89f0fbSDavid Hildenbrand CPUS390XState *env, bool signal, uintptr_t retaddr) 3325b89f0fbSDavid Hildenbrand { 3335b89f0fbSDavid Hildenbrand /* only the zero-indexed elements are compared */ 3344da79375SDavid Hildenbrand const float64 a = s390_vec_read_float64(v1, 0); 3354da79375SDavid Hildenbrand const float64 b = s390_vec_read_float64(v2, 0); 3365b89f0fbSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 3375b89f0fbSDavid Hildenbrand int cmp; 3385b89f0fbSDavid Hildenbrand 3395b89f0fbSDavid Hildenbrand if (signal) { 3405b89f0fbSDavid Hildenbrand cmp = float64_compare(a, b, &env->fpu_status); 3415b89f0fbSDavid Hildenbrand } else { 3425b89f0fbSDavid Hildenbrand cmp = float64_compare_quiet(a, b, &env->fpu_status); 3435b89f0fbSDavid Hildenbrand } 3445b89f0fbSDavid Hildenbrand vxc = check_ieee_exc(env, 0, false, &vec_exc); 3455b89f0fbSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 3465b89f0fbSDavid Hildenbrand 3475b89f0fbSDavid Hildenbrand return float_comp_to_cc(env, cmp); 3485b89f0fbSDavid Hildenbrand } 3495b89f0fbSDavid Hildenbrand 3501c6b5b47SDavid Hildenbrand static int wfc128(const S390Vector *v1, const S390Vector *v2, 3511c6b5b47SDavid Hildenbrand CPUS390XState *env, bool signal, uintptr_t retaddr) 3521c6b5b47SDavid Hildenbrand { 3531c6b5b47SDavid Hildenbrand /* only the zero-indexed elements are compared */ 3541c6b5b47SDavid Hildenbrand const float128 a = s390_vec_read_float128(v1); 3551c6b5b47SDavid Hildenbrand const float128 b = s390_vec_read_float128(v2); 3561c6b5b47SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 3571c6b5b47SDavid Hildenbrand int cmp; 3581c6b5b47SDavid Hildenbrand 3591c6b5b47SDavid Hildenbrand if (signal) { 3601c6b5b47SDavid Hildenbrand cmp = float128_compare(a, b, &env->fpu_status); 3611c6b5b47SDavid Hildenbrand } else { 3621c6b5b47SDavid Hildenbrand cmp = float128_compare_quiet(a, b, &env->fpu_status); 3631c6b5b47SDavid Hildenbrand } 3641c6b5b47SDavid Hildenbrand vxc = check_ieee_exc(env, 0, false, &vec_exc); 3651c6b5b47SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 3661c6b5b47SDavid Hildenbrand 3671c6b5b47SDavid Hildenbrand return float_comp_to_cc(env, cmp); 3681c6b5b47SDavid Hildenbrand } 3691c6b5b47SDavid Hildenbrand 3704da79375SDavid Hildenbrand #define DEF_GVEC_WFC_B(NAME, SIGNAL, BITS) \ 3714da79375SDavid Hildenbrand void HELPER(gvec_##NAME##BITS)(const void *v1, const void *v2, \ 3724da79375SDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 3734da79375SDavid Hildenbrand { \ 3744da79375SDavid Hildenbrand env->cc_op = wfc##BITS(v1, v2, env, SIGNAL, GETPC()); \ 3755b89f0fbSDavid Hildenbrand } 3765b89f0fbSDavid Hildenbrand 3774da79375SDavid Hildenbrand #define DEF_GVEC_WFC(NAME, SIGNAL) \ 3781c6b5b47SDavid Hildenbrand DEF_GVEC_WFC_B(NAME, SIGNAL, 32) \ 3791c6b5b47SDavid Hildenbrand DEF_GVEC_WFC_B(NAME, SIGNAL, 64) \ 3801c6b5b47SDavid Hildenbrand DEF_GVEC_WFC_B(NAME, SIGNAL, 128) 3814da79375SDavid Hildenbrand 3824da79375SDavid Hildenbrand DEF_GVEC_WFC(wfc, false) 3834da79375SDavid Hildenbrand DEF_GVEC_WFC(wfk, true) 3842c806ab4SDavid Hildenbrand 385e384332cSDavid Hildenbrand typedef bool (*vfc32_fn)(float32 a, float32 b, float_status *status); 386e384332cSDavid Hildenbrand static int vfc32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 387e384332cSDavid Hildenbrand CPUS390XState *env, bool s, vfc32_fn fn, uintptr_t retaddr) 388e384332cSDavid Hildenbrand { 389e384332cSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 390e384332cSDavid Hildenbrand S390Vector tmp = {}; 391e384332cSDavid Hildenbrand int match = 0; 392e384332cSDavid Hildenbrand int i; 393e384332cSDavid Hildenbrand 394e384332cSDavid Hildenbrand for (i = 0; i < 4; i++) { 395e384332cSDavid Hildenbrand const float32 a = s390_vec_read_float32(v2, i); 396e384332cSDavid Hildenbrand const float32 b = s390_vec_read_float32(v3, i); 397e384332cSDavid Hildenbrand 398e384332cSDavid Hildenbrand /* swap the order of the parameters, so we can use existing functions */ 399e384332cSDavid Hildenbrand if (fn(b, a, &env->fpu_status)) { 400e384332cSDavid Hildenbrand match++; 401e384332cSDavid Hildenbrand s390_vec_write_element32(&tmp, i, -1u); 402e384332cSDavid Hildenbrand } 403e384332cSDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 404e384332cSDavid Hildenbrand if (s || vxc) { 405e384332cSDavid Hildenbrand break; 406e384332cSDavid Hildenbrand } 407e384332cSDavid Hildenbrand } 408e384332cSDavid Hildenbrand 409e384332cSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 410e384332cSDavid Hildenbrand *v1 = tmp; 411e384332cSDavid Hildenbrand if (match) { 412e384332cSDavid Hildenbrand return s || match == 4 ? 0 : 1; 413e384332cSDavid Hildenbrand } 414e384332cSDavid Hildenbrand return 3; 415e384332cSDavid Hildenbrand } 416e384332cSDavid Hildenbrand 4170673ecdfSRichard Henderson typedef bool (*vfc64_fn)(float64 a, float64 b, float_status *status); 4182c806ab4SDavid Hildenbrand static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 4192c806ab4SDavid Hildenbrand CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr) 4202c806ab4SDavid Hildenbrand { 4212c806ab4SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 4222c806ab4SDavid Hildenbrand S390Vector tmp = {}; 4232c806ab4SDavid Hildenbrand int match = 0; 4242c806ab4SDavid Hildenbrand int i; 4252c806ab4SDavid Hildenbrand 4262c806ab4SDavid Hildenbrand for (i = 0; i < 2; i++) { 42764deb65aSDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 42864deb65aSDavid Hildenbrand const float64 b = s390_vec_read_float64(v3, i); 4292c806ab4SDavid Hildenbrand 4302c806ab4SDavid Hildenbrand /* swap the order of the parameters, so we can use existing functions */ 4312c806ab4SDavid Hildenbrand if (fn(b, a, &env->fpu_status)) { 4322c806ab4SDavid Hildenbrand match++; 4332c806ab4SDavid Hildenbrand s390_vec_write_element64(&tmp, i, -1ull); 4342c806ab4SDavid Hildenbrand } 4352c806ab4SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 4362c806ab4SDavid Hildenbrand if (s || vxc) { 4372c806ab4SDavid Hildenbrand break; 4382c806ab4SDavid Hildenbrand } 4392c806ab4SDavid Hildenbrand } 4402c806ab4SDavid Hildenbrand 4412c806ab4SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 4422c806ab4SDavid Hildenbrand *v1 = tmp; 4432c806ab4SDavid Hildenbrand if (match) { 4442c806ab4SDavid Hildenbrand return s || match == 2 ? 0 : 1; 4452c806ab4SDavid Hildenbrand } 4462c806ab4SDavid Hildenbrand return 3; 4472c806ab4SDavid Hildenbrand } 4482c806ab4SDavid Hildenbrand 449e384332cSDavid Hildenbrand typedef bool (*vfc128_fn)(float128 a, float128 b, float_status *status); 450e384332cSDavid Hildenbrand static int vfc128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 451e384332cSDavid Hildenbrand CPUS390XState *env, bool s, vfc128_fn fn, uintptr_t retaddr) 452e384332cSDavid Hildenbrand { 453e384332cSDavid Hildenbrand const float128 a = s390_vec_read_float128(v2); 454e384332cSDavid Hildenbrand const float128 b = s390_vec_read_float128(v3); 455e384332cSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 456e384332cSDavid Hildenbrand S390Vector tmp = {}; 457e384332cSDavid Hildenbrand bool match = false; 458e384332cSDavid Hildenbrand 459e384332cSDavid Hildenbrand /* swap the order of the parameters, so we can use existing functions */ 460e384332cSDavid Hildenbrand if (fn(b, a, &env->fpu_status)) { 461e384332cSDavid Hildenbrand match = true; 462e384332cSDavid Hildenbrand s390_vec_write_element64(&tmp, 0, -1ull); 463e384332cSDavid Hildenbrand s390_vec_write_element64(&tmp, 1, -1ull); 464e384332cSDavid Hildenbrand } 465e384332cSDavid Hildenbrand vxc = check_ieee_exc(env, 0, false, &vec_exc); 466e384332cSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 467e384332cSDavid Hildenbrand *v1 = tmp; 468e384332cSDavid Hildenbrand return match ? 0 : 3; 469e384332cSDavid Hildenbrand } 470e384332cSDavid Hildenbrand 47164deb65aSDavid Hildenbrand #define DEF_GVEC_VFC_B(NAME, OP, BITS) \ 47264deb65aSDavid Hildenbrand void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ 47364deb65aSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 47464deb65aSDavid Hildenbrand { \ 47564deb65aSDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 476e384332cSDavid Hildenbrand const bool sq = extract32(simd_data(desc), 2, 1); \ 477e384332cSDavid Hildenbrand vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet; \ 47864deb65aSDavid Hildenbrand \ 47964deb65aSDavid Hildenbrand vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ 48064deb65aSDavid Hildenbrand } \ 48164deb65aSDavid Hildenbrand \ 48264deb65aSDavid Hildenbrand void HELPER(gvec_##NAME##BITS##_cc)(void *v1, const void *v2, const void *v3, \ 48364deb65aSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 48464deb65aSDavid Hildenbrand { \ 48564deb65aSDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 486e384332cSDavid Hildenbrand const bool sq = extract32(simd_data(desc), 2, 1); \ 487e384332cSDavid Hildenbrand vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet; \ 48864deb65aSDavid Hildenbrand \ 48964deb65aSDavid Hildenbrand env->cc_op = vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ 4902c806ab4SDavid Hildenbrand } 4912c806ab4SDavid Hildenbrand 49264deb65aSDavid Hildenbrand #define DEF_GVEC_VFC(NAME, OP) \ 493e384332cSDavid Hildenbrand DEF_GVEC_VFC_B(NAME, OP, 32) \ 494e384332cSDavid Hildenbrand DEF_GVEC_VFC_B(NAME, OP, 64) \ 495e384332cSDavid Hildenbrand DEF_GVEC_VFC_B(NAME, OP, 128) \ 4962c806ab4SDavid Hildenbrand 49764deb65aSDavid Hildenbrand DEF_GVEC_VFC(vfce, eq) 49864deb65aSDavid Hildenbrand DEF_GVEC_VFC(vfch, lt) 49964deb65aSDavid Hildenbrand DEF_GVEC_VFC(vfche, le) 500bb03fd84SDavid Hildenbrand 501860b707bSDavid Hildenbrand void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env, 502860b707bSDavid Hildenbrand uint32_t desc) 5031a76e59dSDavid Hildenbrand { 504860b707bSDavid Hildenbrand const bool s = extract32(simd_data(desc), 3, 1); 5051a76e59dSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 5061a76e59dSDavid Hildenbrand S390Vector tmp = {}; 5071a76e59dSDavid Hildenbrand int i; 5081a76e59dSDavid Hildenbrand 5091a76e59dSDavid Hildenbrand for (i = 0; i < 2; i++) { 5101a76e59dSDavid Hildenbrand /* load from even element */ 5111a76e59dSDavid Hildenbrand const float32 a = s390_vec_read_element32(v2, i * 2); 5121a76e59dSDavid Hildenbrand const uint64_t ret = float32_to_float64(a, &env->fpu_status); 5131a76e59dSDavid Hildenbrand 5141a76e59dSDavid Hildenbrand s390_vec_write_element64(&tmp, i, ret); 5151a76e59dSDavid Hildenbrand /* indicate the source element */ 5161a76e59dSDavid Hildenbrand vxc = check_ieee_exc(env, i * 2, false, &vec_exc); 5171a76e59dSDavid Hildenbrand if (s || vxc) { 5181a76e59dSDavid Hildenbrand break; 5191a76e59dSDavid Hildenbrand } 5201a76e59dSDavid Hildenbrand } 521860b707bSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, GETPC()); 522860b707bSDavid Hildenbrand *(S390Vector *)v1 = tmp; 5231a76e59dSDavid Hildenbrand } 5244500ede4SDavid Hildenbrand 5252e96005eSDavid Hildenbrand void HELPER(gvec_vfll64)(void *v1, const void *v2, CPUS390XState *env, 5262e96005eSDavid Hildenbrand uint32_t desc) 5272e96005eSDavid Hildenbrand { 5282e96005eSDavid Hildenbrand /* load from even element */ 5292e96005eSDavid Hildenbrand const float128 ret = float64_to_float128(s390_vec_read_float64(v2, 0), 5302e96005eSDavid Hildenbrand &env->fpu_status); 5312e96005eSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 5322e96005eSDavid Hildenbrand 5332e96005eSDavid Hildenbrand vxc = check_ieee_exc(env, 0, false, &vec_exc); 5342e96005eSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, GETPC()); 5352e96005eSDavid Hildenbrand s390_vec_write_float128(v1, ret); 5362e96005eSDavid Hildenbrand } 5372e96005eSDavid Hildenbrand 538977e43d9SDavid Hildenbrand void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env, 539977e43d9SDavid Hildenbrand uint32_t desc) 5404500ede4SDavid Hildenbrand { 541977e43d9SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 542977e43d9SDavid Hildenbrand const bool s = extract32(simd_data(desc), 3, 1); 543977e43d9SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 5444500ede4SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 5454500ede4SDavid Hildenbrand S390Vector tmp = {}; 5464500ede4SDavid Hildenbrand int i, old_mode; 5474500ede4SDavid Hildenbrand 5484500ede4SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 5494500ede4SDavid Hildenbrand for (i = 0; i < 2; i++) { 5504500ede4SDavid Hildenbrand float64 a = s390_vec_read_element64(v2, i); 5514500ede4SDavid Hildenbrand uint32_t ret = float64_to_float32(a, &env->fpu_status); 5524500ede4SDavid Hildenbrand 5534500ede4SDavid Hildenbrand /* place at even element */ 5544500ede4SDavid Hildenbrand s390_vec_write_element32(&tmp, i * 2, ret); 5554500ede4SDavid Hildenbrand /* indicate the source element */ 5564500ede4SDavid Hildenbrand vxc = check_ieee_exc(env, i, XxC, &vec_exc); 5574500ede4SDavid Hildenbrand if (s || vxc) { 5584500ede4SDavid Hildenbrand break; 5594500ede4SDavid Hildenbrand } 5604500ede4SDavid Hildenbrand } 5614500ede4SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 562977e43d9SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, GETPC()); 563977e43d9SDavid Hildenbrand *(S390Vector *)v1 = tmp; 5644500ede4SDavid Hildenbrand } 5658d47d4d2SDavid Hildenbrand 5669cbc8be0SDavid Hildenbrand void HELPER(gvec_vflr128)(void *v1, const void *v2, CPUS390XState *env, 5679cbc8be0SDavid Hildenbrand uint32_t desc) 5689cbc8be0SDavid Hildenbrand { 5699cbc8be0SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 5709cbc8be0SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 5719cbc8be0SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 5729cbc8be0SDavid Hildenbrand int old_mode; 5739cbc8be0SDavid Hildenbrand float64 ret; 5749cbc8be0SDavid Hildenbrand 5759cbc8be0SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 5769cbc8be0SDavid Hildenbrand ret = float128_to_float64(s390_vec_read_float128(v2), &env->fpu_status); 5779cbc8be0SDavid Hildenbrand vxc = check_ieee_exc(env, 0, XxC, &vec_exc); 5789cbc8be0SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 5799cbc8be0SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, GETPC()); 5809cbc8be0SDavid Hildenbrand 5819cbc8be0SDavid Hildenbrand /* place at even element, odd element is unpredictable */ 5829cbc8be0SDavid Hildenbrand s390_vec_write_float64(v1, 0, ret); 5839cbc8be0SDavid Hildenbrand } 5849cbc8be0SDavid Hildenbrand 585c64c5984SDavid Hildenbrand static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 586c64c5984SDavid Hildenbrand const S390Vector *v4, CPUS390XState *env, bool s, int flags, 587c64c5984SDavid Hildenbrand uintptr_t retaddr) 588c64c5984SDavid Hildenbrand { 589c64c5984SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 590c64c5984SDavid Hildenbrand S390Vector tmp = {}; 591c64c5984SDavid Hildenbrand int i; 592c64c5984SDavid Hildenbrand 593c64c5984SDavid Hildenbrand for (i = 0; i < 2; i++) { 59434142ffdSDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 59534142ffdSDavid Hildenbrand const float64 b = s390_vec_read_float64(v3, i); 59634142ffdSDavid Hildenbrand const float64 c = s390_vec_read_float64(v4, i); 59734142ffdSDavid Hildenbrand const float64 ret = float64_muladd(a, b, c, flags, &env->fpu_status); 598c64c5984SDavid Hildenbrand 59934142ffdSDavid Hildenbrand s390_vec_write_float64(&tmp, i, ret); 600c64c5984SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 601c64c5984SDavid Hildenbrand if (s || vxc) { 602c64c5984SDavid Hildenbrand break; 603c64c5984SDavid Hildenbrand } 604c64c5984SDavid Hildenbrand } 605c64c5984SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 606c64c5984SDavid Hildenbrand *v1 = tmp; 607c64c5984SDavid Hildenbrand } 608c64c5984SDavid Hildenbrand 60934142ffdSDavid Hildenbrand #define DEF_GVEC_VFMA_B(NAME, FLAGS, BITS) \ 61034142ffdSDavid Hildenbrand void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ 61134142ffdSDavid Hildenbrand const void *v4, CPUS390XState *env, \ 61234142ffdSDavid Hildenbrand uint32_t desc) \ 61334142ffdSDavid Hildenbrand { \ 61434142ffdSDavid Hildenbrand const bool se = extract32(simd_data(desc), 3, 1); \ 61534142ffdSDavid Hildenbrand \ 61634142ffdSDavid Hildenbrand vfma##BITS(v1, v2, v3, v4, env, se, FLAGS, GETPC()); \ 617c64c5984SDavid Hildenbrand } 618c64c5984SDavid Hildenbrand 61934142ffdSDavid Hildenbrand #define DEF_GVEC_VFMA(NAME, FLAGS) \ 62034142ffdSDavid Hildenbrand DEF_GVEC_VFMA_B(NAME, FLAGS, 64) 621c64c5984SDavid Hildenbrand 62234142ffdSDavid Hildenbrand DEF_GVEC_VFMA(vfma, 0) 62334142ffdSDavid Hildenbrand DEF_GVEC_VFMA(vfms, float_muladd_negate_c) 6245938f20cSDavid Hildenbrand 625*a38b5a0eSDavid Hildenbrand void HELPER(gvec_vftci32)(void *v1, const void *v2, CPUS390XState *env, 626*a38b5a0eSDavid Hildenbrand uint32_t desc) 627*a38b5a0eSDavid Hildenbrand { 628*a38b5a0eSDavid Hildenbrand uint16_t i3 = extract32(simd_data(desc), 4, 12); 629*a38b5a0eSDavid Hildenbrand bool s = extract32(simd_data(desc), 3, 1); 630*a38b5a0eSDavid Hildenbrand int i, match = 0; 631*a38b5a0eSDavid Hildenbrand 632*a38b5a0eSDavid Hildenbrand for (i = 0; i < 4; i++) { 633*a38b5a0eSDavid Hildenbrand float32 a = s390_vec_read_float32(v2, i); 634*a38b5a0eSDavid Hildenbrand 635*a38b5a0eSDavid Hildenbrand if (float32_dcmask(env, a) & i3) { 636*a38b5a0eSDavid Hildenbrand match++; 637*a38b5a0eSDavid Hildenbrand s390_vec_write_element32(v1, i, -1u); 638*a38b5a0eSDavid Hildenbrand } else { 639*a38b5a0eSDavid Hildenbrand s390_vec_write_element32(v1, i, 0); 640*a38b5a0eSDavid Hildenbrand } 641*a38b5a0eSDavid Hildenbrand if (s) { 642*a38b5a0eSDavid Hildenbrand break; 643*a38b5a0eSDavid Hildenbrand } 644*a38b5a0eSDavid Hildenbrand } 645*a38b5a0eSDavid Hildenbrand 646*a38b5a0eSDavid Hildenbrand if (match == 4 || (s && match)) { 647*a38b5a0eSDavid Hildenbrand env->cc_op = 0; 648*a38b5a0eSDavid Hildenbrand } else if (match) { 649*a38b5a0eSDavid Hildenbrand env->cc_op = 1; 650*a38b5a0eSDavid Hildenbrand } else { 651*a38b5a0eSDavid Hildenbrand env->cc_op = 3; 652*a38b5a0eSDavid Hildenbrand } 653*a38b5a0eSDavid Hildenbrand } 654*a38b5a0eSDavid Hildenbrand 655622ebe64SDavid Hildenbrand void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env, 656622ebe64SDavid Hildenbrand uint32_t desc) 65783b955f9SDavid Hildenbrand { 658622ebe64SDavid Hildenbrand const uint16_t i3 = extract32(simd_data(desc), 4, 12); 659622ebe64SDavid Hildenbrand const bool s = extract32(simd_data(desc), 3, 1); 66083b955f9SDavid Hildenbrand int i, match = 0; 66183b955f9SDavid Hildenbrand 66283b955f9SDavid Hildenbrand for (i = 0; i < 2; i++) { 663622ebe64SDavid Hildenbrand const float64 a = s390_vec_read_float64(v2, i); 66483b955f9SDavid Hildenbrand 66583b955f9SDavid Hildenbrand if (float64_dcmask(env, a) & i3) { 66683b955f9SDavid Hildenbrand match++; 66783b955f9SDavid Hildenbrand s390_vec_write_element64(v1, i, -1ull); 66883b955f9SDavid Hildenbrand } else { 66983b955f9SDavid Hildenbrand s390_vec_write_element64(v1, i, 0); 67083b955f9SDavid Hildenbrand } 67183b955f9SDavid Hildenbrand if (s) { 67283b955f9SDavid Hildenbrand break; 67383b955f9SDavid Hildenbrand } 67483b955f9SDavid Hildenbrand } 67583b955f9SDavid Hildenbrand 676622ebe64SDavid Hildenbrand if (match == 2 || (s && match)) { 677622ebe64SDavid Hildenbrand env->cc_op = 0; 678622ebe64SDavid Hildenbrand } else if (match) { 679622ebe64SDavid Hildenbrand env->cc_op = 1; 680622ebe64SDavid Hildenbrand } else { 681622ebe64SDavid Hildenbrand env->cc_op = 3; 68283b955f9SDavid Hildenbrand } 68383b955f9SDavid Hildenbrand } 684*a38b5a0eSDavid Hildenbrand 685*a38b5a0eSDavid Hildenbrand void HELPER(gvec_vftci128)(void *v1, const void *v2, CPUS390XState *env, 686*a38b5a0eSDavid Hildenbrand uint32_t desc) 687*a38b5a0eSDavid Hildenbrand { 688*a38b5a0eSDavid Hildenbrand const float128 a = s390_vec_read_float128(v2); 689*a38b5a0eSDavid Hildenbrand uint16_t i3 = extract32(simd_data(desc), 4, 12); 690*a38b5a0eSDavid Hildenbrand 691*a38b5a0eSDavid Hildenbrand if (float128_dcmask(env, a) & i3) { 692*a38b5a0eSDavid Hildenbrand env->cc_op = 0; 693*a38b5a0eSDavid Hildenbrand s390_vec_write_element64(v1, 0, -1ull); 694*a38b5a0eSDavid Hildenbrand s390_vec_write_element64(v1, 1, -1ull); 695*a38b5a0eSDavid Hildenbrand } else { 696*a38b5a0eSDavid Hildenbrand env->cc_op = 3; 697*a38b5a0eSDavid Hildenbrand s390_vec_write_element64(v1, 0, 0); 698*a38b5a0eSDavid Hildenbrand s390_vec_write_element64(v1, 1, 0); 699*a38b5a0eSDavid Hildenbrand } 700*a38b5a0eSDavid Hildenbrand } 701