2 * QEMU TCG support -- s390x vector floating point instruction support
4 * Copyright (C) 2019 Red Hat Inc
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"
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
,
33 uint8_t vece_exc
= 0, trap_exc
;
36 /* Retrieve and clear the softfloat exceptions */
37 qemu_exc
= env
->fpu_status
.float_exception_flags
;
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 */
48 /* Check for traps and construct the VXC */
49 trap_exc
= vece_exc
& env
->fpc
>> 24;
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
;
60 g_assert(trap_exc
& S390_IEEE_MASK_INEXACT
);
61 /* inexact has lowest priority on traps */
62 return enr
<< 4 | VIC_INEXACT
;
68 static void handle_ieee_exc(CPUS390XState
*env
, uint8_t vxc
, uint8_t vec_exc
,
72 /* on traps, the fpc flags are not updated, instruction is suppressed */
73 tcg_s390_vector_exception(env
, vxc
, retaddr
);
76 /* indicate exceptions for all elements combined */
77 env
->fpc
|= vec_exc
<< 16;
81 typedef uint64_t (*vop64_2_fn
)(uint64_t a
, float_status
*s
);
82 static void vop64_2(S390Vector
*v1
, const S390Vector
*v2
, CPUS390XState
*env
,
83 bool s
, bool XxC
, uint8_t erm
, vop64_2_fn fn
,
86 uint8_t vxc
, vec_exc
= 0;
90 old_mode
= s390_swap_bfp_rounding_mode(env
, erm
);
91 for (i
= 0; i
< 2; i
++) {
92 const uint64_t a
= s390_vec_read_element64(v2
, i
);
94 s390_vec_write_element64(&tmp
, i
, fn(a
, &env
->fpu_status
));
95 vxc
= check_ieee_exc(env
, i
, XxC
, &vec_exc
);
100 s390_restore_bfp_rounding_mode(env
, old_mode
);
101 handle_ieee_exc(env
, vxc
, vec_exc
, retaddr
);
105 typedef uint64_t (*vop64_3_fn
)(uint64_t a
, uint64_t b
, float_status
*s
);
106 static void vop64_3(S390Vector
*v1
, const S390Vector
*v2
, const S390Vector
*v3
,
107 CPUS390XState
*env
, bool s
, vop64_3_fn fn
,
110 uint8_t vxc
, vec_exc
= 0;
114 for (i
= 0; i
< 2; i
++) {
115 const uint64_t a
= s390_vec_read_element64(v2
, i
);
116 const uint64_t b
= s390_vec_read_element64(v3
, i
);
118 s390_vec_write_element64(&tmp
, i
, fn(a
, b
, &env
->fpu_status
));
119 vxc
= check_ieee_exc(env
, i
, false, &vec_exc
);
124 handle_ieee_exc(env
, vxc
, vec_exc
, retaddr
);
128 static uint64_t vfa64(uint64_t a
, uint64_t b
, float_status
*s
)
130 return float64_add(a
, b
, s
);
133 void HELPER(gvec_vfa64
)(void *v1
, const void *v2
, const void *v3
,
134 CPUS390XState
*env
, uint32_t desc
)
136 vop64_3(v1
, v2
, v3
, env
, false, vfa64
, GETPC());
139 void HELPER(gvec_vfa64s
)(void *v1
, const void *v2
, const void *v3
,
140 CPUS390XState
*env
, uint32_t desc
)
142 vop64_3(v1
, v2
, v3
, env
, true, vfa64
, GETPC());
145 static int wfc64(const S390Vector
*v1
, const S390Vector
*v2
,
146 CPUS390XState
*env
, bool signal
, uintptr_t retaddr
)
148 /* only the zero-indexed elements are compared */
149 const float64 a
= s390_vec_read_element64(v1
, 0);
150 const float64 b
= s390_vec_read_element64(v2
, 0);
151 uint8_t vxc
, vec_exc
= 0;
155 cmp
= float64_compare(a
, b
, &env
->fpu_status
);
157 cmp
= float64_compare_quiet(a
, b
, &env
->fpu_status
);
159 vxc
= check_ieee_exc(env
, 0, false, &vec_exc
);
160 handle_ieee_exc(env
, vxc
, vec_exc
, retaddr
);
162 return float_comp_to_cc(env
, cmp
);
165 void HELPER(gvec_wfc64
)(const void *v1
, const void *v2
, CPUS390XState
*env
,
168 env
->cc_op
= wfc64(v1
, v2
, env
, false, GETPC());
171 void HELPER(gvec_wfk64
)(const void *v1
, const void *v2
, CPUS390XState
*env
,
174 env
->cc_op
= wfc64(v1
, v2
, env
, true, GETPC());
177 typedef bool (*vfc64_fn
)(float64 a
, float64 b
, float_status
*status
);
178 static int vfc64(S390Vector
*v1
, const S390Vector
*v2
, const S390Vector
*v3
,
179 CPUS390XState
*env
, bool s
, vfc64_fn fn
, uintptr_t retaddr
)
181 uint8_t vxc
, vec_exc
= 0;
186 for (i
= 0; i
< 2; i
++) {
187 const float64 a
= s390_vec_read_element64(v2
, i
);
188 const float64 b
= s390_vec_read_element64(v3
, i
);
190 /* swap the order of the parameters, so we can use existing functions */
191 if (fn(b
, a
, &env
->fpu_status
)) {
193 s390_vec_write_element64(&tmp
, i
, -1ull);
195 vxc
= check_ieee_exc(env
, i
, false, &vec_exc
);
201 handle_ieee_exc(env
, vxc
, vec_exc
, retaddr
);
204 return s
|| match
== 2 ? 0 : 1;
209 void HELPER(gvec_vfce64
)(void *v1
, const void *v2
, const void *v3
,
210 CPUS390XState
*env
, uint32_t desc
)
212 vfc64(v1
, v2
, v3
, env
, false, float64_eq_quiet
, GETPC());
215 void HELPER(gvec_vfce64s
)(void *v1
, const void *v2
, const void *v3
,
216 CPUS390XState
*env
, uint32_t desc
)
218 vfc64(v1
, v2
, v3
, env
, true, float64_eq_quiet
, GETPC());
221 void HELPER(gvec_vfce64_cc
)(void *v1
, const void *v2
, const void *v3
,
222 CPUS390XState
*env
, uint32_t desc
)
224 env
->cc_op
= vfc64(v1
, v2
, v3
, env
, false, float64_eq_quiet
, GETPC());
227 void HELPER(gvec_vfce64s_cc
)(void *v1
, const void *v2
, const void *v3
,
228 CPUS390XState
*env
, uint32_t desc
)
230 env
->cc_op
= vfc64(v1
, v2
, v3
, env
, true, float64_eq_quiet
, GETPC());
233 void HELPER(gvec_vfch64
)(void *v1
, const void *v2
, const void *v3
,
234 CPUS390XState
*env
, uint32_t desc
)
236 vfc64(v1
, v2
, v3
, env
, false, float64_lt_quiet
, GETPC());
239 void HELPER(gvec_vfch64s
)(void *v1
, const void *v2
, const void *v3
,
240 CPUS390XState
*env
, uint32_t desc
)
242 vfc64(v1
, v2
, v3
, env
, true, float64_lt_quiet
, GETPC());
245 void HELPER(gvec_vfch64_cc
)(void *v1
, const void *v2
, const void *v3
,
246 CPUS390XState
*env
, uint32_t desc
)
248 env
->cc_op
= vfc64(v1
, v2
, v3
, env
, false, float64_lt_quiet
, GETPC());
251 void HELPER(gvec_vfch64s_cc
)(void *v1
, const void *v2
, const void *v3
,
252 CPUS390XState
*env
, uint32_t desc
)
254 env
->cc_op
= vfc64(v1
, v2
, v3
, env
, true, float64_lt_quiet
, GETPC());
257 void HELPER(gvec_vfche64
)(void *v1
, const void *v2
, const void *v3
,
258 CPUS390XState
*env
, uint32_t desc
)
260 vfc64(v1
, v2
, v3
, env
, false, float64_le_quiet
, GETPC());
263 void HELPER(gvec_vfche64s
)(void *v1
, const void *v2
, const void *v3
,
264 CPUS390XState
*env
, uint32_t desc
)
266 vfc64(v1
, v2
, v3
, env
, true, float64_le_quiet
, GETPC());
269 void HELPER(gvec_vfche64_cc
)(void *v1
, const void *v2
, const void *v3
,
270 CPUS390XState
*env
, uint32_t desc
)
272 env
->cc_op
= vfc64(v1
, v2
, v3
, env
, false, float64_le_quiet
, GETPC());
275 void HELPER(gvec_vfche64s_cc
)(void *v1
, const void *v2
, const void *v3
,
276 CPUS390XState
*env
, uint32_t desc
)
278 env
->cc_op
= vfc64(v1
, v2
, v3
, env
, true, float64_le_quiet
, GETPC());
281 static uint64_t vcdg64(uint64_t a
, float_status
*s
)
283 return int64_to_float64(a
, s
);
286 void HELPER(gvec_vcdg64
)(void *v1
, const void *v2
, CPUS390XState
*env
,
289 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
290 const bool XxC
= extract32(simd_data(desc
), 2, 1);
292 vop64_2(v1
, v2
, env
, false, XxC
, erm
, vcdg64
, GETPC());
295 void HELPER(gvec_vcdg64s
)(void *v1
, const void *v2
, CPUS390XState
*env
,
298 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
299 const bool XxC
= extract32(simd_data(desc
), 2, 1);
301 vop64_2(v1
, v2
, env
, true, XxC
, erm
, vcdg64
, GETPC());
304 static uint64_t vcdlg64(uint64_t a
, float_status
*s
)
306 return uint64_to_float64(a
, s
);
309 void HELPER(gvec_vcdlg64
)(void *v1
, const void *v2
, CPUS390XState
*env
,
312 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
313 const bool XxC
= extract32(simd_data(desc
), 2, 1);
315 vop64_2(v1
, v2
, env
, false, XxC
, erm
, vcdlg64
, GETPC());
318 void HELPER(gvec_vcdlg64s
)(void *v1
, const void *v2
, CPUS390XState
*env
,
321 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
322 const bool XxC
= extract32(simd_data(desc
), 2, 1);
324 vop64_2(v1
, v2
, env
, true, XxC
, erm
, vcdlg64
, GETPC());
327 static uint64_t vcgd64(uint64_t a
, float_status
*s
)
329 return float64_to_int64(a
, s
);
332 void HELPER(gvec_vcgd64
)(void *v1
, const void *v2
, CPUS390XState
*env
,
335 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
336 const bool XxC
= extract32(simd_data(desc
), 2, 1);
338 vop64_2(v1
, v2
, env
, false, XxC
, erm
, vcgd64
, GETPC());
341 void HELPER(gvec_vcgd64s
)(void *v1
, const void *v2
, CPUS390XState
*env
,
344 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
345 const bool XxC
= extract32(simd_data(desc
), 2, 1);
347 vop64_2(v1
, v2
, env
, true, XxC
, erm
, vcgd64
, GETPC());
350 static uint64_t vclgd64(uint64_t a
, float_status
*s
)
352 return float64_to_uint64(a
, s
);
355 void HELPER(gvec_vclgd64
)(void *v1
, const void *v2
, CPUS390XState
*env
,
358 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
359 const bool XxC
= extract32(simd_data(desc
), 2, 1);
361 vop64_2(v1
, v2
, env
, false, XxC
, erm
, vclgd64
, GETPC());
364 void HELPER(gvec_vclgd64s
)(void *v1
, const void *v2
, CPUS390XState
*env
,
367 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
368 const bool XxC
= extract32(simd_data(desc
), 2, 1);
370 vop64_2(v1
, v2
, env
, true, XxC
, erm
, vclgd64
, GETPC());
373 static uint64_t vfd64(uint64_t a
, uint64_t b
, float_status
*s
)
375 return float64_div(a
, b
, s
);
378 void HELPER(gvec_vfd64
)(void *v1
, const void *v2
, const void *v3
,
379 CPUS390XState
*env
, uint32_t desc
)
381 vop64_3(v1
, v2
, v3
, env
, false, vfd64
, GETPC());
384 void HELPER(gvec_vfd64s
)(void *v1
, const void *v2
, const void *v3
,
385 CPUS390XState
*env
, uint32_t desc
)
387 vop64_3(v1
, v2
, v3
, env
, true, vfd64
, GETPC());
390 static uint64_t vfi64(uint64_t a
, float_status
*s
)
392 return float64_round_to_int(a
, s
);
395 void HELPER(gvec_vfi64
)(void *v1
, const void *v2
, CPUS390XState
*env
,
398 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
399 const bool XxC
= extract32(simd_data(desc
), 2, 1);
401 vop64_2(v1
, v2
, env
, false, XxC
, erm
, vfi64
, GETPC());
404 void HELPER(gvec_vfi64s
)(void *v1
, const void *v2
, CPUS390XState
*env
,
407 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
408 const bool XxC
= extract32(simd_data(desc
), 2, 1);
410 vop64_2(v1
, v2
, env
, true, XxC
, erm
, vfi64
, GETPC());
413 static void vfll32(S390Vector
*v1
, const S390Vector
*v2
, CPUS390XState
*env
,
414 bool s
, uintptr_t retaddr
)
416 uint8_t vxc
, vec_exc
= 0;
420 for (i
= 0; i
< 2; i
++) {
421 /* load from even element */
422 const float32 a
= s390_vec_read_element32(v2
, i
* 2);
423 const uint64_t ret
= float32_to_float64(a
, &env
->fpu_status
);
425 s390_vec_write_element64(&tmp
, i
, ret
);
426 /* indicate the source element */
427 vxc
= check_ieee_exc(env
, i
* 2, false, &vec_exc
);
432 handle_ieee_exc(env
, vxc
, vec_exc
, retaddr
);
436 void HELPER(gvec_vfll32
)(void *v1
, const void *v2
, CPUS390XState
*env
,
439 vfll32(v1
, v2
, env
, false, GETPC());
442 void HELPER(gvec_vfll32s
)(void *v1
, const void *v2
, CPUS390XState
*env
,
445 vfll32(v1
, v2
, env
, true, GETPC());
448 static void vflr64(S390Vector
*v1
, const S390Vector
*v2
, CPUS390XState
*env
,
449 bool s
, bool XxC
, uint8_t erm
, uintptr_t retaddr
)
451 uint8_t vxc
, vec_exc
= 0;
455 old_mode
= s390_swap_bfp_rounding_mode(env
, erm
);
456 for (i
= 0; i
< 2; i
++) {
457 float64 a
= s390_vec_read_element64(v2
, i
);
458 uint32_t ret
= float64_to_float32(a
, &env
->fpu_status
);
460 /* place at even element */
461 s390_vec_write_element32(&tmp
, i
* 2, ret
);
462 /* indicate the source element */
463 vxc
= check_ieee_exc(env
, i
, XxC
, &vec_exc
);
468 s390_restore_bfp_rounding_mode(env
, old_mode
);
469 handle_ieee_exc(env
, vxc
, vec_exc
, retaddr
);
473 void HELPER(gvec_vflr64
)(void *v1
, const void *v2
, CPUS390XState
*env
,
476 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
477 const bool XxC
= extract32(simd_data(desc
), 2, 1);
479 vflr64(v1
, v2
, env
, false, XxC
, erm
, GETPC());
482 void HELPER(gvec_vflr64s
)(void *v1
, const void *v2
, CPUS390XState
*env
,
485 const uint8_t erm
= extract32(simd_data(desc
), 4, 4);
486 const bool XxC
= extract32(simd_data(desc
), 2, 1);
488 vflr64(v1
, v2
, env
, true, XxC
, erm
, GETPC());
491 static uint64_t vfm64(uint64_t a
, uint64_t b
, float_status
*s
)
493 return float64_mul(a
, b
, s
);
496 void HELPER(gvec_vfm64
)(void *v1
, const void *v2
, const void *v3
,
497 CPUS390XState
*env
, uint32_t desc
)
499 vop64_3(v1
, v2
, v3
, env
, false, vfm64
, GETPC());
502 void HELPER(gvec_vfm64s
)(void *v1
, const void *v2
, const void *v3
,
503 CPUS390XState
*env
, uint32_t desc
)
505 vop64_3(v1
, v2
, v3
, env
, true, vfm64
, GETPC());
508 static void vfma64(S390Vector
*v1
, const S390Vector
*v2
, const S390Vector
*v3
,
509 const S390Vector
*v4
, CPUS390XState
*env
, bool s
, int flags
,
512 uint8_t vxc
, vec_exc
= 0;
516 for (i
= 0; i
< 2; i
++) {
517 const uint64_t a
= s390_vec_read_element64(v2
, i
);
518 const uint64_t b
= s390_vec_read_element64(v3
, i
);
519 const uint64_t c
= s390_vec_read_element64(v4
, i
);
520 uint64_t ret
= float64_muladd(a
, b
, c
, flags
, &env
->fpu_status
);
522 s390_vec_write_element64(&tmp
, i
, ret
);
523 vxc
= check_ieee_exc(env
, i
, false, &vec_exc
);
528 handle_ieee_exc(env
, vxc
, vec_exc
, retaddr
);
532 void HELPER(gvec_vfma64
)(void *v1
, const void *v2
, const void *v3
,
533 const void *v4
, CPUS390XState
*env
, uint32_t desc
)
535 vfma64(v1
, v2
, v3
, v4
, env
, false, 0, GETPC());
538 void HELPER(gvec_vfma64s
)(void *v1
, const void *v2
, const void *v3
,
539 const void *v4
, CPUS390XState
*env
, uint32_t desc
)
541 vfma64(v1
, v2
, v3
, v4
, env
, true, 0, GETPC());
544 void HELPER(gvec_vfms64
)(void *v1
, const void *v2
, const void *v3
,
545 const void *v4
, CPUS390XState
*env
, uint32_t desc
)
547 vfma64(v1
, v2
, v3
, v4
, env
, false, float_muladd_negate_c
, GETPC());
550 void HELPER(gvec_vfms64s
)(void *v1
, const void *v2
, const void *v3
,
551 const void *v4
, CPUS390XState
*env
, uint32_t desc
)
553 vfma64(v1
, v2
, v3
, v4
, env
, true, float_muladd_negate_c
, GETPC());
556 static uint64_t vfsq64(uint64_t a
, float_status
*s
)
558 return float64_sqrt(a
, s
);
561 void HELPER(gvec_vfsq64
)(void *v1
, const void *v2
, CPUS390XState
*env
,
564 vop64_2(v1
, v2
, env
, false, false, 0, vfsq64
, GETPC());
567 void HELPER(gvec_vfsq64s
)(void *v1
, const void *v2
, CPUS390XState
*env
,
570 vop64_2(v1
, v2
, env
, true, false, 0, vfsq64
, GETPC());
573 static uint64_t vfs64(uint64_t a
, uint64_t b
, float_status
*s
)
575 return float64_sub(a
, b
, s
);
578 void HELPER(gvec_vfs64
)(void *v1
, const void *v2
, const void *v3
,
579 CPUS390XState
*env
, uint32_t desc
)
581 vop64_3(v1
, v2
, v3
, env
, false, vfs64
, GETPC());
584 void HELPER(gvec_vfs64s
)(void *v1
, const void *v2
, const void *v3
,
585 CPUS390XState
*env
, uint32_t desc
)
587 vop64_3(v1
, v2
, v3
, env
, true, vfs64
, GETPC());
590 static int vftci64(S390Vector
*v1
, const S390Vector
*v2
, CPUS390XState
*env
,
595 for (i
= 0; i
< 2; i
++) {
596 float64 a
= s390_vec_read_element64(v2
, i
);
598 if (float64_dcmask(env
, a
) & i3
) {
600 s390_vec_write_element64(v1
, i
, -1ull);
602 s390_vec_write_element64(v1
, i
, 0);
610 return s
|| match
== 2 ? 0 : 1;
615 void HELPER(gvec_vftci64
)(void *v1
, const void *v2
, CPUS390XState
*env
,
618 env
->cc_op
= vftci64(v1
, v2
, env
, false, simd_data(desc
));
621 void HELPER(gvec_vftci64s
)(void *v1
, const void *v2
, CPUS390XState
*env
,
624 env
->cc_op
= vftci64(v1
, v2
, env
, true, simd_data(desc
));