]> git.proxmox.com Git - mirror_qemu.git/blame - target/s390x/tcg/vec_fpu_helper.c
Remove qemu-common.h include from most units
[mirror_qemu.git] / target / s390x / tcg / vec_fpu_helper.c
CommitLineData
3a0eae85
DH
1/*
2 * QEMU TCG support -- s390x vector floating point instruction support
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"
3a0eae85 13#include "cpu.h"
b6b47223 14#include "s390x-internal.h"
3a0eae85
DH
15#include "vec.h"
16#include "tcg_s390x.h"
17#include "tcg/tcg-gvec-desc.h"
18#include "exec/exec-all.h"
19#include "exec/helper-proto.h"
20#include "fpu/softfloat.h"
21
22#define VIC_INVALID 0x1
23#define VIC_DIVBYZERO 0x2
24#define VIC_OVERFLOW 0x3
25#define VIC_UNDERFLOW 0x4
26#define VIC_INEXACT 0x5
27
28/* returns the VEX. If the VEX is 0, there is no trap */
29static uint8_t check_ieee_exc(CPUS390XState *env, uint8_t enr, bool XxC,
30 uint8_t *vec_exc)
31{
32 uint8_t vece_exc = 0, trap_exc;
33 unsigned qemu_exc;
34
35 /* Retrieve and clear the softfloat exceptions */
36 qemu_exc = env->fpu_status.float_exception_flags;
37 if (qemu_exc == 0) {
38 return 0;
39 }
40 env->fpu_status.float_exception_flags = 0;
41
42 vece_exc = s390_softfloat_exc_to_ieee(qemu_exc);
43
44 /* Add them to the vector-wide s390x exception bits */
45 *vec_exc |= vece_exc;
46
47 /* Check for traps and construct the VXC */
48 trap_exc = vece_exc & env->fpc >> 24;
49 if (trap_exc) {
50 if (trap_exc & S390_IEEE_MASK_INVALID) {
51 return enr << 4 | VIC_INVALID;
52 } else if (trap_exc & S390_IEEE_MASK_DIVBYZERO) {
53 return enr << 4 | VIC_DIVBYZERO;
54 } else if (trap_exc & S390_IEEE_MASK_OVERFLOW) {
55 return enr << 4 | VIC_OVERFLOW;
56 } else if (trap_exc & S390_IEEE_MASK_UNDERFLOW) {
57 return enr << 4 | VIC_UNDERFLOW;
58 } else if (!XxC) {
59 g_assert(trap_exc & S390_IEEE_MASK_INEXACT);
60 /* inexact has lowest priority on traps */
61 return enr << 4 | VIC_INEXACT;
62 }
63 }
64 return 0;
65}
66
67static void handle_ieee_exc(CPUS390XState *env, uint8_t vxc, uint8_t vec_exc,
68 uintptr_t retaddr)
69{
70 if (vxc) {
71 /* on traps, the fpc flags are not updated, instruction is suppressed */
72 tcg_s390_vector_exception(env, vxc, retaddr);
73 }
74 if (vec_exc) {
75 /* indicate exceptions for all elements combined */
76 env->fpc |= vec_exc << 16;
77 }
78}
79
0987961d
DH
80static float32 s390_vec_read_float32(const S390Vector *v, uint8_t enr)
81{
82 return make_float32(s390_vec_read_element32(v, enr));
83}
84
863b9507
DH
85static float64 s390_vec_read_float64(const S390Vector *v, uint8_t enr)
86{
87 return make_float64(s390_vec_read_element64(v, enr));
88}
89
0987961d
DH
90static float128 s390_vec_read_float128(const S390Vector *v)
91{
92 return make_float128(s390_vec_read_element64(v, 0),
93 s390_vec_read_element64(v, 1));
94}
95
96static void s390_vec_write_float32(S390Vector *v, uint8_t enr, float32 data)
97{
98 return s390_vec_write_element32(v, enr, data);
99}
100
863b9507
DH
101static void s390_vec_write_float64(S390Vector *v, uint8_t enr, float64 data)
102{
103 return s390_vec_write_element64(v, enr, data);
104}
105
0987961d
DH
106static void s390_vec_write_float128(S390Vector *v, float128 data)
107{
108 s390_vec_write_element64(v, 0, data.high);
109 s390_vec_write_element64(v, 1, data.low);
110}
111
acb269a4
DH
112typedef float32 (*vop32_2_fn)(float32 a, float_status *s);
113static void vop32_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
114 bool s, bool XxC, uint8_t erm, vop32_2_fn fn,
115 uintptr_t retaddr)
116{
117 uint8_t vxc, vec_exc = 0;
118 S390Vector tmp = {};
119 int i, old_mode;
120
121 old_mode = s390_swap_bfp_rounding_mode(env, erm);
122 for (i = 0; i < 4; i++) {
123 const float32 a = s390_vec_read_float32(v2, i);
124
125 s390_vec_write_float32(&tmp, i, fn(a, &env->fpu_status));
126 vxc = check_ieee_exc(env, i, XxC, &vec_exc);
127 if (s || vxc) {
128 break;
129 }
130 }
131 s390_restore_bfp_rounding_mode(env, old_mode);
132 handle_ieee_exc(env, vxc, vec_exc, retaddr);
133 *v1 = tmp;
134}
135
21bd6ea2 136typedef float64 (*vop64_2_fn)(float64 a, float_status *s);
bb03fd84
DH
137static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
138 bool s, bool XxC, uint8_t erm, vop64_2_fn fn,
139 uintptr_t retaddr)
140{
141 uint8_t vxc, vec_exc = 0;
142 S390Vector tmp = {};
143 int i, old_mode;
144
145 old_mode = s390_swap_bfp_rounding_mode(env, erm);
146 for (i = 0; i < 2; i++) {
21bd6ea2 147 const float64 a = s390_vec_read_float64(v2, i);
bb03fd84 148
21bd6ea2 149 s390_vec_write_float64(&tmp, i, fn(a, &env->fpu_status));
bb03fd84
DH
150 vxc = check_ieee_exc(env, i, XxC, &vec_exc);
151 if (s || vxc) {
152 break;
153 }
154 }
155 s390_restore_bfp_rounding_mode(env, old_mode);
156 handle_ieee_exc(env, vxc, vec_exc, retaddr);
157 *v1 = tmp;
158}
159
acb269a4
DH
160typedef float128 (*vop128_2_fn)(float128 a, float_status *s);
161static void vop128_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
162 bool s, bool XxC, uint8_t erm, vop128_2_fn fn,
163 uintptr_t retaddr)
164{
165 const float128 a = s390_vec_read_float128(v2);
166 uint8_t vxc, vec_exc = 0;
167 S390Vector tmp = {};
168 int old_mode;
169
170 old_mode = s390_swap_bfp_rounding_mode(env, erm);
171 s390_vec_write_float128(&tmp, fn(a, &env->fpu_status));
172 vxc = check_ieee_exc(env, 0, XxC, &vec_exc);
173 s390_restore_bfp_rounding_mode(env, old_mode);
174 handle_ieee_exc(env, vxc, vec_exc, retaddr);
175 *v1 = tmp;
176}
177
21bd6ea2
DH
178static float64 vcdg64(float64 a, float_status *s)
179{
180 return int64_to_float64(a, s);
181}
182
183static float64 vcdlg64(float64 a, float_status *s)
184{
185 return uint64_to_float64(a, s);
186}
187
188static float64 vcgd64(float64 a, float_status *s)
189{
190 const float64 tmp = float64_to_int64(a, s);
191
192 return float64_is_any_nan(a) ? INT64_MIN : tmp;
193}
194
195static float64 vclgd64(float64 a, float_status *s)
196{
197 const float64 tmp = float64_to_uint64(a, s);
198
199 return float64_is_any_nan(a) ? 0 : tmp;
200}
201
202#define DEF_GVEC_VOP2_FN(NAME, FN, BITS) \
203void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, CPUS390XState *env, \
204 uint32_t desc) \
205{ \
206 const uint8_t erm = extract32(simd_data(desc), 4, 4); \
207 const bool se = extract32(simd_data(desc), 3, 1); \
208 const bool XxC = extract32(simd_data(desc), 2, 1); \
209 \
210 vop##BITS##_2(v1, v2, env, se, XxC, erm, FN, GETPC()); \
211}
212
213#define DEF_GVEC_VOP2_64(NAME) \
214DEF_GVEC_VOP2_FN(NAME, NAME##64, 64)
215
216#define DEF_GVEC_VOP2(NAME, OP) \
acb269a4
DH
217DEF_GVEC_VOP2_FN(NAME, float32_##OP, 32) \
218DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64) \
219DEF_GVEC_VOP2_FN(NAME, float128_##OP, 128)
21bd6ea2
DH
220
221DEF_GVEC_VOP2_64(vcdg)
222DEF_GVEC_VOP2_64(vcdlg)
223DEF_GVEC_VOP2_64(vcgd)
224DEF_GVEC_VOP2_64(vclgd)
225DEF_GVEC_VOP2(vfi, round_to_int)
226DEF_GVEC_VOP2(vfsq, sqrt)
227
0987961d
DH
228typedef float32 (*vop32_3_fn)(float32 a, float32 b, float_status *s);
229static void vop32_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
230 CPUS390XState *env, bool s, vop32_3_fn fn,
231 uintptr_t retaddr)
232{
233 uint8_t vxc, vec_exc = 0;
234 S390Vector tmp = {};
235 int i;
236
237 for (i = 0; i < 4; i++) {
238 const float32 a = s390_vec_read_float32(v2, i);
239 const float32 b = s390_vec_read_float32(v3, i);
240
241 s390_vec_write_float32(&tmp, i, fn(a, b, &env->fpu_status));
242 vxc = check_ieee_exc(env, i, false, &vec_exc);
243 if (s || vxc) {
244 break;
245 }
246 }
247 handle_ieee_exc(env, vxc, vec_exc, retaddr);
248 *v1 = tmp;
249}
250
863b9507 251typedef float64 (*vop64_3_fn)(float64 a, float64 b, float_status *s);
3a0eae85
DH
252static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
253 CPUS390XState *env, bool s, vop64_3_fn fn,
254 uintptr_t retaddr)
255{
256 uint8_t vxc, vec_exc = 0;
257 S390Vector tmp = {};
258 int i;
259
260 for (i = 0; i < 2; i++) {
863b9507
DH
261 const float64 a = s390_vec_read_float64(v2, i);
262 const float64 b = s390_vec_read_float64(v3, i);
3a0eae85 263
863b9507 264 s390_vec_write_float64(&tmp, i, fn(a, b, &env->fpu_status));
3a0eae85
DH
265 vxc = check_ieee_exc(env, i, false, &vec_exc);
266 if (s || vxc) {
267 break;
268 }
269 }
270 handle_ieee_exc(env, vxc, vec_exc, retaddr);
271 *v1 = tmp;
272}
273
0987961d
DH
274typedef float128 (*vop128_3_fn)(float128 a, float128 b, float_status *s);
275static void vop128_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
276 CPUS390XState *env, bool s, vop128_3_fn fn,
277 uintptr_t retaddr)
278{
279 const float128 a = s390_vec_read_float128(v2);
280 const float128 b = s390_vec_read_float128(v3);
281 uint8_t vxc, vec_exc = 0;
282 S390Vector tmp = {};
283
284 s390_vec_write_float128(&tmp, fn(a, b, &env->fpu_status));
285 vxc = check_ieee_exc(env, 0, false, &vec_exc);
286 handle_ieee_exc(env, vxc, vec_exc, retaddr);
287 *v1 = tmp;
288}
289
290#define DEF_GVEC_VOP3_B(NAME, OP, BITS) \
291void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \
292 CPUS390XState *env, uint32_t desc) \
863b9507
DH
293{ \
294 const bool se = extract32(simd_data(desc), 3, 1); \
295 \
0987961d 296 vop##BITS##_3(v1, v2, v3, env, se, float##BITS##_##OP, GETPC()); \
3a0eae85
DH
297}
298
0987961d
DH
299#define DEF_GVEC_VOP3(NAME, OP) \
300DEF_GVEC_VOP3_B(NAME, OP, 32) \
301DEF_GVEC_VOP3_B(NAME, OP, 64) \
302DEF_GVEC_VOP3_B(NAME, OP, 128)
303
863b9507
DH
304DEF_GVEC_VOP3(vfa, add)
305DEF_GVEC_VOP3(vfs, sub)
306DEF_GVEC_VOP3(vfd, div)
307DEF_GVEC_VOP3(vfm, mul)
5b89f0fb 308
1c6b5b47
DH
309static int wfc32(const S390Vector *v1, const S390Vector *v2,
310 CPUS390XState *env, bool signal, uintptr_t retaddr)
311{
312 /* only the zero-indexed elements are compared */
313 const float32 a = s390_vec_read_float32(v1, 0);
314 const float32 b = s390_vec_read_float32(v2, 0);
315 uint8_t vxc, vec_exc = 0;
316 int cmp;
317
318 if (signal) {
319 cmp = float32_compare(a, b, &env->fpu_status);
320 } else {
321 cmp = float32_compare_quiet(a, b, &env->fpu_status);
322 }
323 vxc = check_ieee_exc(env, 0, false, &vec_exc);
324 handle_ieee_exc(env, vxc, vec_exc, retaddr);
325
326 return float_comp_to_cc(env, cmp);
327}
328
5b89f0fb
DH
329static int wfc64(const S390Vector *v1, const S390Vector *v2,
330 CPUS390XState *env, bool signal, uintptr_t retaddr)
331{
332 /* only the zero-indexed elements are compared */
4da79375
DH
333 const float64 a = s390_vec_read_float64(v1, 0);
334 const float64 b = s390_vec_read_float64(v2, 0);
5b89f0fb
DH
335 uint8_t vxc, vec_exc = 0;
336 int cmp;
337
338 if (signal) {
339 cmp = float64_compare(a, b, &env->fpu_status);
340 } else {
341 cmp = float64_compare_quiet(a, b, &env->fpu_status);
342 }
343 vxc = check_ieee_exc(env, 0, false, &vec_exc);
344 handle_ieee_exc(env, vxc, vec_exc, retaddr);
345
346 return float_comp_to_cc(env, cmp);
347}
348
1c6b5b47
DH
349static int wfc128(const S390Vector *v1, const S390Vector *v2,
350 CPUS390XState *env, bool signal, uintptr_t retaddr)
351{
352 /* only the zero-indexed elements are compared */
353 const float128 a = s390_vec_read_float128(v1);
354 const float128 b = s390_vec_read_float128(v2);
355 uint8_t vxc, vec_exc = 0;
356 int cmp;
357
358 if (signal) {
359 cmp = float128_compare(a, b, &env->fpu_status);
360 } else {
361 cmp = float128_compare_quiet(a, b, &env->fpu_status);
362 }
363 vxc = check_ieee_exc(env, 0, false, &vec_exc);
364 handle_ieee_exc(env, vxc, vec_exc, retaddr);
365
366 return float_comp_to_cc(env, cmp);
367}
368
4da79375
DH
369#define DEF_GVEC_WFC_B(NAME, SIGNAL, BITS) \
370void HELPER(gvec_##NAME##BITS)(const void *v1, const void *v2, \
371 CPUS390XState *env, uint32_t desc) \
372{ \
373 env->cc_op = wfc##BITS(v1, v2, env, SIGNAL, GETPC()); \
5b89f0fb
DH
374}
375
4da79375 376#define DEF_GVEC_WFC(NAME, SIGNAL) \
1c6b5b47
DH
377 DEF_GVEC_WFC_B(NAME, SIGNAL, 32) \
378 DEF_GVEC_WFC_B(NAME, SIGNAL, 64) \
379 DEF_GVEC_WFC_B(NAME, SIGNAL, 128)
4da79375
DH
380
381DEF_GVEC_WFC(wfc, false)
382DEF_GVEC_WFC(wfk, true)
2c806ab4 383
e384332c
DH
384typedef bool (*vfc32_fn)(float32 a, float32 b, float_status *status);
385static int vfc32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
386 CPUS390XState *env, bool s, vfc32_fn fn, uintptr_t retaddr)
387{
388 uint8_t vxc, vec_exc = 0;
389 S390Vector tmp = {};
390 int match = 0;
391 int i;
392
393 for (i = 0; i < 4; i++) {
394 const float32 a = s390_vec_read_float32(v2, i);
395 const float32 b = s390_vec_read_float32(v3, i);
396
397 /* swap the order of the parameters, so we can use existing functions */
398 if (fn(b, a, &env->fpu_status)) {
399 match++;
400 s390_vec_write_element32(&tmp, i, -1u);
401 }
402 vxc = check_ieee_exc(env, i, false, &vec_exc);
403 if (s || vxc) {
404 break;
405 }
406 }
407
408 handle_ieee_exc(env, vxc, vec_exc, retaddr);
409 *v1 = tmp;
410 if (match) {
411 return s || match == 4 ? 0 : 1;
412 }
413 return 3;
414}
415
0673ecdf 416typedef bool (*vfc64_fn)(float64 a, float64 b, float_status *status);
2c806ab4
DH
417static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
418 CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr)
419{
420 uint8_t vxc, vec_exc = 0;
421 S390Vector tmp = {};
422 int match = 0;
423 int i;
424
425 for (i = 0; i < 2; i++) {
64deb65a
DH
426 const float64 a = s390_vec_read_float64(v2, i);
427 const float64 b = s390_vec_read_float64(v3, i);
2c806ab4
DH
428
429 /* swap the order of the parameters, so we can use existing functions */
430 if (fn(b, a, &env->fpu_status)) {
431 match++;
432 s390_vec_write_element64(&tmp, i, -1ull);
433 }
434 vxc = check_ieee_exc(env, i, false, &vec_exc);
435 if (s || vxc) {
436 break;
437 }
438 }
439
440 handle_ieee_exc(env, vxc, vec_exc, retaddr);
441 *v1 = tmp;
442 if (match) {
443 return s || match == 2 ? 0 : 1;
444 }
445 return 3;
446}
447
e384332c
DH
448typedef bool (*vfc128_fn)(float128 a, float128 b, float_status *status);
449static int vfc128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
450 CPUS390XState *env, bool s, vfc128_fn fn, uintptr_t retaddr)
451{
452 const float128 a = s390_vec_read_float128(v2);
453 const float128 b = s390_vec_read_float128(v3);
454 uint8_t vxc, vec_exc = 0;
455 S390Vector tmp = {};
456 bool match = false;
457
458 /* swap the order of the parameters, so we can use existing functions */
459 if (fn(b, a, &env->fpu_status)) {
460 match = true;
461 s390_vec_write_element64(&tmp, 0, -1ull);
462 s390_vec_write_element64(&tmp, 1, -1ull);
463 }
464 vxc = check_ieee_exc(env, 0, false, &vec_exc);
465 handle_ieee_exc(env, vxc, vec_exc, retaddr);
466 *v1 = tmp;
467 return match ? 0 : 3;
468}
469
64deb65a
DH
470#define DEF_GVEC_VFC_B(NAME, OP, BITS) \
471void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \
472 CPUS390XState *env, uint32_t desc) \
473{ \
474 const bool se = extract32(simd_data(desc), 3, 1); \
e384332c
DH
475 const bool sq = extract32(simd_data(desc), 2, 1); \
476 vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet; \
64deb65a
DH
477 \
478 vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \
479} \
480 \
481void HELPER(gvec_##NAME##BITS##_cc)(void *v1, const void *v2, const void *v3, \
482 CPUS390XState *env, uint32_t desc) \
483{ \
484 const bool se = extract32(simd_data(desc), 3, 1); \
e384332c
DH
485 const bool sq = extract32(simd_data(desc), 2, 1); \
486 vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet; \
64deb65a
DH
487 \
488 env->cc_op = vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \
2c806ab4
DH
489}
490
64deb65a 491#define DEF_GVEC_VFC(NAME, OP) \
e384332c
DH
492DEF_GVEC_VFC_B(NAME, OP, 32) \
493DEF_GVEC_VFC_B(NAME, OP, 64) \
494DEF_GVEC_VFC_B(NAME, OP, 128) \
2c806ab4 495
64deb65a
DH
496DEF_GVEC_VFC(vfce, eq)
497DEF_GVEC_VFC(vfch, lt)
498DEF_GVEC_VFC(vfche, le)
bb03fd84 499
860b707b
DH
500void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env,
501 uint32_t desc)
1a76e59d 502{
860b707b 503 const bool s = extract32(simd_data(desc), 3, 1);
1a76e59d
DH
504 uint8_t vxc, vec_exc = 0;
505 S390Vector tmp = {};
506 int i;
507
508 for (i = 0; i < 2; i++) {
509 /* load from even element */
510 const float32 a = s390_vec_read_element32(v2, i * 2);
511 const uint64_t ret = float32_to_float64(a, &env->fpu_status);
512
513 s390_vec_write_element64(&tmp, i, ret);
514 /* indicate the source element */
515 vxc = check_ieee_exc(env, i * 2, false, &vec_exc);
516 if (s || vxc) {
517 break;
518 }
519 }
860b707b
DH
520 handle_ieee_exc(env, vxc, vec_exc, GETPC());
521 *(S390Vector *)v1 = tmp;
1a76e59d 522}
4500ede4 523
2e96005e
DH
524void HELPER(gvec_vfll64)(void *v1, const void *v2, CPUS390XState *env,
525 uint32_t desc)
526{
527 /* load from even element */
528 const float128 ret = float64_to_float128(s390_vec_read_float64(v2, 0),
529 &env->fpu_status);
530 uint8_t vxc, vec_exc = 0;
531
532 vxc = check_ieee_exc(env, 0, false, &vec_exc);
533 handle_ieee_exc(env, vxc, vec_exc, GETPC());
534 s390_vec_write_float128(v1, ret);
535}
536
977e43d9
DH
537void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env,
538 uint32_t desc)
4500ede4 539{
977e43d9
DH
540 const uint8_t erm = extract32(simd_data(desc), 4, 4);
541 const bool s = extract32(simd_data(desc), 3, 1);
542 const bool XxC = extract32(simd_data(desc), 2, 1);
4500ede4
DH
543 uint8_t vxc, vec_exc = 0;
544 S390Vector tmp = {};
545 int i, old_mode;
546
547 old_mode = s390_swap_bfp_rounding_mode(env, erm);
548 for (i = 0; i < 2; i++) {
549 float64 a = s390_vec_read_element64(v2, i);
550 uint32_t ret = float64_to_float32(a, &env->fpu_status);
551
552 /* place at even element */
553 s390_vec_write_element32(&tmp, i * 2, ret);
554 /* indicate the source element */
555 vxc = check_ieee_exc(env, i, XxC, &vec_exc);
556 if (s || vxc) {
557 break;
558 }
559 }
560 s390_restore_bfp_rounding_mode(env, old_mode);
977e43d9
DH
561 handle_ieee_exc(env, vxc, vec_exc, GETPC());
562 *(S390Vector *)v1 = tmp;
4500ede4 563}
8d47d4d2 564
9cbc8be0
DH
565void HELPER(gvec_vflr128)(void *v1, const void *v2, CPUS390XState *env,
566 uint32_t desc)
567{
568 const uint8_t erm = extract32(simd_data(desc), 4, 4);
569 const bool XxC = extract32(simd_data(desc), 2, 1);
570 uint8_t vxc, vec_exc = 0;
571 int old_mode;
572 float64 ret;
573
574 old_mode = s390_swap_bfp_rounding_mode(env, erm);
575 ret = float128_to_float64(s390_vec_read_float128(v2), &env->fpu_status);
576 vxc = check_ieee_exc(env, 0, XxC, &vec_exc);
577 s390_restore_bfp_rounding_mode(env, old_mode);
578 handle_ieee_exc(env, vxc, vec_exc, GETPC());
579
580 /* place at even element, odd element is unpredictable */
581 s390_vec_write_float64(v1, 0, ret);
582}
583
e257abc8
DH
584static void vfma32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
585 const S390Vector *v4, CPUS390XState *env, bool s, int flags,
586 uintptr_t retaddr)
587{
588 uint8_t vxc, vec_exc = 0;
589 S390Vector tmp = {};
590 int i;
591
592 for (i = 0; i < 4; i++) {
593 const float32 a = s390_vec_read_float32(v2, i);
594 const float32 b = s390_vec_read_float32(v3, i);
595 const float32 c = s390_vec_read_float32(v4, i);
596 float32 ret = float32_muladd(a, b, c, flags, &env->fpu_status);
597
598 s390_vec_write_float32(&tmp, i, ret);
599 vxc = check_ieee_exc(env, i, false, &vec_exc);
600 if (s || vxc) {
601 break;
602 }
603 }
604 handle_ieee_exc(env, vxc, vec_exc, retaddr);
605 *v1 = tmp;
606}
607
c64c5984
DH
608static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
609 const S390Vector *v4, CPUS390XState *env, bool s, int flags,
610 uintptr_t retaddr)
611{
612 uint8_t vxc, vec_exc = 0;
613 S390Vector tmp = {};
614 int i;
615
616 for (i = 0; i < 2; i++) {
34142ffd
DH
617 const float64 a = s390_vec_read_float64(v2, i);
618 const float64 b = s390_vec_read_float64(v3, i);
619 const float64 c = s390_vec_read_float64(v4, i);
620 const float64 ret = float64_muladd(a, b, c, flags, &env->fpu_status);
c64c5984 621
34142ffd 622 s390_vec_write_float64(&tmp, i, ret);
c64c5984
DH
623 vxc = check_ieee_exc(env, i, false, &vec_exc);
624 if (s || vxc) {
625 break;
626 }
627 }
628 handle_ieee_exc(env, vxc, vec_exc, retaddr);
629 *v1 = tmp;
630}
631
e257abc8
DH
632static void vfma128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
633 const S390Vector *v4, CPUS390XState *env, bool s, int flags,
634 uintptr_t retaddr)
635{
636 const float128 a = s390_vec_read_float128(v2);
637 const float128 b = s390_vec_read_float128(v3);
638 const float128 c = s390_vec_read_float128(v4);
639 uint8_t vxc, vec_exc = 0;
640 float128 ret;
641
642 ret = float128_muladd(a, b, c, flags, &env->fpu_status);
643 vxc = check_ieee_exc(env, 0, false, &vec_exc);
644 handle_ieee_exc(env, vxc, vec_exc, retaddr);
645 s390_vec_write_float128(v1, ret);
646}
647
34142ffd
DH
648#define DEF_GVEC_VFMA_B(NAME, FLAGS, BITS) \
649void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \
650 const void *v4, CPUS390XState *env, \
651 uint32_t desc) \
652{ \
653 const bool se = extract32(simd_data(desc), 3, 1); \
654 \
655 vfma##BITS(v1, v2, v3, v4, env, se, FLAGS, GETPC()); \
c64c5984
DH
656}
657
34142ffd 658#define DEF_GVEC_VFMA(NAME, FLAGS) \
e257abc8
DH
659 DEF_GVEC_VFMA_B(NAME, FLAGS, 32) \
660 DEF_GVEC_VFMA_B(NAME, FLAGS, 64) \
661 DEF_GVEC_VFMA_B(NAME, FLAGS, 128)
c64c5984 662
34142ffd
DH
663DEF_GVEC_VFMA(vfma, 0)
664DEF_GVEC_VFMA(vfms, float_muladd_negate_c)
f0249730
DH
665DEF_GVEC_VFMA(vfnma, float_muladd_negate_result)
666DEF_GVEC_VFMA(vfnms, float_muladd_negate_c | float_muladd_negate_result)
5938f20c 667
a38b5a0e
DH
668void HELPER(gvec_vftci32)(void *v1, const void *v2, CPUS390XState *env,
669 uint32_t desc)
670{
671 uint16_t i3 = extract32(simd_data(desc), 4, 12);
672 bool s = extract32(simd_data(desc), 3, 1);
673 int i, match = 0;
674
675 for (i = 0; i < 4; i++) {
676 float32 a = s390_vec_read_float32(v2, i);
677
678 if (float32_dcmask(env, a) & i3) {
679 match++;
680 s390_vec_write_element32(v1, i, -1u);
681 } else {
682 s390_vec_write_element32(v1, i, 0);
683 }
684 if (s) {
685 break;
686 }
687 }
688
689 if (match == 4 || (s && match)) {
690 env->cc_op = 0;
691 } else if (match) {
692 env->cc_op = 1;
693 } else {
694 env->cc_op = 3;
695 }
696}
697
622ebe64
DH
698void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env,
699 uint32_t desc)
83b955f9 700{
622ebe64
DH
701 const uint16_t i3 = extract32(simd_data(desc), 4, 12);
702 const bool s = extract32(simd_data(desc), 3, 1);
83b955f9
DH
703 int i, match = 0;
704
705 for (i = 0; i < 2; i++) {
622ebe64 706 const float64 a = s390_vec_read_float64(v2, i);
83b955f9
DH
707
708 if (float64_dcmask(env, a) & i3) {
709 match++;
710 s390_vec_write_element64(v1, i, -1ull);
711 } else {
712 s390_vec_write_element64(v1, i, 0);
713 }
714 if (s) {
715 break;
716 }
717 }
718
622ebe64
DH
719 if (match == 2 || (s && match)) {
720 env->cc_op = 0;
721 } else if (match) {
722 env->cc_op = 1;
723 } else {
724 env->cc_op = 3;
83b955f9 725 }
83b955f9 726}
a38b5a0e
DH
727
728void HELPER(gvec_vftci128)(void *v1, const void *v2, CPUS390XState *env,
729 uint32_t desc)
730{
731 const float128 a = s390_vec_read_float128(v2);
732 uint16_t i3 = extract32(simd_data(desc), 4, 12);
733
734 if (float128_dcmask(env, a) & i3) {
735 env->cc_op = 0;
736 s390_vec_write_element64(v1, 0, -1ull);
737 s390_vec_write_element64(v1, 1, -1ull);
738 } else {
739 env->cc_op = 3;
740 s390_vec_write_element64(v1, 0, 0);
741 s390_vec_write_element64(v1, 1, 0);
742 }
743}
da480752
DH
744
745typedef enum S390MinMaxType {
746 S390_MINMAX_TYPE_IEEE = 0,
747 S390_MINMAX_TYPE_JAVA,
748 S390_MINMAX_TYPE_C_MACRO,
749 S390_MINMAX_TYPE_CPP,
750 S390_MINMAX_TYPE_F,
751} S390MinMaxType;
752
753typedef enum S390MinMaxRes {
754 S390_MINMAX_RES_MINMAX = 0,
755 S390_MINMAX_RES_A,
756 S390_MINMAX_RES_B,
757 S390_MINMAX_RES_SILENCE_A,
758 S390_MINMAX_RES_SILENCE_B,
759} S390MinMaxRes;
760
761static S390MinMaxRes vfmin_res(uint16_t dcmask_a, uint16_t dcmask_b,
762 S390MinMaxType type, float_status *s)
763{
764 const bool neg_a = dcmask_a & DCMASK_NEGATIVE;
765 const bool nan_a = dcmask_a & DCMASK_NAN;
766 const bool nan_b = dcmask_b & DCMASK_NAN;
767
768 g_assert(type > S390_MINMAX_TYPE_IEEE && type <= S390_MINMAX_TYPE_F);
769
770 if (unlikely((dcmask_a | dcmask_b) & DCMASK_NAN)) {
771 const bool sig_a = dcmask_a & DCMASK_SIGNALING_NAN;
772 const bool sig_b = dcmask_b & DCMASK_SIGNALING_NAN;
773
774 if ((dcmask_a | dcmask_b) & DCMASK_SIGNALING_NAN) {
775 s->float_exception_flags |= float_flag_invalid;
776 }
777 switch (type) {
778 case S390_MINMAX_TYPE_JAVA:
779 if (sig_a) {
780 return S390_MINMAX_RES_SILENCE_A;
781 } else if (sig_b) {
782 return S390_MINMAX_RES_SILENCE_B;
783 }
784 return nan_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
785 case S390_MINMAX_TYPE_F:
786 return nan_b ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
787 case S390_MINMAX_TYPE_C_MACRO:
788 s->float_exception_flags |= float_flag_invalid;
789 return S390_MINMAX_RES_B;
790 case S390_MINMAX_TYPE_CPP:
791 s->float_exception_flags |= float_flag_invalid;
792 return S390_MINMAX_RES_A;
793 default:
794 g_assert_not_reached();
795 }
796 } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) {
797 switch (type) {
798 case S390_MINMAX_TYPE_JAVA:
799 return neg_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
800 case S390_MINMAX_TYPE_C_MACRO:
801 return S390_MINMAX_RES_B;
802 case S390_MINMAX_TYPE_F:
803 return !neg_a ? S390_MINMAX_RES_B : S390_MINMAX_RES_A;
804 case S390_MINMAX_TYPE_CPP:
805 return S390_MINMAX_RES_A;
806 default:
807 g_assert_not_reached();
808 }
809 }
810 return S390_MINMAX_RES_MINMAX;
811}
812
813static S390MinMaxRes vfmax_res(uint16_t dcmask_a, uint16_t dcmask_b,
814 S390MinMaxType type, float_status *s)
815{
816 g_assert(type > S390_MINMAX_TYPE_IEEE && type <= S390_MINMAX_TYPE_F);
817
818 if (unlikely((dcmask_a | dcmask_b) & DCMASK_NAN)) {
819 const bool sig_a = dcmask_a & DCMASK_SIGNALING_NAN;
820 const bool sig_b = dcmask_b & DCMASK_SIGNALING_NAN;
821 const bool nan_a = dcmask_a & DCMASK_NAN;
822 const bool nan_b = dcmask_b & DCMASK_NAN;
823
824 if ((dcmask_a | dcmask_b) & DCMASK_SIGNALING_NAN) {
825 s->float_exception_flags |= float_flag_invalid;
826 }
827 switch (type) {
828 case S390_MINMAX_TYPE_JAVA:
829 if (sig_a) {
830 return S390_MINMAX_RES_SILENCE_A;
831 } else if (sig_b) {
832 return S390_MINMAX_RES_SILENCE_B;
833 }
834 return nan_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
835 case S390_MINMAX_TYPE_F:
836 return nan_b ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
837 case S390_MINMAX_TYPE_C_MACRO:
838 s->float_exception_flags |= float_flag_invalid;
839 return S390_MINMAX_RES_B;
840 case S390_MINMAX_TYPE_CPP:
841 s->float_exception_flags |= float_flag_invalid;
842 return S390_MINMAX_RES_A;
843 default:
844 g_assert_not_reached();
845 }
846 } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) {
847 const bool neg_a = dcmask_a & DCMASK_NEGATIVE;
848
849 switch (type) {
850 case S390_MINMAX_TYPE_JAVA:
851 case S390_MINMAX_TYPE_F:
852 return neg_a ? S390_MINMAX_RES_B : S390_MINMAX_RES_A;
853 case S390_MINMAX_TYPE_C_MACRO:
854 return S390_MINMAX_RES_B;
855 case S390_MINMAX_TYPE_CPP:
856 return S390_MINMAX_RES_A;
857 default:
858 g_assert_not_reached();
859 }
860 }
861 return S390_MINMAX_RES_MINMAX;
862}
863
864static S390MinMaxRes vfminmax_res(uint16_t dcmask_a, uint16_t dcmask_b,
865 S390MinMaxType type, bool is_min,
866 float_status *s)
867{
868 return is_min ? vfmin_res(dcmask_a, dcmask_b, type, s) :
869 vfmax_res(dcmask_a, dcmask_b, type, s);
870}
871
872static void vfminmax32(S390Vector *v1, const S390Vector *v2,
873 const S390Vector *v3, CPUS390XState *env,
874 S390MinMaxType type, bool is_min, bool is_abs, bool se,
875 uintptr_t retaddr)
876{
877 float_status *s = &env->fpu_status;
878 uint8_t vxc, vec_exc = 0;
879 S390Vector tmp = {};
880 int i;
881
882 for (i = 0; i < 4; i++) {
883 float32 a = s390_vec_read_float32(v2, i);
884 float32 b = s390_vec_read_float32(v3, i);
885 float32 result;
886
887 if (type != S390_MINMAX_TYPE_IEEE) {
888 S390MinMaxRes res;
889
890 if (is_abs) {
891 a = float32_abs(a);
892 b = float32_abs(b);
893 }
894
895 res = vfminmax_res(float32_dcmask(env, a), float32_dcmask(env, b),
896 type, is_min, s);
897 switch (res) {
898 case S390_MINMAX_RES_MINMAX:
899 result = is_min ? float32_min(a, b, s) : float32_max(a, b, s);
900 break;
901 case S390_MINMAX_RES_A:
902 result = a;
903 break;
904 case S390_MINMAX_RES_B:
905 result = b;
906 break;
907 case S390_MINMAX_RES_SILENCE_A:
908 result = float32_silence_nan(a, s);
909 break;
910 case S390_MINMAX_RES_SILENCE_B:
911 result = float32_silence_nan(b, s);
912 break;
913 default:
914 g_assert_not_reached();
915 }
916 } else if (!is_abs) {
917 result = is_min ? float32_minnum(a, b, &env->fpu_status) :
918 float32_maxnum(a, b, &env->fpu_status);
919 } else {
920 result = is_min ? float32_minnummag(a, b, &env->fpu_status) :
921 float32_maxnummag(a, b, &env->fpu_status);
922 }
923
924 s390_vec_write_float32(&tmp, i, result);
925 vxc = check_ieee_exc(env, i, false, &vec_exc);
926 if (se || vxc) {
927 break;
928 }
929 }
930 handle_ieee_exc(env, vxc, vec_exc, retaddr);
931 *v1 = tmp;
932}
933
934static void vfminmax64(S390Vector *v1, const S390Vector *v2,
935 const S390Vector *v3, CPUS390XState *env,
936 S390MinMaxType type, bool is_min, bool is_abs, bool se,
937 uintptr_t retaddr)
938{
939 float_status *s = &env->fpu_status;
940 uint8_t vxc, vec_exc = 0;
941 S390Vector tmp = {};
942 int i;
943
944 for (i = 0; i < 2; i++) {
945 float64 a = s390_vec_read_float64(v2, i);
946 float64 b = s390_vec_read_float64(v3, i);
947 float64 result;
948
949 if (type != S390_MINMAX_TYPE_IEEE) {
950 S390MinMaxRes res;
951
952 if (is_abs) {
953 a = float64_abs(a);
954 b = float64_abs(b);
955 }
956
957 res = vfminmax_res(float64_dcmask(env, a), float64_dcmask(env, b),
958 type, is_min, s);
959 switch (res) {
960 case S390_MINMAX_RES_MINMAX:
961 result = is_min ? float64_min(a, b, s) : float64_max(a, b, s);
962 break;
963 case S390_MINMAX_RES_A:
964 result = a;
965 break;
966 case S390_MINMAX_RES_B:
967 result = b;
968 break;
969 case S390_MINMAX_RES_SILENCE_A:
970 result = float64_silence_nan(a, s);
971 break;
972 case S390_MINMAX_RES_SILENCE_B:
973 result = float64_silence_nan(b, s);
974 break;
975 default:
976 g_assert_not_reached();
977 }
978 } else if (!is_abs) {
979 result = is_min ? float64_minnum(a, b, &env->fpu_status) :
980 float64_maxnum(a, b, &env->fpu_status);
981 } else {
982 result = is_min ? float64_minnummag(a, b, &env->fpu_status) :
983 float64_maxnummag(a, b, &env->fpu_status);
984 }
985
986 s390_vec_write_float64(&tmp, i, result);
987 vxc = check_ieee_exc(env, i, false, &vec_exc);
988 if (se || vxc) {
989 break;
990 }
991 }
992 handle_ieee_exc(env, vxc, vec_exc, retaddr);
993 *v1 = tmp;
994}
995
996static void vfminmax128(S390Vector *v1, const S390Vector *v2,
997 const S390Vector *v3, CPUS390XState *env,
998 S390MinMaxType type, bool is_min, bool is_abs, bool se,
999 uintptr_t retaddr)
1000{
1001 float128 a = s390_vec_read_float128(v2);
1002 float128 b = s390_vec_read_float128(v3);
1003 float_status *s = &env->fpu_status;
1004 uint8_t vxc, vec_exc = 0;
1005 float128 result;
1006
1007 if (type != S390_MINMAX_TYPE_IEEE) {
1008 S390MinMaxRes res;
1009
1010 if (is_abs) {
1011 a = float128_abs(a);
1012 b = float128_abs(b);
1013 }
1014
1015 res = vfminmax_res(float128_dcmask(env, a), float128_dcmask(env, b),
1016 type, is_min, s);
1017 switch (res) {
1018 case S390_MINMAX_RES_MINMAX:
1019 result = is_min ? float128_min(a, b, s) : float128_max(a, b, s);
1020 break;
1021 case S390_MINMAX_RES_A:
1022 result = a;
1023 break;
1024 case S390_MINMAX_RES_B:
1025 result = b;
1026 break;
1027 case S390_MINMAX_RES_SILENCE_A:
1028 result = float128_silence_nan(a, s);
1029 break;
1030 case S390_MINMAX_RES_SILENCE_B:
1031 result = float128_silence_nan(b, s);
1032 break;
1033 default:
1034 g_assert_not_reached();
1035 }
1036 } else if (!is_abs) {
1037 result = is_min ? float128_minnum(a, b, &env->fpu_status) :
1038 float128_maxnum(a, b, &env->fpu_status);
1039 } else {
1040 result = is_min ? float128_minnummag(a, b, &env->fpu_status) :
1041 float128_maxnummag(a, b, &env->fpu_status);
1042 }
1043
1044 vxc = check_ieee_exc(env, 0, false, &vec_exc);
1045 handle_ieee_exc(env, vxc, vec_exc, retaddr);
1046 s390_vec_write_float128(v1, result);
1047}
1048
1049#define DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, BITS) \
1050void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \
1051 CPUS390XState *env, uint32_t desc) \
1052{ \
1053 const bool se = extract32(simd_data(desc), 3, 1); \
1054 uint8_t type = extract32(simd_data(desc), 4, 4); \
1055 bool is_abs = false; \
1056 \
1057 if (type >= 8) { \
1058 is_abs = true; \
1059 type -= 8; \
1060 } \
1061 \
1062 vfminmax##BITS(v1, v2, v3, env, type, IS_MIN, is_abs, se, GETPC()); \
1063}
1064
1065#define DEF_GVEC_VFMINMAX(NAME, IS_MIN) \
1066 DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 32) \
1067 DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 64) \
1068 DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 128)
1069
1070DEF_GVEC_VFMINMAX(vfmax, false)
1071DEF_GVEC_VFMINMAX(vfmin, true)