xref: /qemu/target/s390x/tcg/vec_helper.c (revision 6e0dc9d2)
1 /*
2  * QEMU TCG support -- s390x vector support instructions
3  *
4  * Copyright (C) 2019 Red Hat Inc
5  *
6  * Authors:
7  *   David Hildenbrand <david@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  */
12 #include "qemu/osdep.h"
13 #include "cpu.h"
14 #include "s390x-internal.h"
15 #include "vec.h"
16 #include "tcg/tcg.h"
17 #include "tcg/tcg-gvec-desc.h"
18 #include "exec/helper-proto.h"
19 #include "exec/cpu_ldst.h"
20 #include "exec/exec-all.h"
21 
22 void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3,
23                          uint32_t desc)
24 {
25     S390Vector tmp = {};
26     uint16_t result = 0;
27     int i;
28 
29     for (i = 0; i < 16; i++) {
30         const uint8_t bit_nr = s390_vec_read_element8(v3, i);
31         uint16_t bit;
32 
33         if (bit_nr >= 128) {
34             continue;
35         }
36         bit = (s390_vec_read_element8(v2, bit_nr / 8)
37                >> (7 - (bit_nr % 8))) & 1;
38         result |= (bit << (15 - i));
39     }
40     s390_vec_write_element16(&tmp, 3, result);
41     *(S390Vector *)v1 = tmp;
42 }
43 
44 void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes)
45 {
46     if (likely(bytes >= 16)) {
47         uint64_t t0, t1;
48 
49         t0 = cpu_ldq_data_ra(env, addr, GETPC());
50         addr = wrap_address(env, addr + 8);
51         t1 = cpu_ldq_data_ra(env, addr, GETPC());
52         s390_vec_write_element64(v1, 0, t0);
53         s390_vec_write_element64(v1, 1, t1);
54     } else {
55         S390Vector tmp = {};
56         int i;
57 
58         for (i = 0; i < bytes; i++) {
59             uint8_t byte = cpu_ldub_data_ra(env, addr, GETPC());
60 
61             s390_vec_write_element8(&tmp, i, byte);
62             addr = wrap_address(env, addr + 1);
63         }
64         *(S390Vector *)v1 = tmp;
65     }
66 }
67 
68 #define DEF_VPK_HFN(BITS, TBITS)                                               \
69 typedef uint##TBITS##_t (*vpk##BITS##_fn)(uint##BITS##_t, int *);              \
70 static int vpk##BITS##_hfn(S390Vector *v1, const S390Vector *v2,               \
71                            const S390Vector *v3, vpk##BITS##_fn fn)            \
72 {                                                                              \
73     int i, saturated = 0;                                                      \
74     S390Vector tmp;                                                            \
75                                                                                \
76     for (i = 0; i < (128 / TBITS); i++) {                                      \
77         uint##BITS##_t src;                                                    \
78                                                                                \
79         if (i < (128 / BITS)) {                                                \
80             src = s390_vec_read_element##BITS(v2, i);                          \
81         } else {                                                               \
82             src = s390_vec_read_element##BITS(v3, i - (128 / BITS));           \
83         }                                                                      \
84         s390_vec_write_element##TBITS(&tmp, i, fn(src, &saturated));           \
85     }                                                                          \
86     *v1 = tmp;                                                                 \
87     return saturated;                                                          \
88 }
89 DEF_VPK_HFN(64, 32)
90 DEF_VPK_HFN(32, 16)
91 DEF_VPK_HFN(16, 8)
92 
93 #define DEF_VPK(BITS, TBITS)                                                   \
94 static uint##TBITS##_t vpk##BITS##e(uint##BITS##_t src, int *saturated)        \
95 {                                                                              \
96     return src;                                                                \
97 }                                                                              \
98 void HELPER(gvec_vpk##BITS)(void *v1, const void *v2, const void *v3,          \
99                             uint32_t desc)                                     \
100 {                                                                              \
101     vpk##BITS##_hfn(v1, v2, v3, vpk##BITS##e);                                 \
102 }
103 DEF_VPK(64, 32)
104 DEF_VPK(32, 16)
105 DEF_VPK(16, 8)
106 
107 #define DEF_VPKS(BITS, TBITS)                                                  \
108 static uint##TBITS##_t vpks##BITS##e(uint##BITS##_t src, int *saturated)       \
109 {                                                                              \
110     if ((int##BITS##_t)src > INT##TBITS##_MAX) {                               \
111         (*saturated)++;                                                        \
112         return INT##TBITS##_MAX;                                               \
113     } else if ((int##BITS##_t)src < INT##TBITS##_MIN) {                        \
114         (*saturated)++;                                                        \
115         return INT##TBITS##_MIN;                                               \
116     }                                                                          \
117     return src;                                                                \
118 }                                                                              \
119 void HELPER(gvec_vpks##BITS)(void *v1, const void *v2, const void *v3,         \
120                              uint32_t desc)                                    \
121 {                                                                              \
122     vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e);                                \
123 }                                                                              \
124 void HELPER(gvec_vpks_cc##BITS)(void *v1, const void *v2, const void *v3,      \
125                                 CPUS390XState *env, uint32_t desc)             \
126 {                                                                              \
127     int saturated = vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e);                \
128                                                                                \
129     if (saturated == (128 / TBITS)) {                                          \
130         env->cc_op = 3;                                                        \
131     } else if (saturated) {                                                    \
132         env->cc_op = 1;                                                        \
133     } else {                                                                   \
134         env->cc_op = 0;                                                        \
135     }                                                                          \
136 }
137 DEF_VPKS(64, 32)
138 DEF_VPKS(32, 16)
139 DEF_VPKS(16, 8)
140 
141 #define DEF_VPKLS(BITS, TBITS)                                                 \
142 static uint##TBITS##_t vpkls##BITS##e(uint##BITS##_t src, int *saturated)      \
143 {                                                                              \
144     if (src > UINT##TBITS##_MAX) {                                             \
145         (*saturated)++;                                                        \
146         return UINT##TBITS##_MAX;                                              \
147     }                                                                          \
148     return src;                                                                \
149 }                                                                              \
150 void HELPER(gvec_vpkls##BITS)(void *v1, const void *v2, const void *v3,        \
151                               uint32_t desc)                                   \
152 {                                                                              \
153     vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e);                               \
154 }                                                                              \
155 void HELPER(gvec_vpkls_cc##BITS)(void *v1, const void *v2, const void *v3,     \
156                                  CPUS390XState *env, uint32_t desc)            \
157 {                                                                              \
158     int saturated = vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e);               \
159                                                                                \
160     if (saturated == (128 / TBITS)) {                                          \
161         env->cc_op = 3;                                                        \
162     } else if (saturated) {                                                    \
163         env->cc_op = 1;                                                        \
164     } else {                                                                   \
165         env->cc_op = 0;                                                        \
166     }                                                                          \
167 }
168 DEF_VPKLS(64, 32)
169 DEF_VPKLS(32, 16)
170 DEF_VPKLS(16, 8)
171 
172 void HELPER(gvec_vperm)(void *v1, const void *v2, const void *v3,
173                         const void *v4, uint32_t desc)
174 {
175     S390Vector tmp;
176     int i;
177 
178     for (i = 0; i < 16; i++) {
179         const uint8_t selector = s390_vec_read_element8(v4, i) & 0x1f;
180         uint8_t byte;
181 
182         if (selector < 16) {
183             byte = s390_vec_read_element8(v2, selector);
184         } else {
185             byte = s390_vec_read_element8(v3, selector - 16);
186         }
187         s390_vec_write_element8(&tmp, i, byte);
188     }
189     *(S390Vector *)v1 = tmp;
190 }
191 
192 void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr,
193                   uint64_t bytes)
194 {
195     /* Probe write access before actually modifying memory */
196     probe_write_access(env, addr, MIN(bytes, 16), GETPC());
197 
198     if (likely(bytes >= 16)) {
199         cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 0), GETPC());
200         addr = wrap_address(env, addr + 8);
201         cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 1), GETPC());
202     } else {
203         int i;
204 
205         for (i = 0; i < bytes; i++) {
206             uint8_t byte = s390_vec_read_element8(v1, i);
207 
208             cpu_stb_data_ra(env, addr, byte, GETPC());
209             addr = wrap_address(env, addr + 1);
210         }
211     }
212 }
213