s390x/tcg: Implement VECTOR FP NEGATIVE MULTIPLY AND (ADD|SUBTRACT)
[qemu/kevin.git] / target / s390x / vec_fpu_helper.c
blobdc9bcc90a765e92e27f67b28462d47fa92a76d2b
1 /*
2 * QEMU TCG support -- s390x vector floating point instruction support
4 * Copyright (C) 2019 Red Hat Inc
6 * Authors:
7 * David Hildenbrand <david@redhat.com>
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.
12 #include "qemu/osdep.h"
13 #include "qemu-common.h"
14 #include "cpu.h"
15 #include "internal.h"
16 #include "vec.h"
17 #include "tcg_s390x.h"
18 #include "tcg/tcg-gvec-desc.h"
19 #include "exec/exec-all.h"
20 #include "exec/helper-proto.h"
21 #include "fpu/softfloat.h"
23 #define VIC_INVALID 0x1
24 #define VIC_DIVBYZERO 0x2
25 #define VIC_OVERFLOW 0x3
26 #define VIC_UNDERFLOW 0x4
27 #define VIC_INEXACT 0x5
29 /* returns the VEX. If the VEX is 0, there is no trap */
30 static uint8_t check_ieee_exc(CPUS390XState *env, uint8_t enr, bool XxC,
31 uint8_t *vec_exc)
33 uint8_t vece_exc = 0, trap_exc;
34 unsigned qemu_exc;
36 /* Retrieve and clear the softfloat exceptions */
37 qemu_exc = env->fpu_status.float_exception_flags;
38 if (qemu_exc == 0) {
39 return 0;
41 env->fpu_status.float_exception_flags = 0;
43 vece_exc = s390_softfloat_exc_to_ieee(qemu_exc);
45 /* Add them to the vector-wide s390x exception bits */
46 *vec_exc |= vece_exc;
48 /* Check for traps and construct the VXC */
49 trap_exc = vece_exc & env->fpc >> 24;
50 if (trap_exc) {
51 if (trap_exc & S390_IEEE_MASK_INVALID) {
52 return enr << 4 | VIC_INVALID;
53 } else if (trap_exc & S390_IEEE_MASK_DIVBYZERO) {
54 return enr << 4 | VIC_DIVBYZERO;
55 } else if (trap_exc & S390_IEEE_MASK_OVERFLOW) {
56 return enr << 4 | VIC_OVERFLOW;
57 } else if (trap_exc & S390_IEEE_MASK_UNDERFLOW) {
58 return enr << 4 | VIC_UNDERFLOW;
59 } else if (!XxC) {
60 g_assert(trap_exc & S390_IEEE_MASK_INEXACT);
61 /* inexact has lowest priority on traps */
62 return enr << 4 | VIC_INEXACT;
65 return 0;
68 static void handle_ieee_exc(CPUS390XState *env, uint8_t vxc, uint8_t vec_exc,
69 uintptr_t retaddr)
71 if (vxc) {
72 /* on traps, the fpc flags are not updated, instruction is suppressed */
73 tcg_s390_vector_exception(env, vxc, retaddr);
75 if (vec_exc) {
76 /* indicate exceptions for all elements combined */
77 env->fpc |= vec_exc << 16;
81 static float32 s390_vec_read_float32(const S390Vector *v, uint8_t enr)
83 return make_float32(s390_vec_read_element32(v, enr));
86 static float64 s390_vec_read_float64(const S390Vector *v, uint8_t enr)
88 return make_float64(s390_vec_read_element64(v, enr));
91 static float128 s390_vec_read_float128(const S390Vector *v)
93 return make_float128(s390_vec_read_element64(v, 0),
94 s390_vec_read_element64(v, 1));
97 static void s390_vec_write_float32(S390Vector *v, uint8_t enr, float32 data)
99 return s390_vec_write_element32(v, enr, data);
102 static void s390_vec_write_float64(S390Vector *v, uint8_t enr, float64 data)
104 return s390_vec_write_element64(v, enr, data);
107 static void s390_vec_write_float128(S390Vector *v, float128 data)
109 s390_vec_write_element64(v, 0, data.high);
110 s390_vec_write_element64(v, 1, data.low);
113 typedef float32 (*vop32_2_fn)(float32 a, float_status *s);
114 static void vop32_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
115 bool s, bool XxC, uint8_t erm, vop32_2_fn fn,
116 uintptr_t retaddr)
118 uint8_t vxc, vec_exc = 0;
119 S390Vector tmp = {};
120 int i, old_mode;
122 old_mode = s390_swap_bfp_rounding_mode(env, erm);
123 for (i = 0; i < 4; i++) {
124 const float32 a = s390_vec_read_float32(v2, i);
126 s390_vec_write_float32(&tmp, i, fn(a, &env->fpu_status));
127 vxc = check_ieee_exc(env, i, XxC, &vec_exc);
128 if (s || vxc) {
129 break;
132 s390_restore_bfp_rounding_mode(env, old_mode);
133 handle_ieee_exc(env, vxc, vec_exc, retaddr);
134 *v1 = tmp;
137 typedef float64 (*vop64_2_fn)(float64 a, float_status *s);
138 static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
139 bool s, bool XxC, uint8_t erm, vop64_2_fn fn,
140 uintptr_t retaddr)
142 uint8_t vxc, vec_exc = 0;
143 S390Vector tmp = {};
144 int i, old_mode;
146 old_mode = s390_swap_bfp_rounding_mode(env, erm);
147 for (i = 0; i < 2; i++) {
148 const float64 a = s390_vec_read_float64(v2, i);
150 s390_vec_write_float64(&tmp, i, fn(a, &env->fpu_status));
151 vxc = check_ieee_exc(env, i, XxC, &vec_exc);
152 if (s || vxc) {
153 break;
156 s390_restore_bfp_rounding_mode(env, old_mode);
157 handle_ieee_exc(env, vxc, vec_exc, retaddr);
158 *v1 = tmp;
161 typedef float128 (*vop128_2_fn)(float128 a, float_status *s);
162 static void vop128_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
163 bool s, bool XxC, uint8_t erm, vop128_2_fn fn,
164 uintptr_t retaddr)
166 const float128 a = s390_vec_read_float128(v2);
167 uint8_t vxc, vec_exc = 0;
168 S390Vector tmp = {};
169 int old_mode;
171 old_mode = s390_swap_bfp_rounding_mode(env, erm);
172 s390_vec_write_float128(&tmp, fn(a, &env->fpu_status));
173 vxc = check_ieee_exc(env, 0, XxC, &vec_exc);
174 s390_restore_bfp_rounding_mode(env, old_mode);
175 handle_ieee_exc(env, vxc, vec_exc, retaddr);
176 *v1 = tmp;
179 static float64 vcdg64(float64 a, float_status *s)
181 return int64_to_float64(a, s);
184 static float64 vcdlg64(float64 a, float_status *s)
186 return uint64_to_float64(a, s);
189 static float64 vcgd64(float64 a, float_status *s)
191 const float64 tmp = float64_to_int64(a, s);
193 return float64_is_any_nan(a) ? INT64_MIN : tmp;
196 static float64 vclgd64(float64 a, float_status *s)
198 const float64 tmp = float64_to_uint64(a, s);
200 return float64_is_any_nan(a) ? 0 : tmp;
203 #define DEF_GVEC_VOP2_FN(NAME, FN, BITS) \
204 void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, CPUS390XState *env, \
205 uint32_t desc) \
207 const uint8_t erm = extract32(simd_data(desc), 4, 4); \
208 const bool se = extract32(simd_data(desc), 3, 1); \
209 const bool XxC = extract32(simd_data(desc), 2, 1); \
211 vop##BITS##_2(v1, v2, env, se, XxC, erm, FN, GETPC()); \
214 #define DEF_GVEC_VOP2_64(NAME) \
215 DEF_GVEC_VOP2_FN(NAME, NAME##64, 64)
217 #define DEF_GVEC_VOP2(NAME, OP) \
218 DEF_GVEC_VOP2_FN(NAME, float32_##OP, 32) \
219 DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64) \
220 DEF_GVEC_VOP2_FN(NAME, float128_##OP, 128)
222 DEF_GVEC_VOP2_64(vcdg)
223 DEF_GVEC_VOP2_64(vcdlg)
224 DEF_GVEC_VOP2_64(vcgd)
225 DEF_GVEC_VOP2_64(vclgd)
226 DEF_GVEC_VOP2(vfi, round_to_int)
227 DEF_GVEC_VOP2(vfsq, sqrt)
229 typedef float32 (*vop32_3_fn)(float32 a, float32 b, float_status *s);
230 static void vop32_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
231 CPUS390XState *env, bool s, vop32_3_fn fn,
232 uintptr_t retaddr)
234 uint8_t vxc, vec_exc = 0;
235 S390Vector tmp = {};
236 int i;
238 for (i = 0; i < 4; i++) {
239 const float32 a = s390_vec_read_float32(v2, i);
240 const float32 b = s390_vec_read_float32(v3, i);
242 s390_vec_write_float32(&tmp, i, fn(a, b, &env->fpu_status));
243 vxc = check_ieee_exc(env, i, false, &vec_exc);
244 if (s || vxc) {
245 break;
248 handle_ieee_exc(env, vxc, vec_exc, retaddr);
249 *v1 = tmp;
252 typedef float64 (*vop64_3_fn)(float64 a, float64 b, float_status *s);
253 static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
254 CPUS390XState *env, bool s, vop64_3_fn fn,
255 uintptr_t retaddr)
257 uint8_t vxc, vec_exc = 0;
258 S390Vector tmp = {};
259 int i;
261 for (i = 0; i < 2; i++) {
262 const float64 a = s390_vec_read_float64(v2, i);
263 const float64 b = s390_vec_read_float64(v3, i);
265 s390_vec_write_float64(&tmp, i, fn(a, b, &env->fpu_status));
266 vxc = check_ieee_exc(env, i, false, &vec_exc);
267 if (s || vxc) {
268 break;
271 handle_ieee_exc(env, vxc, vec_exc, retaddr);
272 *v1 = tmp;
275 typedef float128 (*vop128_3_fn)(float128 a, float128 b, float_status *s);
276 static void vop128_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
277 CPUS390XState *env, bool s, vop128_3_fn fn,
278 uintptr_t retaddr)
280 const float128 a = s390_vec_read_float128(v2);
281 const float128 b = s390_vec_read_float128(v3);
282 uint8_t vxc, vec_exc = 0;
283 S390Vector tmp = {};
285 s390_vec_write_float128(&tmp, fn(a, b, &env->fpu_status));
286 vxc = check_ieee_exc(env, 0, false, &vec_exc);
287 handle_ieee_exc(env, vxc, vec_exc, retaddr);
288 *v1 = tmp;
291 #define DEF_GVEC_VOP3_B(NAME, OP, BITS) \
292 void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \
293 CPUS390XState *env, uint32_t desc) \
295 const bool se = extract32(simd_data(desc), 3, 1); \
297 vop##BITS##_3(v1, v2, v3, env, se, float##BITS##_##OP, GETPC()); \
300 #define DEF_GVEC_VOP3(NAME, OP) \
301 DEF_GVEC_VOP3_B(NAME, OP, 32) \
302 DEF_GVEC_VOP3_B(NAME, OP, 64) \
303 DEF_GVEC_VOP3_B(NAME, OP, 128)
305 DEF_GVEC_VOP3(vfa, add)
306 DEF_GVEC_VOP3(vfs, sub)
307 DEF_GVEC_VOP3(vfd, div)
308 DEF_GVEC_VOP3(vfm, mul)
310 static int wfc32(const S390Vector *v1, const S390Vector *v2,
311 CPUS390XState *env, bool signal, uintptr_t retaddr)
313 /* only the zero-indexed elements are compared */
314 const float32 a = s390_vec_read_float32(v1, 0);
315 const float32 b = s390_vec_read_float32(v2, 0);
316 uint8_t vxc, vec_exc = 0;
317 int cmp;
319 if (signal) {
320 cmp = float32_compare(a, b, &env->fpu_status);
321 } else {
322 cmp = float32_compare_quiet(a, b, &env->fpu_status);
324 vxc = check_ieee_exc(env, 0, false, &vec_exc);
325 handle_ieee_exc(env, vxc, vec_exc, retaddr);
327 return float_comp_to_cc(env, cmp);
330 static int wfc64(const S390Vector *v1, const S390Vector *v2,
331 CPUS390XState *env, bool signal, uintptr_t retaddr)
333 /* only the zero-indexed elements are compared */
334 const float64 a = s390_vec_read_float64(v1, 0);
335 const float64 b = s390_vec_read_float64(v2, 0);
336 uint8_t vxc, vec_exc = 0;
337 int cmp;
339 if (signal) {
340 cmp = float64_compare(a, b, &env->fpu_status);
341 } else {
342 cmp = float64_compare_quiet(a, b, &env->fpu_status);
344 vxc = check_ieee_exc(env, 0, false, &vec_exc);
345 handle_ieee_exc(env, vxc, vec_exc, retaddr);
347 return float_comp_to_cc(env, cmp);
350 static int wfc128(const S390Vector *v1, const S390Vector *v2,
351 CPUS390XState *env, bool signal, uintptr_t retaddr)
353 /* only the zero-indexed elements are compared */
354 const float128 a = s390_vec_read_float128(v1);
355 const float128 b = s390_vec_read_float128(v2);
356 uint8_t vxc, vec_exc = 0;
357 int cmp;
359 if (signal) {
360 cmp = float128_compare(a, b, &env->fpu_status);
361 } else {
362 cmp = float128_compare_quiet(a, b, &env->fpu_status);
364 vxc = check_ieee_exc(env, 0, false, &vec_exc);
365 handle_ieee_exc(env, vxc, vec_exc, retaddr);
367 return float_comp_to_cc(env, cmp);
370 #define DEF_GVEC_WFC_B(NAME, SIGNAL, BITS) \
371 void HELPER(gvec_##NAME##BITS)(const void *v1, const void *v2, \
372 CPUS390XState *env, uint32_t desc) \
374 env->cc_op = wfc##BITS(v1, v2, env, SIGNAL, GETPC()); \
377 #define DEF_GVEC_WFC(NAME, SIGNAL) \
378 DEF_GVEC_WFC_B(NAME, SIGNAL, 32) \
379 DEF_GVEC_WFC_B(NAME, SIGNAL, 64) \
380 DEF_GVEC_WFC_B(NAME, SIGNAL, 128)
382 DEF_GVEC_WFC(wfc, false)
383 DEF_GVEC_WFC(wfk, true)
385 typedef bool (*vfc32_fn)(float32 a, float32 b, float_status *status);
386 static int vfc32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
387 CPUS390XState *env, bool s, vfc32_fn fn, uintptr_t retaddr)
389 uint8_t vxc, vec_exc = 0;
390 S390Vector tmp = {};
391 int match = 0;
392 int i;
394 for (i = 0; i < 4; i++) {
395 const float32 a = s390_vec_read_float32(v2, i);
396 const float32 b = s390_vec_read_float32(v3, i);
398 /* swap the order of the parameters, so we can use existing functions */
399 if (fn(b, a, &env->fpu_status)) {
400 match++;
401 s390_vec_write_element32(&tmp, i, -1u);
403 vxc = check_ieee_exc(env, i, false, &vec_exc);
404 if (s || vxc) {
405 break;
409 handle_ieee_exc(env, vxc, vec_exc, retaddr);
410 *v1 = tmp;
411 if (match) {
412 return s || match == 4 ? 0 : 1;
414 return 3;
417 typedef bool (*vfc64_fn)(float64 a, float64 b, float_status *status);
418 static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
419 CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr)
421 uint8_t vxc, vec_exc = 0;
422 S390Vector tmp = {};
423 int match = 0;
424 int i;
426 for (i = 0; i < 2; i++) {
427 const float64 a = s390_vec_read_float64(v2, i);
428 const float64 b = s390_vec_read_float64(v3, i);
430 /* swap the order of the parameters, so we can use existing functions */
431 if (fn(b, a, &env->fpu_status)) {
432 match++;
433 s390_vec_write_element64(&tmp, i, -1ull);
435 vxc = check_ieee_exc(env, i, false, &vec_exc);
436 if (s || vxc) {
437 break;
441 handle_ieee_exc(env, vxc, vec_exc, retaddr);
442 *v1 = tmp;
443 if (match) {
444 return s || match == 2 ? 0 : 1;
446 return 3;
449 typedef bool (*vfc128_fn)(float128 a, float128 b, float_status *status);
450 static int vfc128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
451 CPUS390XState *env, bool s, vfc128_fn fn, uintptr_t retaddr)
453 const float128 a = s390_vec_read_float128(v2);
454 const float128 b = s390_vec_read_float128(v3);
455 uint8_t vxc, vec_exc = 0;
456 S390Vector tmp = {};
457 bool match = false;
459 /* swap the order of the parameters, so we can use existing functions */
460 if (fn(b, a, &env->fpu_status)) {
461 match = true;
462 s390_vec_write_element64(&tmp, 0, -1ull);
463 s390_vec_write_element64(&tmp, 1, -1ull);
465 vxc = check_ieee_exc(env, 0, false, &vec_exc);
466 handle_ieee_exc(env, vxc, vec_exc, retaddr);
467 *v1 = tmp;
468 return match ? 0 : 3;
471 #define DEF_GVEC_VFC_B(NAME, OP, BITS) \
472 void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \
473 CPUS390XState *env, uint32_t desc) \
475 const bool se = extract32(simd_data(desc), 3, 1); \
476 const bool sq = extract32(simd_data(desc), 2, 1); \
477 vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet; \
479 vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \
482 void HELPER(gvec_##NAME##BITS##_cc)(void *v1, const void *v2, const void *v3, \
483 CPUS390XState *env, uint32_t desc) \
485 const bool se = extract32(simd_data(desc), 3, 1); \
486 const bool sq = extract32(simd_data(desc), 2, 1); \
487 vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet; \
489 env->cc_op = vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \
492 #define DEF_GVEC_VFC(NAME, OP) \
493 DEF_GVEC_VFC_B(NAME, OP, 32) \
494 DEF_GVEC_VFC_B(NAME, OP, 64) \
495 DEF_GVEC_VFC_B(NAME, OP, 128) \
497 DEF_GVEC_VFC(vfce, eq)
498 DEF_GVEC_VFC(vfch, lt)
499 DEF_GVEC_VFC(vfche, le)
501 void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env,
502 uint32_t desc)
504 const bool s = extract32(simd_data(desc), 3, 1);
505 uint8_t vxc, vec_exc = 0;
506 S390Vector tmp = {};
507 int i;
509 for (i = 0; i < 2; i++) {
510 /* load from even element */
511 const float32 a = s390_vec_read_element32(v2, i * 2);
512 const uint64_t ret = float32_to_float64(a, &env->fpu_status);
514 s390_vec_write_element64(&tmp, i, ret);
515 /* indicate the source element */
516 vxc = check_ieee_exc(env, i * 2, false, &vec_exc);
517 if (s || vxc) {
518 break;
521 handle_ieee_exc(env, vxc, vec_exc, GETPC());
522 *(S390Vector *)v1 = tmp;
525 void HELPER(gvec_vfll64)(void *v1, const void *v2, CPUS390XState *env,
526 uint32_t desc)
528 /* load from even element */
529 const float128 ret = float64_to_float128(s390_vec_read_float64(v2, 0),
530 &env->fpu_status);
531 uint8_t vxc, vec_exc = 0;
533 vxc = check_ieee_exc(env, 0, false, &vec_exc);
534 handle_ieee_exc(env, vxc, vec_exc, GETPC());
535 s390_vec_write_float128(v1, ret);
538 void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env,
539 uint32_t desc)
541 const uint8_t erm = extract32(simd_data(desc), 4, 4);
542 const bool s = extract32(simd_data(desc), 3, 1);
543 const bool XxC = extract32(simd_data(desc), 2, 1);
544 uint8_t vxc, vec_exc = 0;
545 S390Vector tmp = {};
546 int i, old_mode;
548 old_mode = s390_swap_bfp_rounding_mode(env, erm);
549 for (i = 0; i < 2; i++) {
550 float64 a = s390_vec_read_element64(v2, i);
551 uint32_t ret = float64_to_float32(a, &env->fpu_status);
553 /* place at even element */
554 s390_vec_write_element32(&tmp, i * 2, ret);
555 /* indicate the source element */
556 vxc = check_ieee_exc(env, i, XxC, &vec_exc);
557 if (s || vxc) {
558 break;
561 s390_restore_bfp_rounding_mode(env, old_mode);
562 handle_ieee_exc(env, vxc, vec_exc, GETPC());
563 *(S390Vector *)v1 = tmp;
566 void HELPER(gvec_vflr128)(void *v1, const void *v2, CPUS390XState *env,
567 uint32_t desc)
569 const uint8_t erm = extract32(simd_data(desc), 4, 4);
570 const bool XxC = extract32(simd_data(desc), 2, 1);
571 uint8_t vxc, vec_exc = 0;
572 int old_mode;
573 float64 ret;
575 old_mode = s390_swap_bfp_rounding_mode(env, erm);
576 ret = float128_to_float64(s390_vec_read_float128(v2), &env->fpu_status);
577 vxc = check_ieee_exc(env, 0, XxC, &vec_exc);
578 s390_restore_bfp_rounding_mode(env, old_mode);
579 handle_ieee_exc(env, vxc, vec_exc, GETPC());
581 /* place at even element, odd element is unpredictable */
582 s390_vec_write_float64(v1, 0, ret);
585 static void vfma32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
586 const S390Vector *v4, CPUS390XState *env, bool s, int flags,
587 uintptr_t retaddr)
589 uint8_t vxc, vec_exc = 0;
590 S390Vector tmp = {};
591 int i;
593 for (i = 0; i < 4; i++) {
594 const float32 a = s390_vec_read_float32(v2, i);
595 const float32 b = s390_vec_read_float32(v3, i);
596 const float32 c = s390_vec_read_float32(v4, i);
597 float32 ret = float32_muladd(a, b, c, flags, &env->fpu_status);
599 s390_vec_write_float32(&tmp, i, ret);
600 vxc = check_ieee_exc(env, i, false, &vec_exc);
601 if (s || vxc) {
602 break;
605 handle_ieee_exc(env, vxc, vec_exc, retaddr);
606 *v1 = tmp;
609 static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
610 const S390Vector *v4, CPUS390XState *env, bool s, int flags,
611 uintptr_t retaddr)
613 uint8_t vxc, vec_exc = 0;
614 S390Vector tmp = {};
615 int i;
617 for (i = 0; i < 2; i++) {
618 const float64 a = s390_vec_read_float64(v2, i);
619 const float64 b = s390_vec_read_float64(v3, i);
620 const float64 c = s390_vec_read_float64(v4, i);
621 const float64 ret = float64_muladd(a, b, c, flags, &env->fpu_status);
623 s390_vec_write_float64(&tmp, i, ret);
624 vxc = check_ieee_exc(env, i, false, &vec_exc);
625 if (s || vxc) {
626 break;
629 handle_ieee_exc(env, vxc, vec_exc, retaddr);
630 *v1 = tmp;
633 static void vfma128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
634 const S390Vector *v4, CPUS390XState *env, bool s, int flags,
635 uintptr_t retaddr)
637 const float128 a = s390_vec_read_float128(v2);
638 const float128 b = s390_vec_read_float128(v3);
639 const float128 c = s390_vec_read_float128(v4);
640 uint8_t vxc, vec_exc = 0;
641 float128 ret;
643 ret = float128_muladd(a, b, c, flags, &env->fpu_status);
644 vxc = check_ieee_exc(env, 0, false, &vec_exc);
645 handle_ieee_exc(env, vxc, vec_exc, retaddr);
646 s390_vec_write_float128(v1, ret);
649 #define DEF_GVEC_VFMA_B(NAME, FLAGS, BITS) \
650 void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \
651 const void *v4, CPUS390XState *env, \
652 uint32_t desc) \
654 const bool se = extract32(simd_data(desc), 3, 1); \
656 vfma##BITS(v1, v2, v3, v4, env, se, FLAGS, GETPC()); \
659 #define DEF_GVEC_VFMA(NAME, FLAGS) \
660 DEF_GVEC_VFMA_B(NAME, FLAGS, 32) \
661 DEF_GVEC_VFMA_B(NAME, FLAGS, 64) \
662 DEF_GVEC_VFMA_B(NAME, FLAGS, 128)
664 DEF_GVEC_VFMA(vfma, 0)
665 DEF_GVEC_VFMA(vfms, float_muladd_negate_c)
666 DEF_GVEC_VFMA(vfnma, float_muladd_negate_result)
667 DEF_GVEC_VFMA(vfnms, float_muladd_negate_c | float_muladd_negate_result)
669 void HELPER(gvec_vftci32)(void *v1, const void *v2, CPUS390XState *env,
670 uint32_t desc)
672 uint16_t i3 = extract32(simd_data(desc), 4, 12);
673 bool s = extract32(simd_data(desc), 3, 1);
674 int i, match = 0;
676 for (i = 0; i < 4; i++) {
677 float32 a = s390_vec_read_float32(v2, i);
679 if (float32_dcmask(env, a) & i3) {
680 match++;
681 s390_vec_write_element32(v1, i, -1u);
682 } else {
683 s390_vec_write_element32(v1, i, 0);
685 if (s) {
686 break;
690 if (match == 4 || (s && match)) {
691 env->cc_op = 0;
692 } else if (match) {
693 env->cc_op = 1;
694 } else {
695 env->cc_op = 3;
699 void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env,
700 uint32_t desc)
702 const uint16_t i3 = extract32(simd_data(desc), 4, 12);
703 const bool s = extract32(simd_data(desc), 3, 1);
704 int i, match = 0;
706 for (i = 0; i < 2; i++) {
707 const float64 a = s390_vec_read_float64(v2, i);
709 if (float64_dcmask(env, a) & i3) {
710 match++;
711 s390_vec_write_element64(v1, i, -1ull);
712 } else {
713 s390_vec_write_element64(v1, i, 0);
715 if (s) {
716 break;
720 if (match == 2 || (s && match)) {
721 env->cc_op = 0;
722 } else if (match) {
723 env->cc_op = 1;
724 } else {
725 env->cc_op = 3;
729 void HELPER(gvec_vftci128)(void *v1, const void *v2, CPUS390XState *env,
730 uint32_t desc)
732 const float128 a = s390_vec_read_float128(v2);
733 uint16_t i3 = extract32(simd_data(desc), 4, 12);
735 if (float128_dcmask(env, a) & i3) {
736 env->cc_op = 0;
737 s390_vec_write_element64(v1, 0, -1ull);
738 s390_vec_write_element64(v1, 1, -1ull);
739 } else {
740 env->cc_op = 3;
741 s390_vec_write_element64(v1, 0, 0);
742 s390_vec_write_element64(v1, 1, 0);