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 81bb03fd84SDavid Hildenbrand typedef uint64_t (*vop64_2_fn)(uint64_t a, float_status *s); 82bb03fd84SDavid Hildenbrand static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 83bb03fd84SDavid Hildenbrand bool s, bool XxC, uint8_t erm, vop64_2_fn fn, 84bb03fd84SDavid Hildenbrand uintptr_t retaddr) 85bb03fd84SDavid Hildenbrand { 86bb03fd84SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 87bb03fd84SDavid Hildenbrand S390Vector tmp = {}; 88bb03fd84SDavid Hildenbrand int i, old_mode; 89bb03fd84SDavid Hildenbrand 90bb03fd84SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 91bb03fd84SDavid Hildenbrand for (i = 0; i < 2; i++) { 92bb03fd84SDavid Hildenbrand const uint64_t a = s390_vec_read_element64(v2, i); 93bb03fd84SDavid Hildenbrand 94bb03fd84SDavid Hildenbrand s390_vec_write_element64(&tmp, i, fn(a, &env->fpu_status)); 95bb03fd84SDavid Hildenbrand vxc = check_ieee_exc(env, i, XxC, &vec_exc); 96bb03fd84SDavid Hildenbrand if (s || vxc) { 97bb03fd84SDavid Hildenbrand break; 98bb03fd84SDavid Hildenbrand } 99bb03fd84SDavid Hildenbrand } 100bb03fd84SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 101bb03fd84SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 102bb03fd84SDavid Hildenbrand *v1 = tmp; 103bb03fd84SDavid Hildenbrand } 104bb03fd84SDavid Hildenbrand 1053a0eae85SDavid Hildenbrand typedef uint64_t (*vop64_3_fn)(uint64_t a, uint64_t b, float_status *s); 1063a0eae85SDavid Hildenbrand static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 1073a0eae85SDavid Hildenbrand CPUS390XState *env, bool s, vop64_3_fn fn, 1083a0eae85SDavid Hildenbrand uintptr_t retaddr) 1093a0eae85SDavid Hildenbrand { 1103a0eae85SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 1113a0eae85SDavid Hildenbrand S390Vector tmp = {}; 1123a0eae85SDavid Hildenbrand int i; 1133a0eae85SDavid Hildenbrand 1143a0eae85SDavid Hildenbrand for (i = 0; i < 2; i++) { 1153a0eae85SDavid Hildenbrand const uint64_t a = s390_vec_read_element64(v2, i); 1163a0eae85SDavid Hildenbrand const uint64_t b = s390_vec_read_element64(v3, i); 1173a0eae85SDavid Hildenbrand 1183a0eae85SDavid Hildenbrand s390_vec_write_element64(&tmp, i, fn(a, b, &env->fpu_status)); 1193a0eae85SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 1203a0eae85SDavid Hildenbrand if (s || vxc) { 1213a0eae85SDavid Hildenbrand break; 1223a0eae85SDavid Hildenbrand } 1233a0eae85SDavid Hildenbrand } 1243a0eae85SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 1253a0eae85SDavid Hildenbrand *v1 = tmp; 1263a0eae85SDavid Hildenbrand } 1273a0eae85SDavid Hildenbrand 1283a0eae85SDavid Hildenbrand static uint64_t vfa64(uint64_t a, uint64_t b, float_status *s) 1293a0eae85SDavid Hildenbrand { 1303a0eae85SDavid Hildenbrand return float64_add(a, b, s); 1313a0eae85SDavid Hildenbrand } 1323a0eae85SDavid Hildenbrand 1333a0eae85SDavid Hildenbrand void HELPER(gvec_vfa64)(void *v1, const void *v2, const void *v3, 1343a0eae85SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 1353a0eae85SDavid Hildenbrand { 1363a0eae85SDavid Hildenbrand vop64_3(v1, v2, v3, env, false, vfa64, GETPC()); 1373a0eae85SDavid Hildenbrand } 1383a0eae85SDavid Hildenbrand 1393a0eae85SDavid Hildenbrand void HELPER(gvec_vfa64s)(void *v1, const void *v2, const void *v3, 1403a0eae85SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 1413a0eae85SDavid Hildenbrand { 1423a0eae85SDavid Hildenbrand vop64_3(v1, v2, v3, env, true, vfa64, GETPC()); 1433a0eae85SDavid Hildenbrand } 1445b89f0fbSDavid Hildenbrand 1455b89f0fbSDavid Hildenbrand static int wfc64(const S390Vector *v1, const S390Vector *v2, 1465b89f0fbSDavid Hildenbrand CPUS390XState *env, bool signal, uintptr_t retaddr) 1475b89f0fbSDavid Hildenbrand { 1485b89f0fbSDavid Hildenbrand /* only the zero-indexed elements are compared */ 1495b89f0fbSDavid Hildenbrand const float64 a = s390_vec_read_element64(v1, 0); 1505b89f0fbSDavid Hildenbrand const float64 b = s390_vec_read_element64(v2, 0); 1515b89f0fbSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 1525b89f0fbSDavid Hildenbrand int cmp; 1535b89f0fbSDavid Hildenbrand 1545b89f0fbSDavid Hildenbrand if (signal) { 1555b89f0fbSDavid Hildenbrand cmp = float64_compare(a, b, &env->fpu_status); 1565b89f0fbSDavid Hildenbrand } else { 1575b89f0fbSDavid Hildenbrand cmp = float64_compare_quiet(a, b, &env->fpu_status); 1585b89f0fbSDavid Hildenbrand } 1595b89f0fbSDavid Hildenbrand vxc = check_ieee_exc(env, 0, false, &vec_exc); 1605b89f0fbSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 1615b89f0fbSDavid Hildenbrand 1625b89f0fbSDavid Hildenbrand return float_comp_to_cc(env, cmp); 1635b89f0fbSDavid Hildenbrand } 1645b89f0fbSDavid Hildenbrand 1655b89f0fbSDavid Hildenbrand void HELPER(gvec_wfc64)(const void *v1, const void *v2, CPUS390XState *env, 1665b89f0fbSDavid Hildenbrand uint32_t desc) 1675b89f0fbSDavid Hildenbrand { 1685b89f0fbSDavid Hildenbrand env->cc_op = wfc64(v1, v2, env, false, GETPC()); 1695b89f0fbSDavid Hildenbrand } 1705b89f0fbSDavid Hildenbrand 1715b89f0fbSDavid Hildenbrand void HELPER(gvec_wfk64)(const void *v1, const void *v2, CPUS390XState *env, 1725b89f0fbSDavid Hildenbrand uint32_t desc) 1735b89f0fbSDavid Hildenbrand { 1745b89f0fbSDavid Hildenbrand env->cc_op = wfc64(v1, v2, env, true, GETPC()); 1755b89f0fbSDavid Hildenbrand } 1762c806ab4SDavid Hildenbrand 1772c806ab4SDavid Hildenbrand typedef int (*vfc64_fn)(float64 a, float64 b, float_status *status); 1782c806ab4SDavid Hildenbrand static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 1792c806ab4SDavid Hildenbrand CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr) 1802c806ab4SDavid Hildenbrand { 1812c806ab4SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 1822c806ab4SDavid Hildenbrand S390Vector tmp = {}; 1832c806ab4SDavid Hildenbrand int match = 0; 1842c806ab4SDavid Hildenbrand int i; 1852c806ab4SDavid Hildenbrand 1862c806ab4SDavid Hildenbrand for (i = 0; i < 2; i++) { 1872c806ab4SDavid Hildenbrand const float64 a = s390_vec_read_element64(v2, i); 1882c806ab4SDavid Hildenbrand const float64 b = s390_vec_read_element64(v3, i); 1892c806ab4SDavid Hildenbrand 1902c806ab4SDavid Hildenbrand /* swap the order of the parameters, so we can use existing functions */ 1912c806ab4SDavid Hildenbrand if (fn(b, a, &env->fpu_status)) { 1922c806ab4SDavid Hildenbrand match++; 1932c806ab4SDavid Hildenbrand s390_vec_write_element64(&tmp, i, -1ull); 1942c806ab4SDavid Hildenbrand } 1952c806ab4SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 1962c806ab4SDavid Hildenbrand if (s || vxc) { 1972c806ab4SDavid Hildenbrand break; 1982c806ab4SDavid Hildenbrand } 1992c806ab4SDavid Hildenbrand } 2002c806ab4SDavid Hildenbrand 2012c806ab4SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 2022c806ab4SDavid Hildenbrand *v1 = tmp; 2032c806ab4SDavid Hildenbrand if (match) { 2042c806ab4SDavid Hildenbrand return s || match == 2 ? 0 : 1; 2052c806ab4SDavid Hildenbrand } 2062c806ab4SDavid Hildenbrand return 3; 2072c806ab4SDavid Hildenbrand } 2082c806ab4SDavid Hildenbrand 2092c806ab4SDavid Hildenbrand void HELPER(gvec_vfce64)(void *v1, const void *v2, const void *v3, 2102c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2112c806ab4SDavid Hildenbrand { 2122c806ab4SDavid Hildenbrand vfc64(v1, v2, v3, env, false, float64_eq_quiet, GETPC()); 2132c806ab4SDavid Hildenbrand } 2142c806ab4SDavid Hildenbrand 2152c806ab4SDavid Hildenbrand void HELPER(gvec_vfce64s)(void *v1, const void *v2, const void *v3, 2162c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2172c806ab4SDavid Hildenbrand { 2182c806ab4SDavid Hildenbrand vfc64(v1, v2, v3, env, true, float64_eq_quiet, GETPC()); 2192c806ab4SDavid Hildenbrand } 2202c806ab4SDavid Hildenbrand 2212c806ab4SDavid Hildenbrand void HELPER(gvec_vfce64_cc)(void *v1, const void *v2, const void *v3, 2222c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2232c806ab4SDavid Hildenbrand { 2242c806ab4SDavid Hildenbrand env->cc_op = vfc64(v1, v2, v3, env, false, float64_eq_quiet, GETPC()); 2252c806ab4SDavid Hildenbrand } 2262c806ab4SDavid Hildenbrand 2272c806ab4SDavid Hildenbrand void HELPER(gvec_vfce64s_cc)(void *v1, const void *v2, const void *v3, 2282c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2292c806ab4SDavid Hildenbrand { 2302c806ab4SDavid Hildenbrand env->cc_op = vfc64(v1, v2, v3, env, true, float64_eq_quiet, GETPC()); 2312c806ab4SDavid Hildenbrand } 2322c806ab4SDavid Hildenbrand 2332c806ab4SDavid Hildenbrand void HELPER(gvec_vfch64)(void *v1, const void *v2, const void *v3, 2342c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2352c806ab4SDavid Hildenbrand { 2362c806ab4SDavid Hildenbrand vfc64(v1, v2, v3, env, false, float64_lt_quiet, GETPC()); 2372c806ab4SDavid Hildenbrand } 2382c806ab4SDavid Hildenbrand 2392c806ab4SDavid Hildenbrand void HELPER(gvec_vfch64s)(void *v1, const void *v2, const void *v3, 2402c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2412c806ab4SDavid Hildenbrand { 2422c806ab4SDavid Hildenbrand vfc64(v1, v2, v3, env, true, float64_lt_quiet, GETPC()); 2432c806ab4SDavid Hildenbrand } 2442c806ab4SDavid Hildenbrand 2452c806ab4SDavid Hildenbrand void HELPER(gvec_vfch64_cc)(void *v1, const void *v2, const void *v3, 2462c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2472c806ab4SDavid Hildenbrand { 2482c806ab4SDavid Hildenbrand env->cc_op = vfc64(v1, v2, v3, env, false, float64_lt_quiet, GETPC()); 2492c806ab4SDavid Hildenbrand } 2502c806ab4SDavid Hildenbrand 2512c806ab4SDavid Hildenbrand void HELPER(gvec_vfch64s_cc)(void *v1, const void *v2, const void *v3, 2522c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2532c806ab4SDavid Hildenbrand { 2542c806ab4SDavid Hildenbrand env->cc_op = vfc64(v1, v2, v3, env, true, float64_lt_quiet, GETPC()); 2552c806ab4SDavid Hildenbrand } 2562c806ab4SDavid Hildenbrand 2572c806ab4SDavid Hildenbrand void HELPER(gvec_vfche64)(void *v1, const void *v2, const void *v3, 2582c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2592c806ab4SDavid Hildenbrand { 2602c806ab4SDavid Hildenbrand vfc64(v1, v2, v3, env, false, float64_le_quiet, GETPC()); 2612c806ab4SDavid Hildenbrand } 2622c806ab4SDavid Hildenbrand 2632c806ab4SDavid Hildenbrand void HELPER(gvec_vfche64s)(void *v1, const void *v2, const void *v3, 2642c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2652c806ab4SDavid Hildenbrand { 2662c806ab4SDavid Hildenbrand vfc64(v1, v2, v3, env, true, float64_le_quiet, GETPC()); 2672c806ab4SDavid Hildenbrand } 2682c806ab4SDavid Hildenbrand 2692c806ab4SDavid Hildenbrand void HELPER(gvec_vfche64_cc)(void *v1, const void *v2, const void *v3, 2702c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2712c806ab4SDavid Hildenbrand { 2722c806ab4SDavid Hildenbrand env->cc_op = vfc64(v1, v2, v3, env, false, float64_le_quiet, GETPC()); 2732c806ab4SDavid Hildenbrand } 2742c806ab4SDavid Hildenbrand 2752c806ab4SDavid Hildenbrand void HELPER(gvec_vfche64s_cc)(void *v1, const void *v2, const void *v3, 2762c806ab4SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 2772c806ab4SDavid Hildenbrand { 2782c806ab4SDavid Hildenbrand env->cc_op = vfc64(v1, v2, v3, env, true, float64_le_quiet, GETPC()); 2792c806ab4SDavid Hildenbrand } 280bb03fd84SDavid Hildenbrand 281bb03fd84SDavid Hildenbrand static uint64_t vcdg64(uint64_t a, float_status *s) 282bb03fd84SDavid Hildenbrand { 283bb03fd84SDavid Hildenbrand return int64_to_float64(a, s); 284bb03fd84SDavid Hildenbrand } 285bb03fd84SDavid Hildenbrand 286bb03fd84SDavid Hildenbrand void HELPER(gvec_vcdg64)(void *v1, const void *v2, CPUS390XState *env, 287bb03fd84SDavid Hildenbrand uint32_t desc) 288bb03fd84SDavid Hildenbrand { 289bb03fd84SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 290bb03fd84SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 291bb03fd84SDavid Hildenbrand 292bb03fd84SDavid Hildenbrand vop64_2(v1, v2, env, false, XxC, erm, vcdg64, GETPC()); 293bb03fd84SDavid Hildenbrand } 294bb03fd84SDavid Hildenbrand 295bb03fd84SDavid Hildenbrand void HELPER(gvec_vcdg64s)(void *v1, const void *v2, CPUS390XState *env, 296bb03fd84SDavid Hildenbrand uint32_t desc) 297bb03fd84SDavid Hildenbrand { 298bb03fd84SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 299bb03fd84SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 300bb03fd84SDavid Hildenbrand 301bb03fd84SDavid Hildenbrand vop64_2(v1, v2, env, true, XxC, erm, vcdg64, GETPC()); 302bb03fd84SDavid Hildenbrand } 3039b8d1a38SDavid Hildenbrand 3049b8d1a38SDavid Hildenbrand static uint64_t vcdlg64(uint64_t a, float_status *s) 3059b8d1a38SDavid Hildenbrand { 3069b8d1a38SDavid Hildenbrand return uint64_to_float64(a, s); 3079b8d1a38SDavid Hildenbrand } 3089b8d1a38SDavid Hildenbrand 3099b8d1a38SDavid Hildenbrand void HELPER(gvec_vcdlg64)(void *v1, const void *v2, CPUS390XState *env, 3109b8d1a38SDavid Hildenbrand uint32_t desc) 3119b8d1a38SDavid Hildenbrand { 3129b8d1a38SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 3139b8d1a38SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 3149b8d1a38SDavid Hildenbrand 3159b8d1a38SDavid Hildenbrand vop64_2(v1, v2, env, false, XxC, erm, vcdlg64, GETPC()); 3169b8d1a38SDavid Hildenbrand } 3179b8d1a38SDavid Hildenbrand 3189b8d1a38SDavid Hildenbrand void HELPER(gvec_vcdlg64s)(void *v1, const void *v2, CPUS390XState *env, 3199b8d1a38SDavid Hildenbrand uint32_t desc) 3209b8d1a38SDavid Hildenbrand { 3219b8d1a38SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 3229b8d1a38SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 3239b8d1a38SDavid Hildenbrand 3249b8d1a38SDavid Hildenbrand vop64_2(v1, v2, env, true, XxC, erm, vcdlg64, GETPC()); 3259b8d1a38SDavid Hildenbrand } 32635b3bb1cSDavid Hildenbrand 32735b3bb1cSDavid Hildenbrand static uint64_t vcgd64(uint64_t a, float_status *s) 32835b3bb1cSDavid Hildenbrand { 32935b3bb1cSDavid Hildenbrand return float64_to_int64(a, s); 33035b3bb1cSDavid Hildenbrand } 33135b3bb1cSDavid Hildenbrand 33235b3bb1cSDavid Hildenbrand void HELPER(gvec_vcgd64)(void *v1, const void *v2, CPUS390XState *env, 33335b3bb1cSDavid Hildenbrand uint32_t desc) 33435b3bb1cSDavid Hildenbrand { 33535b3bb1cSDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 33635b3bb1cSDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 33735b3bb1cSDavid Hildenbrand 33835b3bb1cSDavid Hildenbrand vop64_2(v1, v2, env, false, XxC, erm, vcgd64, GETPC()); 33935b3bb1cSDavid Hildenbrand } 34035b3bb1cSDavid Hildenbrand 34135b3bb1cSDavid Hildenbrand void HELPER(gvec_vcgd64s)(void *v1, const void *v2, CPUS390XState *env, 34235b3bb1cSDavid Hildenbrand uint32_t desc) 34335b3bb1cSDavid Hildenbrand { 34435b3bb1cSDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 34535b3bb1cSDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 34635b3bb1cSDavid Hildenbrand 34735b3bb1cSDavid Hildenbrand vop64_2(v1, v2, env, true, XxC, erm, vcgd64, GETPC()); 34835b3bb1cSDavid Hildenbrand } 34909c04e4bSDavid Hildenbrand 35009c04e4bSDavid Hildenbrand static uint64_t vclgd64(uint64_t a, float_status *s) 35109c04e4bSDavid Hildenbrand { 35209c04e4bSDavid Hildenbrand return float64_to_uint64(a, s); 35309c04e4bSDavid Hildenbrand } 35409c04e4bSDavid Hildenbrand 35509c04e4bSDavid Hildenbrand void HELPER(gvec_vclgd64)(void *v1, const void *v2, CPUS390XState *env, 35609c04e4bSDavid Hildenbrand uint32_t desc) 35709c04e4bSDavid Hildenbrand { 35809c04e4bSDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 35909c04e4bSDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 36009c04e4bSDavid Hildenbrand 36109c04e4bSDavid Hildenbrand vop64_2(v1, v2, env, false, XxC, erm, vclgd64, GETPC()); 36209c04e4bSDavid Hildenbrand } 36309c04e4bSDavid Hildenbrand 36409c04e4bSDavid Hildenbrand void HELPER(gvec_vclgd64s)(void *v1, const void *v2, CPUS390XState *env, 36509c04e4bSDavid Hildenbrand uint32_t desc) 36609c04e4bSDavid Hildenbrand { 36709c04e4bSDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 36809c04e4bSDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 36909c04e4bSDavid Hildenbrand 37009c04e4bSDavid Hildenbrand vop64_2(v1, v2, env, true, XxC, erm, vclgd64, GETPC()); 37109c04e4bSDavid Hildenbrand } 372817a1cecSDavid Hildenbrand 373817a1cecSDavid Hildenbrand static uint64_t vfd64(uint64_t a, uint64_t b, float_status *s) 374817a1cecSDavid Hildenbrand { 375817a1cecSDavid Hildenbrand return float64_div(a, b, s); 376817a1cecSDavid Hildenbrand } 377817a1cecSDavid Hildenbrand 378817a1cecSDavid Hildenbrand void HELPER(gvec_vfd64)(void *v1, const void *v2, const void *v3, 379817a1cecSDavid Hildenbrand CPUS390XState *env, uint32_t desc) 380817a1cecSDavid Hildenbrand { 381817a1cecSDavid Hildenbrand vop64_3(v1, v2, v3, env, false, vfd64, GETPC()); 382817a1cecSDavid Hildenbrand } 383817a1cecSDavid Hildenbrand 384817a1cecSDavid Hildenbrand void HELPER(gvec_vfd64s)(void *v1, const void *v2, const void *v3, 385817a1cecSDavid Hildenbrand CPUS390XState *env, uint32_t desc) 386817a1cecSDavid Hildenbrand { 387817a1cecSDavid Hildenbrand vop64_3(v1, v2, v3, env, true, vfd64, GETPC()); 388817a1cecSDavid Hildenbrand } 38960d0ab29SDavid Hildenbrand 39060d0ab29SDavid Hildenbrand static uint64_t vfi64(uint64_t a, float_status *s) 39160d0ab29SDavid Hildenbrand { 39260d0ab29SDavid Hildenbrand return float64_round_to_int(a, s); 39360d0ab29SDavid Hildenbrand } 39460d0ab29SDavid Hildenbrand 39560d0ab29SDavid Hildenbrand void HELPER(gvec_vfi64)(void *v1, const void *v2, CPUS390XState *env, 39660d0ab29SDavid Hildenbrand uint32_t desc) 39760d0ab29SDavid Hildenbrand { 39860d0ab29SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 39960d0ab29SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 40060d0ab29SDavid Hildenbrand 40160d0ab29SDavid Hildenbrand vop64_2(v1, v2, env, false, XxC, erm, vfi64, GETPC()); 40260d0ab29SDavid Hildenbrand } 40360d0ab29SDavid Hildenbrand 40460d0ab29SDavid Hildenbrand void HELPER(gvec_vfi64s)(void *v1, const void *v2, CPUS390XState *env, 40560d0ab29SDavid Hildenbrand uint32_t desc) 40660d0ab29SDavid Hildenbrand { 40760d0ab29SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 40860d0ab29SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 40960d0ab29SDavid Hildenbrand 41060d0ab29SDavid Hildenbrand vop64_2(v1, v2, env, true, XxC, erm, vfi64, GETPC()); 41160d0ab29SDavid Hildenbrand } 4121a76e59dSDavid Hildenbrand 4131a76e59dSDavid Hildenbrand static void vfll32(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 4141a76e59dSDavid Hildenbrand bool s, uintptr_t retaddr) 4151a76e59dSDavid Hildenbrand { 4161a76e59dSDavid Hildenbrand uint8_t vxc, vec_exc = 0; 4171a76e59dSDavid Hildenbrand S390Vector tmp = {}; 4181a76e59dSDavid Hildenbrand int i; 4191a76e59dSDavid Hildenbrand 4201a76e59dSDavid Hildenbrand for (i = 0; i < 2; i++) { 4211a76e59dSDavid Hildenbrand /* load from even element */ 4221a76e59dSDavid Hildenbrand const float32 a = s390_vec_read_element32(v2, i * 2); 4231a76e59dSDavid Hildenbrand const uint64_t ret = float32_to_float64(a, &env->fpu_status); 4241a76e59dSDavid Hildenbrand 4251a76e59dSDavid Hildenbrand s390_vec_write_element64(&tmp, i, ret); 4261a76e59dSDavid Hildenbrand /* indicate the source element */ 4271a76e59dSDavid Hildenbrand vxc = check_ieee_exc(env, i * 2, false, &vec_exc); 4281a76e59dSDavid Hildenbrand if (s || vxc) { 4291a76e59dSDavid Hildenbrand break; 4301a76e59dSDavid Hildenbrand } 4311a76e59dSDavid Hildenbrand } 4321a76e59dSDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 4331a76e59dSDavid Hildenbrand *v1 = tmp; 4341a76e59dSDavid Hildenbrand } 4351a76e59dSDavid Hildenbrand 4361a76e59dSDavid Hildenbrand void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env, 4371a76e59dSDavid Hildenbrand uint32_t desc) 4381a76e59dSDavid Hildenbrand { 4391a76e59dSDavid Hildenbrand vfll32(v1, v2, env, false, GETPC()); 4401a76e59dSDavid Hildenbrand } 4411a76e59dSDavid Hildenbrand 4421a76e59dSDavid Hildenbrand void HELPER(gvec_vfll32s)(void *v1, const void *v2, CPUS390XState *env, 4431a76e59dSDavid Hildenbrand uint32_t desc) 4441a76e59dSDavid Hildenbrand { 4451a76e59dSDavid Hildenbrand vfll32(v1, v2, env, true, GETPC()); 4461a76e59dSDavid Hildenbrand } 4474500ede4SDavid Hildenbrand 4484500ede4SDavid Hildenbrand static void vflr64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, 4494500ede4SDavid Hildenbrand bool s, bool XxC, uint8_t erm, uintptr_t retaddr) 4504500ede4SDavid Hildenbrand { 4514500ede4SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 4524500ede4SDavid Hildenbrand S390Vector tmp = {}; 4534500ede4SDavid Hildenbrand int i, old_mode; 4544500ede4SDavid Hildenbrand 4554500ede4SDavid Hildenbrand old_mode = s390_swap_bfp_rounding_mode(env, erm); 4564500ede4SDavid Hildenbrand for (i = 0; i < 2; i++) { 4574500ede4SDavid Hildenbrand float64 a = s390_vec_read_element64(v2, i); 4584500ede4SDavid Hildenbrand uint32_t ret = float64_to_float32(a, &env->fpu_status); 4594500ede4SDavid Hildenbrand 4604500ede4SDavid Hildenbrand /* place at even element */ 4614500ede4SDavid Hildenbrand s390_vec_write_element32(&tmp, i * 2, ret); 4624500ede4SDavid Hildenbrand /* indicate the source element */ 4634500ede4SDavid Hildenbrand vxc = check_ieee_exc(env, i, XxC, &vec_exc); 4644500ede4SDavid Hildenbrand if (s || vxc) { 4654500ede4SDavid Hildenbrand break; 4664500ede4SDavid Hildenbrand } 4674500ede4SDavid Hildenbrand } 4684500ede4SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 4694500ede4SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 4704500ede4SDavid Hildenbrand *v1 = tmp; 4714500ede4SDavid Hildenbrand } 4724500ede4SDavid Hildenbrand 4734500ede4SDavid Hildenbrand void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env, 4744500ede4SDavid Hildenbrand uint32_t desc) 4754500ede4SDavid Hildenbrand { 4764500ede4SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 4774500ede4SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 4784500ede4SDavid Hildenbrand 4794500ede4SDavid Hildenbrand vflr64(v1, v2, env, false, XxC, erm, GETPC()); 4804500ede4SDavid Hildenbrand } 4814500ede4SDavid Hildenbrand 4824500ede4SDavid Hildenbrand void HELPER(gvec_vflr64s)(void *v1, const void *v2, CPUS390XState *env, 4834500ede4SDavid Hildenbrand uint32_t desc) 4844500ede4SDavid Hildenbrand { 4854500ede4SDavid Hildenbrand const uint8_t erm = extract32(simd_data(desc), 4, 4); 4864500ede4SDavid Hildenbrand const bool XxC = extract32(simd_data(desc), 2, 1); 4874500ede4SDavid Hildenbrand 4884500ede4SDavid Hildenbrand vflr64(v1, v2, env, true, XxC, erm, GETPC()); 4894500ede4SDavid Hildenbrand } 4908d47d4d2SDavid Hildenbrand 4918d47d4d2SDavid Hildenbrand static uint64_t vfm64(uint64_t a, uint64_t b, float_status *s) 4928d47d4d2SDavid Hildenbrand { 4938d47d4d2SDavid Hildenbrand return float64_mul(a, b, s); 4948d47d4d2SDavid Hildenbrand } 4958d47d4d2SDavid Hildenbrand 4968d47d4d2SDavid Hildenbrand void HELPER(gvec_vfm64)(void *v1, const void *v2, const void *v3, 4978d47d4d2SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 4988d47d4d2SDavid Hildenbrand { 4998d47d4d2SDavid Hildenbrand vop64_3(v1, v2, v3, env, false, vfm64, GETPC()); 5008d47d4d2SDavid Hildenbrand } 5018d47d4d2SDavid Hildenbrand 5028d47d4d2SDavid Hildenbrand void HELPER(gvec_vfm64s)(void *v1, const void *v2, const void *v3, 5038d47d4d2SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 5048d47d4d2SDavid Hildenbrand { 5058d47d4d2SDavid Hildenbrand vop64_3(v1, v2, v3, env, true, vfm64, GETPC()); 5068d47d4d2SDavid Hildenbrand } 507c64c5984SDavid Hildenbrand 508c64c5984SDavid Hildenbrand static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 509c64c5984SDavid Hildenbrand const S390Vector *v4, CPUS390XState *env, bool s, int flags, 510c64c5984SDavid Hildenbrand uintptr_t retaddr) 511c64c5984SDavid Hildenbrand { 512c64c5984SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 513c64c5984SDavid Hildenbrand S390Vector tmp = {}; 514c64c5984SDavid Hildenbrand int i; 515c64c5984SDavid Hildenbrand 516c64c5984SDavid Hildenbrand for (i = 0; i < 2; i++) { 517c64c5984SDavid Hildenbrand const uint64_t a = s390_vec_read_element64(v2, i); 518c64c5984SDavid Hildenbrand const uint64_t b = s390_vec_read_element64(v3, i); 519c64c5984SDavid Hildenbrand const uint64_t c = s390_vec_read_element64(v4, i); 520c64c5984SDavid Hildenbrand uint64_t ret = float64_muladd(a, b, c, flags, &env->fpu_status); 521c64c5984SDavid Hildenbrand 522c64c5984SDavid Hildenbrand s390_vec_write_element64(&tmp, i, ret); 523c64c5984SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 524c64c5984SDavid Hildenbrand if (s || vxc) { 525c64c5984SDavid Hildenbrand break; 526c64c5984SDavid Hildenbrand } 527c64c5984SDavid Hildenbrand } 528c64c5984SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 529c64c5984SDavid Hildenbrand *v1 = tmp; 530c64c5984SDavid Hildenbrand } 531c64c5984SDavid Hildenbrand 532c64c5984SDavid Hildenbrand void HELPER(gvec_vfma64)(void *v1, const void *v2, const void *v3, 533c64c5984SDavid Hildenbrand const void *v4, CPUS390XState *env, uint32_t desc) 534c64c5984SDavid Hildenbrand { 535c64c5984SDavid Hildenbrand vfma64(v1, v2, v3, v4, env, false, 0, GETPC()); 536c64c5984SDavid Hildenbrand } 537c64c5984SDavid Hildenbrand 538c64c5984SDavid Hildenbrand void HELPER(gvec_vfma64s)(void *v1, const void *v2, const void *v3, 539c64c5984SDavid Hildenbrand const void *v4, CPUS390XState *env, uint32_t desc) 540c64c5984SDavid Hildenbrand { 541c64c5984SDavid Hildenbrand vfma64(v1, v2, v3, v4, env, true, 0, GETPC()); 542c64c5984SDavid Hildenbrand } 543c64c5984SDavid Hildenbrand 544c64c5984SDavid Hildenbrand void HELPER(gvec_vfms64)(void *v1, const void *v2, const void *v3, 545c64c5984SDavid Hildenbrand const void *v4, CPUS390XState *env, uint32_t desc) 546c64c5984SDavid Hildenbrand { 547c64c5984SDavid Hildenbrand vfma64(v1, v2, v3, v4, env, false, float_muladd_negate_c, GETPC()); 548c64c5984SDavid Hildenbrand } 549c64c5984SDavid Hildenbrand 550c64c5984SDavid Hildenbrand void HELPER(gvec_vfms64s)(void *v1, const void *v2, const void *v3, 551c64c5984SDavid Hildenbrand const void *v4, CPUS390XState *env, uint32_t desc) 552c64c5984SDavid Hildenbrand { 553c64c5984SDavid Hildenbrand vfma64(v1, v2, v3, v4, env, true, float_muladd_negate_c, GETPC()); 554c64c5984SDavid Hildenbrand } 555*5938f20cSDavid Hildenbrand 556*5938f20cSDavid Hildenbrand static uint64_t vfsq64(uint64_t a, float_status *s) 557*5938f20cSDavid Hildenbrand { 558*5938f20cSDavid Hildenbrand return float64_sqrt(a, s); 559*5938f20cSDavid Hildenbrand } 560*5938f20cSDavid Hildenbrand 561*5938f20cSDavid Hildenbrand void HELPER(gvec_vfsq64)(void *v1, const void *v2, CPUS390XState *env, 562*5938f20cSDavid Hildenbrand uint32_t desc) 563*5938f20cSDavid Hildenbrand { 564*5938f20cSDavid Hildenbrand vop64_2(v1, v2, env, false, false, 0, vfsq64, GETPC()); 565*5938f20cSDavid Hildenbrand } 566*5938f20cSDavid Hildenbrand 567*5938f20cSDavid Hildenbrand void HELPER(gvec_vfsq64s)(void *v1, const void *v2, CPUS390XState *env, 568*5938f20cSDavid Hildenbrand uint32_t desc) 569*5938f20cSDavid Hildenbrand { 570*5938f20cSDavid Hildenbrand vop64_2(v1, v2, env, true, false, 0, vfsq64, GETPC()); 571*5938f20cSDavid Hildenbrand } 572