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