xref: /qemu/target/s390x/tcg/vec_helper.c (revision 2a785dfb5071fdb269c77aeb7fa3930e93d413ef)
160e9e3f1SDavid Hildenbrand /*
260e9e3f1SDavid Hildenbrand  * QEMU TCG support -- s390x vector support instructions
360e9e3f1SDavid Hildenbrand  *
460e9e3f1SDavid Hildenbrand  * Copyright (C) 2019 Red Hat Inc
560e9e3f1SDavid Hildenbrand  *
660e9e3f1SDavid Hildenbrand  * Authors:
760e9e3f1SDavid Hildenbrand  *   David Hildenbrand <david@redhat.com>
860e9e3f1SDavid Hildenbrand  *
960e9e3f1SDavid Hildenbrand  * This work is licensed under the terms of the GNU GPL, version 2 or later.
1060e9e3f1SDavid Hildenbrand  * See the COPYING file in the top-level directory.
1160e9e3f1SDavid Hildenbrand  */
1260e9e3f1SDavid Hildenbrand #include "qemu/osdep.h"
1360e9e3f1SDavid Hildenbrand #include "cpu.h"
1460e9e3f1SDavid Hildenbrand #include "internal.h"
1560e9e3f1SDavid Hildenbrand #include "vec.h"
1660e9e3f1SDavid Hildenbrand #include "tcg/tcg.h"
1773946f0dSDavid Hildenbrand #include "tcg/tcg-gvec-desc.h"
1860e9e3f1SDavid Hildenbrand #include "exec/helper-proto.h"
1960e9e3f1SDavid Hildenbrand #include "exec/cpu_ldst.h"
2060e9e3f1SDavid Hildenbrand #include "exec/exec-all.h"
2160e9e3f1SDavid Hildenbrand 
22*2a785dfbSDavid Hildenbrand void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3,
23*2a785dfbSDavid Hildenbrand                          uint32_t desc)
24*2a785dfbSDavid Hildenbrand {
25*2a785dfbSDavid Hildenbrand     S390Vector tmp = {};
26*2a785dfbSDavid Hildenbrand     uint16_t result = 0;
27*2a785dfbSDavid Hildenbrand     int i;
28*2a785dfbSDavid Hildenbrand 
29*2a785dfbSDavid Hildenbrand     for (i = 0; i < 16; i++) {
30*2a785dfbSDavid Hildenbrand         const uint8_t bit_nr = s390_vec_read_element8(v3, i);
31*2a785dfbSDavid Hildenbrand         uint16_t bit;
32*2a785dfbSDavid Hildenbrand 
33*2a785dfbSDavid Hildenbrand         if (bit_nr >= 128) {
34*2a785dfbSDavid Hildenbrand             continue;
35*2a785dfbSDavid Hildenbrand         }
36*2a785dfbSDavid Hildenbrand         bit = (s390_vec_read_element8(v2, bit_nr / 8)
37*2a785dfbSDavid Hildenbrand                >> (7 - (bit_nr % 8))) & 1;
38*2a785dfbSDavid Hildenbrand         result |= (bit << (15 - i));
39*2a785dfbSDavid Hildenbrand     }
40*2a785dfbSDavid Hildenbrand     s390_vec_write_element16(&tmp, 3, result);
41*2a785dfbSDavid Hildenbrand     *(S390Vector *)v1 = tmp;
42*2a785dfbSDavid Hildenbrand }
43*2a785dfbSDavid Hildenbrand 
4460e9e3f1SDavid Hildenbrand void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes)
4560e9e3f1SDavid Hildenbrand {
4660e9e3f1SDavid Hildenbrand     if (likely(bytes >= 16)) {
4760e9e3f1SDavid Hildenbrand         uint64_t t0, t1;
4860e9e3f1SDavid Hildenbrand 
4960e9e3f1SDavid Hildenbrand         t0 = cpu_ldq_data_ra(env, addr, GETPC());
5060e9e3f1SDavid Hildenbrand         addr = wrap_address(env, addr + 8);
5160e9e3f1SDavid Hildenbrand         t1 = cpu_ldq_data_ra(env, addr, GETPC());
5260e9e3f1SDavid Hildenbrand         s390_vec_write_element64(v1, 0, t0);
5360e9e3f1SDavid Hildenbrand         s390_vec_write_element64(v1, 1, t1);
5460e9e3f1SDavid Hildenbrand     } else {
5560e9e3f1SDavid Hildenbrand         S390Vector tmp = {};
5660e9e3f1SDavid Hildenbrand         int i;
5760e9e3f1SDavid Hildenbrand 
5860e9e3f1SDavid Hildenbrand         for (i = 0; i < bytes; i++) {
5960e9e3f1SDavid Hildenbrand             uint8_t byte = cpu_ldub_data_ra(env, addr, GETPC());
6060e9e3f1SDavid Hildenbrand 
6160e9e3f1SDavid Hildenbrand             s390_vec_write_element8(&tmp, i, byte);
6260e9e3f1SDavid Hildenbrand             addr = wrap_address(env, addr + 1);
6360e9e3f1SDavid Hildenbrand         }
6460e9e3f1SDavid Hildenbrand         *(S390Vector *)v1 = tmp;
6560e9e3f1SDavid Hildenbrand     }
6660e9e3f1SDavid Hildenbrand }
6773946f0dSDavid Hildenbrand 
6873946f0dSDavid Hildenbrand #define DEF_VPK_HFN(BITS, TBITS)                                               \
6973946f0dSDavid Hildenbrand typedef uint##TBITS##_t (*vpk##BITS##_fn)(uint##BITS##_t, int *);              \
7073946f0dSDavid Hildenbrand static int vpk##BITS##_hfn(S390Vector *v1, const S390Vector *v2,               \
7173946f0dSDavid Hildenbrand                            const S390Vector *v3, vpk##BITS##_fn fn)            \
7273946f0dSDavid Hildenbrand {                                                                              \
7373946f0dSDavid Hildenbrand     int i, saturated = 0;                                                      \
7473946f0dSDavid Hildenbrand     S390Vector tmp;                                                            \
7573946f0dSDavid Hildenbrand                                                                                \
7673946f0dSDavid Hildenbrand     for (i = 0; i < (128 / TBITS); i++) {                                      \
7773946f0dSDavid Hildenbrand         uint##BITS##_t src;                                                    \
7873946f0dSDavid Hildenbrand                                                                                \
7973946f0dSDavid Hildenbrand         if (i < (128 / BITS)) {                                                \
8073946f0dSDavid Hildenbrand             src = s390_vec_read_element##BITS(v2, i);                          \
8173946f0dSDavid Hildenbrand         } else {                                                               \
8273946f0dSDavid Hildenbrand             src = s390_vec_read_element##BITS(v3, i - (128 / BITS));           \
8373946f0dSDavid Hildenbrand         }                                                                      \
8473946f0dSDavid Hildenbrand         s390_vec_write_element##TBITS(&tmp, i, fn(src, &saturated));           \
8573946f0dSDavid Hildenbrand     }                                                                          \
8673946f0dSDavid Hildenbrand     *v1 = tmp;                                                                 \
8773946f0dSDavid Hildenbrand     return saturated;                                                          \
8873946f0dSDavid Hildenbrand }
8973946f0dSDavid Hildenbrand DEF_VPK_HFN(64, 32)
9073946f0dSDavid Hildenbrand DEF_VPK_HFN(32, 16)
9173946f0dSDavid Hildenbrand DEF_VPK_HFN(16, 8)
9273946f0dSDavid Hildenbrand 
9373946f0dSDavid Hildenbrand #define DEF_VPK(BITS, TBITS)                                                   \
9473946f0dSDavid Hildenbrand static uint##TBITS##_t vpk##BITS##e(uint##BITS##_t src, int *saturated)        \
9573946f0dSDavid Hildenbrand {                                                                              \
9673946f0dSDavid Hildenbrand     return src;                                                                \
9773946f0dSDavid Hildenbrand }                                                                              \
9873946f0dSDavid Hildenbrand void HELPER(gvec_vpk##BITS)(void *v1, const void *v2, const void *v3,          \
9973946f0dSDavid Hildenbrand                             uint32_t desc)                                     \
10073946f0dSDavid Hildenbrand {                                                                              \
10173946f0dSDavid Hildenbrand     vpk##BITS##_hfn(v1, v2, v3, vpk##BITS##e);                                 \
10273946f0dSDavid Hildenbrand }
10373946f0dSDavid Hildenbrand DEF_VPK(64, 32)
10473946f0dSDavid Hildenbrand DEF_VPK(32, 16)
10573946f0dSDavid Hildenbrand DEF_VPK(16, 8)
10673946f0dSDavid Hildenbrand 
10773946f0dSDavid Hildenbrand #define DEF_VPKS(BITS, TBITS)                                                  \
10873946f0dSDavid Hildenbrand static uint##TBITS##_t vpks##BITS##e(uint##BITS##_t src, int *saturated)       \
10973946f0dSDavid Hildenbrand {                                                                              \
11073946f0dSDavid Hildenbrand     if ((int##BITS##_t)src > INT##TBITS##_MAX) {                               \
11173946f0dSDavid Hildenbrand         (*saturated)++;                                                        \
11273946f0dSDavid Hildenbrand         return INT##TBITS##_MAX;                                               \
11373946f0dSDavid Hildenbrand     } else if ((int##BITS##_t)src < INT##TBITS##_MIN) {                        \
11473946f0dSDavid Hildenbrand         (*saturated)++;                                                        \
11573946f0dSDavid Hildenbrand         return INT##TBITS##_MIN;                                               \
11673946f0dSDavid Hildenbrand     }                                                                          \
11773946f0dSDavid Hildenbrand     return src;                                                                \
11873946f0dSDavid Hildenbrand }                                                                              \
11973946f0dSDavid Hildenbrand void HELPER(gvec_vpks##BITS)(void *v1, const void *v2, const void *v3,         \
12073946f0dSDavid Hildenbrand                              uint32_t desc)                                    \
12173946f0dSDavid Hildenbrand {                                                                              \
12273946f0dSDavid Hildenbrand     vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e);                                \
12373946f0dSDavid Hildenbrand }                                                                              \
12473946f0dSDavid Hildenbrand void HELPER(gvec_vpks_cc##BITS)(void *v1, const void *v2, const void *v3,      \
12573946f0dSDavid Hildenbrand                                 CPUS390XState *env, uint32_t desc)             \
12673946f0dSDavid Hildenbrand {                                                                              \
12773946f0dSDavid Hildenbrand     int saturated = vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e);                \
12873946f0dSDavid Hildenbrand                                                                                \
12973946f0dSDavid Hildenbrand     if (saturated == (128 / TBITS)) {                                          \
13073946f0dSDavid Hildenbrand         env->cc_op = 3;                                                        \
13173946f0dSDavid Hildenbrand     } else if (saturated) {                                                    \
13273946f0dSDavid Hildenbrand         env->cc_op = 1;                                                        \
13373946f0dSDavid Hildenbrand     } else {                                                                   \
13473946f0dSDavid Hildenbrand         env->cc_op = 0;                                                        \
13573946f0dSDavid Hildenbrand     }                                                                          \
13673946f0dSDavid Hildenbrand }
13773946f0dSDavid Hildenbrand DEF_VPKS(64, 32)
13873946f0dSDavid Hildenbrand DEF_VPKS(32, 16)
13973946f0dSDavid Hildenbrand DEF_VPKS(16, 8)
14073946f0dSDavid Hildenbrand 
14173946f0dSDavid Hildenbrand #define DEF_VPKLS(BITS, TBITS)                                                 \
14273946f0dSDavid Hildenbrand static uint##TBITS##_t vpkls##BITS##e(uint##BITS##_t src, int *saturated)      \
14373946f0dSDavid Hildenbrand {                                                                              \
14473946f0dSDavid Hildenbrand     if (src > UINT##TBITS##_MAX) {                                             \
14573946f0dSDavid Hildenbrand         (*saturated)++;                                                        \
14673946f0dSDavid Hildenbrand         return UINT##TBITS##_MAX;                                              \
14773946f0dSDavid Hildenbrand     }                                                                          \
14873946f0dSDavid Hildenbrand     return src;                                                                \
14973946f0dSDavid Hildenbrand }                                                                              \
15073946f0dSDavid Hildenbrand void HELPER(gvec_vpkls##BITS)(void *v1, const void *v2, const void *v3,        \
15173946f0dSDavid Hildenbrand                               uint32_t desc)                                   \
15273946f0dSDavid Hildenbrand {                                                                              \
15373946f0dSDavid Hildenbrand     vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e);                               \
15473946f0dSDavid Hildenbrand }                                                                              \
15573946f0dSDavid Hildenbrand void HELPER(gvec_vpkls_cc##BITS)(void *v1, const void *v2, const void *v3,     \
15673946f0dSDavid Hildenbrand                                  CPUS390XState *env, uint32_t desc)            \
15773946f0dSDavid Hildenbrand {                                                                              \
15873946f0dSDavid Hildenbrand     int saturated = vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e);               \
15973946f0dSDavid Hildenbrand                                                                                \
16073946f0dSDavid Hildenbrand     if (saturated == (128 / TBITS)) {                                          \
16173946f0dSDavid Hildenbrand         env->cc_op = 3;                                                        \
16273946f0dSDavid Hildenbrand     } else if (saturated) {                                                    \
16373946f0dSDavid Hildenbrand         env->cc_op = 1;                                                        \
16473946f0dSDavid Hildenbrand     } else {                                                                   \
16573946f0dSDavid Hildenbrand         env->cc_op = 0;                                                        \
16673946f0dSDavid Hildenbrand     }                                                                          \
16773946f0dSDavid Hildenbrand }
16873946f0dSDavid Hildenbrand DEF_VPKLS(64, 32)
16973946f0dSDavid Hildenbrand DEF_VPKLS(32, 16)
17073946f0dSDavid Hildenbrand DEF_VPKLS(16, 8)
1717aaf844dSDavid Hildenbrand 
1727aaf844dSDavid Hildenbrand void HELPER(gvec_vperm)(void *v1, const void *v2, const void *v3,
1737aaf844dSDavid Hildenbrand                         const void *v4, uint32_t desc)
1747aaf844dSDavid Hildenbrand {
1757aaf844dSDavid Hildenbrand     S390Vector tmp;
1767aaf844dSDavid Hildenbrand     int i;
1777aaf844dSDavid Hildenbrand 
1787aaf844dSDavid Hildenbrand     for (i = 0; i < 16; i++) {
1797aaf844dSDavid Hildenbrand         const uint8_t selector = s390_vec_read_element8(v4, i) & 0x1f;
1807aaf844dSDavid Hildenbrand         uint8_t byte;
1817aaf844dSDavid Hildenbrand 
1827aaf844dSDavid Hildenbrand         if (selector < 16) {
1837aaf844dSDavid Hildenbrand             byte = s390_vec_read_element8(v2, selector);
1847aaf844dSDavid Hildenbrand         } else {
1857aaf844dSDavid Hildenbrand             byte = s390_vec_read_element8(v3, selector - 16);
1867aaf844dSDavid Hildenbrand         }
1877aaf844dSDavid Hildenbrand         s390_vec_write_element8(&tmp, i, byte);
1887aaf844dSDavid Hildenbrand     }
1897aaf844dSDavid Hildenbrand     *(S390Vector *)v1 = tmp;
1907aaf844dSDavid Hildenbrand }
1910e0a5b49SDavid Hildenbrand 
1920e0a5b49SDavid Hildenbrand void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr,
1930e0a5b49SDavid Hildenbrand                   uint64_t bytes)
1940e0a5b49SDavid Hildenbrand {
1950e0a5b49SDavid Hildenbrand     /* Probe write access before actually modifying memory */
1960e0a5b49SDavid Hildenbrand     probe_write_access(env, addr, bytes, GETPC());
1970e0a5b49SDavid Hildenbrand 
1980e0a5b49SDavid Hildenbrand     if (likely(bytes >= 16)) {
1990e0a5b49SDavid Hildenbrand         cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 0), GETPC());
2000e0a5b49SDavid Hildenbrand         addr = wrap_address(env, addr + 8);
2010e0a5b49SDavid Hildenbrand         cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 1), GETPC());
2020e0a5b49SDavid Hildenbrand     } else {
2030e0a5b49SDavid Hildenbrand         S390Vector tmp = {};
2040e0a5b49SDavid Hildenbrand         int i;
2050e0a5b49SDavid Hildenbrand 
2060e0a5b49SDavid Hildenbrand         for (i = 0; i < bytes; i++) {
2070e0a5b49SDavid Hildenbrand             uint8_t byte = s390_vec_read_element8(v1, i);
2080e0a5b49SDavid Hildenbrand 
2090e0a5b49SDavid Hildenbrand             cpu_stb_data_ra(env, addr, byte, GETPC());
2100e0a5b49SDavid Hildenbrand             addr = wrap_address(env, addr + 1);
2110e0a5b49SDavid Hildenbrand         }
2120e0a5b49SDavid Hildenbrand         *(S390Vector *)v1 = tmp;
2130e0a5b49SDavid Hildenbrand     }
2140e0a5b49SDavid Hildenbrand }
215