From 3fb3b122ac061859c20cdb14567313f137dbc152 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 2 Jun 2021 14:50:50 +0200 Subject: s390x/kvm: remove unused gs handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With commit 0280b3eb7c05 ("s390x/kvm: use cpu model for gscb on compat machines"), we removed any calls to kvm_s390_get_gs() in favour of a different mechanism. Let's remove the unused kvm_s390_get_gs(), and with it the now unneeded cap_gs as well. Signed-off-by: Cornelia Huck Reviewed-by: Christian Borntraeger Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20210602125050.492500-1-cohuck@redhat.com> --- target/s390x/kvm-stub.c | 5 ----- target/s390x/kvm.c | 10 +--------- target/s390x/kvm_s390x.h | 1 - 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c index 9970b5a..8a308cf 100644 --- a/target/s390x/kvm-stub.c +++ b/target/s390x/kvm-stub.c @@ -49,11 +49,6 @@ int kvm_s390_get_ri(void) return 0; } -int kvm_s390_get_gs(void) -{ - return 0; -} - int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low) { return -ENOSYS; diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 4fb3bbf..2388924 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -154,7 +154,6 @@ static int cap_async_pf; static int cap_mem_op; static int cap_s390_irq; static int cap_ri; -static int cap_gs; static int cap_hpage_1m; static int cap_vcpu_resets; static int cap_protected; @@ -369,9 +368,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } if (cpu_model_allowed()) { - if (kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0) == 0) { - cap_gs = 1; - } + kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0); } /* @@ -2039,11 +2036,6 @@ int kvm_s390_get_ri(void) return cap_ri; } -int kvm_s390_get_gs(void) -{ - return cap_gs; -} - int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state) { struct kvm_mp_state mp_state = {}; diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h index 25bbe98..05a5e1e 100644 --- a/target/s390x/kvm_s390x.h +++ b/target/s390x/kvm_s390x.h @@ -27,7 +27,6 @@ void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); int kvm_s390_get_hpage_1m(void); int kvm_s390_get_ri(void); -int kvm_s390_get_gs(void); int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock); int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock); int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock); -- cgit v1.1 From 0a3be7be73e594388ae2a91017b7ffafab15a7d9 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:12 +0200 Subject: s390x/tcg: Fix FP CONVERT TO (LOGICAL) FIXED NaN handling In case we encounter a NaN, we have to return the smallest possible number, corresponding to either 0 or the maximum negative number. This seems to differ from IEEE handling as implemented in softfloat, whereby we return the biggest possible number. While at it, use float32_to_uint64() in the CLGEB handler. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-2-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/fpu_helper.c | 41 +++++++++++++++++++++++++++++++++++++---- target/s390x/vec_fpu_helper.c | 8 ++++++-- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/target/s390x/fpu_helper.c b/target/s390x/fpu_helper.c index f155bc0..13af158 100644 --- a/target/s390x/fpu_helper.c +++ b/target/s390x/fpu_helper.c @@ -509,6 +509,9 @@ uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float32_is_any_nan(v2)) { + return INT64_MIN; + } return ret; } @@ -520,6 +523,9 @@ uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float64_is_any_nan(v2)) { + return INT64_MIN; + } return ret; } @@ -532,6 +538,9 @@ uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float128_is_any_nan(v2)) { + return INT64_MIN; + } return ret; } @@ -543,6 +552,9 @@ uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float32_is_any_nan(v2)) { + return INT32_MIN; + } return ret; } @@ -554,6 +566,9 @@ uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float64_is_any_nan(v2)) { + return INT32_MIN; + } return ret; } @@ -566,6 +581,9 @@ uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float128_is_any_nan(v2)) { + return INT32_MIN; + } return ret; } @@ -573,12 +591,12 @@ uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); - uint64_t ret; - - v2 = float32_to_float64(v2, &env->fpu_status); - ret = float64_to_uint64(v2, &env->fpu_status); + uint64_t ret = float32_to_uint64(v2, &env->fpu_status); s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float32_is_any_nan(v2)) { + return 0; + } return ret; } @@ -590,6 +608,9 @@ uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float64_is_any_nan(v2)) { + return 0; + } return ret; } @@ -601,6 +622,9 @@ uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float128_is_any_nan(make_float128(h, l))) { + return 0; + } return ret; } @@ -612,6 +636,9 @@ uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float32_is_any_nan(v2)) { + return 0; + } return ret; } @@ -623,6 +650,9 @@ uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float64_is_any_nan(v2)) { + return 0; + } return ret; } @@ -634,6 +664,9 @@ uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); + if (float128_is_any_nan(make_float128(h, l))) { + return 0; + } return ret; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index c1564e8..5676591 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -326,7 +326,9 @@ void HELPER(gvec_vcdlg64s)(void *v1, const void *v2, CPUS390XState *env, static uint64_t vcgd64(uint64_t a, float_status *s) { - return float64_to_int64(a, s); + const uint64_t tmp = float64_to_int64(a, s); + + return float64_is_any_nan(a) ? INT64_MIN : tmp; } void HELPER(gvec_vcgd64)(void *v1, const void *v2, CPUS390XState *env, @@ -349,7 +351,9 @@ void HELPER(gvec_vcgd64s)(void *v1, const void *v2, CPUS390XState *env, static uint64_t vclgd64(uint64_t a, float_status *s) { - return float64_to_uint64(a, s); + const uint64_t tmp = float64_to_uint64(a, s); + + return float64_is_any_nan(a) ? 0 : tmp; } void HELPER(gvec_vclgd64)(void *v1, const void *v2, CPUS390XState *env, -- cgit v1.1 From 0bd3c286562e363fd5725209c0b475af9b8465d1 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:13 +0200 Subject: s390x/tcg: Fix instruction name for VECTOR FP LOAD (LENGTHENED|ROUNDED) Let's use the correct name. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-3-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/insn-data.def | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 0bb1886..35a0086 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1245,9 +1245,9 @@ F(0xe7e5, VFD, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) /* VECTOR LOAD FP INTEGER */ F(0xe7c7, VFI, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) -/* VECTOR LOAD LENGTHENED */ +/* VECTOR FP LOAD LENGTHENED */ F(0xe7c4, VFLL, VRR_a, V, 0, 0, 0, 0, vfll, 0, IF_VEC) -/* VECTOR LOAD ROUNDED */ +/* VECTOR FP LOAD ROUNDED */ F(0xe7c5, VFLR, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) /* VECTOR FP MULTIPLY */ F(0xe7e7, VFM, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) -- cgit v1.1 From 863b9507a61bb4f5707de0dadca829945c149e6e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:14 +0200 Subject: s390x/tcg: Simplify vop64_3() handling Let's simplify, reworking our handler generation, passing the whole "m5" register content and not providing specialized handlers for "se", and reading/writing proper float64 values using new helpers. Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-4-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 4 -- target/s390x/translate_vx.c.inc | 11 +++-- target/s390x/vec_fpu_helper.c | 94 +++++++++++------------------------------ 3 files changed, 30 insertions(+), 79 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index d4e4f33..2344f81 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -247,7 +247,6 @@ DEF_HELPER_6(gvec_vstrc_cc_rt32, void, ptr, cptr, cptr, cptr, env, i32) /* === Vector Floating-Point Instructions */ DEF_HELPER_FLAGS_5(gvec_vfa64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_vfa64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfc64, void, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfk64, void, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfce64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) @@ -271,7 +270,6 @@ DEF_HELPER_FLAGS_4(gvec_vcgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vclgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vclgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfd64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_vfd64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfi64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) @@ -279,7 +277,6 @@ DEF_HELPER_FLAGS_4(gvec_vfll32s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_vfm64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) @@ -287,7 +284,6 @@ DEF_HELPER_FLAGS_6(gvec_vfms64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, en DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_vfs64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_4(gvec_vftci64, void, ptr, cptr, env, i32) DEF_HELPER_4(gvec_vftci64s, void, ptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index eb767f5..2d3fbdf 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2443,7 +2443,6 @@ static DisasJumpType op_vfa(DisasContext *s, DisasOps *o) { const uint8_t fpf = get_field(s, m4); const uint8_t m5 = get_field(s, m5); - const bool se = extract32(m5, 3, 1); gen_helper_gvec_3_ptr *fn; if (fpf != FPF_LONG || extract32(m5, 0, 3)) { @@ -2453,22 +2452,22 @@ static DisasJumpType op_vfa(DisasContext *s, DisasOps *o) switch (s->fields.op2) { case 0xe3: - fn = se ? gen_helper_gvec_vfa64s : gen_helper_gvec_vfa64; + fn = gen_helper_gvec_vfa64; break; case 0xe5: - fn = se ? gen_helper_gvec_vfd64s : gen_helper_gvec_vfd64; + fn = gen_helper_gvec_vfd64; break; case 0xe7: - fn = se ? gen_helper_gvec_vfm64s : gen_helper_gvec_vfm64; + fn = gen_helper_gvec_vfm64; break; case 0xe2: - fn = se ? gen_helper_gvec_vfs64s : gen_helper_gvec_vfs64; + fn = gen_helper_gvec_vfs64; break; default: g_assert_not_reached(); } gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), - get_field(s, v3), cpu_env, 0, fn); + get_field(s, v3), cpu_env, m5, fn); return DISAS_NEXT; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 5676591..280ee0f 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -78,6 +78,16 @@ static void handle_ieee_exc(CPUS390XState *env, uint8_t vxc, uint8_t vec_exc, } } +static float64 s390_vec_read_float64(const S390Vector *v, uint8_t enr) +{ + return make_float64(s390_vec_read_element64(v, enr)); +} + +static void s390_vec_write_float64(S390Vector *v, uint8_t enr, float64 data) +{ + return s390_vec_write_element64(v, enr, data); +} + typedef uint64_t (*vop64_2_fn)(uint64_t a, float_status *s); static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool s, bool XxC, uint8_t erm, vop64_2_fn fn, @@ -102,7 +112,7 @@ static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, *v1 = tmp; } -typedef uint64_t (*vop64_3_fn)(uint64_t a, uint64_t b, float_status *s); +typedef float64 (*vop64_3_fn)(float64 a, float64 b, float_status *s); static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, CPUS390XState *env, bool s, vop64_3_fn fn, uintptr_t retaddr) @@ -112,10 +122,10 @@ static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, int i; for (i = 0; i < 2; i++) { - const uint64_t a = s390_vec_read_element64(v2, i); - const uint64_t b = s390_vec_read_element64(v3, i); + const float64 a = s390_vec_read_float64(v2, i); + const float64 b = s390_vec_read_float64(v3, i); - s390_vec_write_element64(&tmp, i, fn(a, b, &env->fpu_status)); + s390_vec_write_float64(&tmp, i, fn(a, b, &env->fpu_status)); vxc = check_ieee_exc(env, i, false, &vec_exc); if (s || vxc) { break; @@ -125,22 +135,19 @@ static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, *v1 = tmp; } -static uint64_t vfa64(uint64_t a, uint64_t b, float_status *s) -{ - return float64_add(a, b, s); +#define DEF_GVEC_VOP3(NAME, OP) \ +void HELPER(gvec_##NAME##64)(void *v1, const void *v2, const void *v3, \ + CPUS390XState *env, uint32_t desc) \ +{ \ + const bool se = extract32(simd_data(desc), 3, 1); \ + \ + vop64_3(v1, v2, v3, env, se, float64_##OP, GETPC()); \ } -void HELPER(gvec_vfa64)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vop64_3(v1, v2, v3, env, false, vfa64, GETPC()); -} - -void HELPER(gvec_vfa64s)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vop64_3(v1, v2, v3, env, true, vfa64, GETPC()); -} +DEF_GVEC_VOP3(vfa, add) +DEF_GVEC_VOP3(vfs, sub) +DEF_GVEC_VOP3(vfd, div) +DEF_GVEC_VOP3(vfm, mul) static int wfc64(const S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool signal, uintptr_t retaddr) @@ -374,23 +381,6 @@ void HELPER(gvec_vclgd64s)(void *v1, const void *v2, CPUS390XState *env, vop64_2(v1, v2, env, true, XxC, erm, vclgd64, GETPC()); } -static uint64_t vfd64(uint64_t a, uint64_t b, float_status *s) -{ - return float64_div(a, b, s); -} - -void HELPER(gvec_vfd64)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vop64_3(v1, v2, v3, env, false, vfd64, GETPC()); -} - -void HELPER(gvec_vfd64s)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vop64_3(v1, v2, v3, env, true, vfd64, GETPC()); -} - static uint64_t vfi64(uint64_t a, float_status *s) { return float64_round_to_int(a, s); @@ -492,23 +482,6 @@ void HELPER(gvec_vflr64s)(void *v1, const void *v2, CPUS390XState *env, vflr64(v1, v2, env, true, XxC, erm, GETPC()); } -static uint64_t vfm64(uint64_t a, uint64_t b, float_status *s) -{ - return float64_mul(a, b, s); -} - -void HELPER(gvec_vfm64)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vop64_3(v1, v2, v3, env, false, vfm64, GETPC()); -} - -void HELPER(gvec_vfm64s)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vop64_3(v1, v2, v3, env, true, vfm64, GETPC()); -} - static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, const S390Vector *v4, CPUS390XState *env, bool s, int flags, uintptr_t retaddr) @@ -574,23 +547,6 @@ void HELPER(gvec_vfsq64s)(void *v1, const void *v2, CPUS390XState *env, vop64_2(v1, v2, env, true, false, 0, vfsq64, GETPC()); } -static uint64_t vfs64(uint64_t a, uint64_t b, float_status *s) -{ - return float64_sub(a, b, s); -} - -void HELPER(gvec_vfs64)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vop64_3(v1, v2, v3, env, false, vfs64, GETPC()); -} - -void HELPER(gvec_vfs64s)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vop64_3(v1, v2, v3, env, true, vfs64, GETPC()); -} - static int vftci64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool s, uint16_t i3) { -- cgit v1.1 From 21bd6ea2b3b0f8c55eb31199bbb3de0eb8827b8e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:15 +0200 Subject: s390x/tcg: Simplify vop64_2() handling Let's rework our macros and simplify. We still need helper functions in most cases due to the different parameters types. Next, we'll only have 32/128bit variants for vfi and vfsq, so special case the others. Note that for vfsq, the XxC and erm passed in the simd_data() will never be set, resulting in the same behavior. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-5-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 6 -- target/s390x/translate_vx.c.inc | 18 ++-- target/s390x/vec_fpu_helper.c | 190 +++++++++++----------------------------- 3 files changed, 58 insertions(+), 156 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 2344f81..4788c1d 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -262,16 +262,11 @@ DEF_HELPER_FLAGS_5(gvec_vfche64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i3 DEF_HELPER_5(gvec_vfche64_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_5(gvec_vfche64s_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcdg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) -DEF_HELPER_FLAGS_4(gvec_vcdg64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcdlg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) -DEF_HELPER_FLAGS_4(gvec_vcdlg64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) -DEF_HELPER_FLAGS_4(gvec_vcgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vclgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) -DEF_HELPER_FLAGS_4(gvec_vclgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfd64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) -DEF_HELPER_FLAGS_4(gvec_vfi64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll32s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) @@ -282,7 +277,6 @@ DEF_HELPER_FLAGS_6(gvec_vfma64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, en DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfms64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) -DEF_HELPER_FLAGS_4(gvec_vfsq64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_4(gvec_vftci64, void, ptr, cptr, env, i32) DEF_HELPER_4(gvec_vftci64s, void, ptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 2d3fbdf..280d45b 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2558,19 +2558,19 @@ static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o) switch (s->fields.op2) { case 0xc3: - fn = se ? gen_helper_gvec_vcdg64s : gen_helper_gvec_vcdg64; + fn = gen_helper_gvec_vcdg64; break; case 0xc1: - fn = se ? gen_helper_gvec_vcdlg64s : gen_helper_gvec_vcdlg64; + fn = gen_helper_gvec_vcdlg64; break; case 0xc2: - fn = se ? gen_helper_gvec_vcgd64s : gen_helper_gvec_vcgd64; + fn = gen_helper_gvec_vcgd64; break; case 0xc0: - fn = se ? gen_helper_gvec_vclgd64s : gen_helper_gvec_vclgd64; + fn = gen_helper_gvec_vclgd64; break; case 0xc7: - fn = se ? gen_helper_gvec_vfi64s : gen_helper_gvec_vfi64; + fn = gen_helper_gvec_vfi64; break; case 0xc5: fn = se ? gen_helper_gvec_vflr64s : gen_helper_gvec_vflr64; @@ -2681,18 +2681,14 @@ static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o) { const uint8_t fpf = get_field(s, m3); const uint8_t m4 = get_field(s, m4); - gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vfsq64; if (fpf != FPF_LONG || extract32(m4, 0, 3)) { gen_program_exception(s, PGM_SPECIFICATION); return DISAS_NORETURN; } - if (extract32(m4, 3, 1)) { - fn = gen_helper_gvec_vfsq64s; - } - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, - 0, fn); + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, + gen_helper_gvec_vfsq64); return DISAS_NEXT; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 280ee0f..ab23a59 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -88,7 +88,7 @@ static void s390_vec_write_float64(S390Vector *v, uint8_t enr, float64 data) return s390_vec_write_element64(v, enr, data); } -typedef uint64_t (*vop64_2_fn)(uint64_t a, float_status *s); +typedef float64 (*vop64_2_fn)(float64 a, float_status *s); static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool s, bool XxC, uint8_t erm, vop64_2_fn fn, uintptr_t retaddr) @@ -99,9 +99,9 @@ static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, old_mode = s390_swap_bfp_rounding_mode(env, erm); for (i = 0; i < 2; i++) { - const uint64_t a = s390_vec_read_element64(v2, i); + const float64 a = s390_vec_read_float64(v2, i); - s390_vec_write_element64(&tmp, i, fn(a, &env->fpu_status)); + s390_vec_write_float64(&tmp, i, fn(a, &env->fpu_status)); vxc = check_ieee_exc(env, i, XxC, &vec_exc); if (s || vxc) { break; @@ -112,6 +112,54 @@ static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, *v1 = tmp; } +static float64 vcdg64(float64 a, float_status *s) +{ + return int64_to_float64(a, s); +} + +static float64 vcdlg64(float64 a, float_status *s) +{ + return uint64_to_float64(a, s); +} + +static float64 vcgd64(float64 a, float_status *s) +{ + const float64 tmp = float64_to_int64(a, s); + + return float64_is_any_nan(a) ? INT64_MIN : tmp; +} + +static float64 vclgd64(float64 a, float_status *s) +{ + const float64 tmp = float64_to_uint64(a, s); + + return float64_is_any_nan(a) ? 0 : tmp; +} + +#define DEF_GVEC_VOP2_FN(NAME, FN, BITS) \ +void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, CPUS390XState *env, \ + uint32_t desc) \ +{ \ + const uint8_t erm = extract32(simd_data(desc), 4, 4); \ + const bool se = extract32(simd_data(desc), 3, 1); \ + const bool XxC = extract32(simd_data(desc), 2, 1); \ + \ + vop##BITS##_2(v1, v2, env, se, XxC, erm, FN, GETPC()); \ +} + +#define DEF_GVEC_VOP2_64(NAME) \ +DEF_GVEC_VOP2_FN(NAME, NAME##64, 64) + +#define DEF_GVEC_VOP2(NAME, OP) \ +DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64) + +DEF_GVEC_VOP2_64(vcdg) +DEF_GVEC_VOP2_64(vcdlg) +DEF_GVEC_VOP2_64(vcgd) +DEF_GVEC_VOP2_64(vclgd) +DEF_GVEC_VOP2(vfi, round_to_int) +DEF_GVEC_VOP2(vfsq, sqrt) + typedef float64 (*vop64_3_fn)(float64 a, float64 b, float_status *s); static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, CPUS390XState *env, bool s, vop64_3_fn fn, @@ -285,125 +333,6 @@ void HELPER(gvec_vfche64s_cc)(void *v1, const void *v2, const void *v3, env->cc_op = vfc64(v1, v2, v3, env, true, float64_le_quiet, GETPC()); } -static uint64_t vcdg64(uint64_t a, float_status *s) -{ - return int64_to_float64(a, s); -} - -void HELPER(gvec_vcdg64)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, false, XxC, erm, vcdg64, GETPC()); -} - -void HELPER(gvec_vcdg64s)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, true, XxC, erm, vcdg64, GETPC()); -} - -static uint64_t vcdlg64(uint64_t a, float_status *s) -{ - return uint64_to_float64(a, s); -} - -void HELPER(gvec_vcdlg64)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, false, XxC, erm, vcdlg64, GETPC()); -} - -void HELPER(gvec_vcdlg64s)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, true, XxC, erm, vcdlg64, GETPC()); -} - -static uint64_t vcgd64(uint64_t a, float_status *s) -{ - const uint64_t tmp = float64_to_int64(a, s); - - return float64_is_any_nan(a) ? INT64_MIN : tmp; -} - -void HELPER(gvec_vcgd64)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, false, XxC, erm, vcgd64, GETPC()); -} - -void HELPER(gvec_vcgd64s)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, true, XxC, erm, vcgd64, GETPC()); -} - -static uint64_t vclgd64(uint64_t a, float_status *s) -{ - const uint64_t tmp = float64_to_uint64(a, s); - - return float64_is_any_nan(a) ? 0 : tmp; -} - -void HELPER(gvec_vclgd64)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, false, XxC, erm, vclgd64, GETPC()); -} - -void HELPER(gvec_vclgd64s)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, true, XxC, erm, vclgd64, GETPC()); -} - -static uint64_t vfi64(uint64_t a, float_status *s) -{ - return float64_round_to_int(a, s); -} - -void HELPER(gvec_vfi64)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, false, XxC, erm, vfi64, GETPC()); -} - -void HELPER(gvec_vfi64s)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vop64_2(v1, v2, env, true, XxC, erm, vfi64, GETPC()); -} - static void vfll32(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool s, uintptr_t retaddr) { @@ -530,23 +459,6 @@ void HELPER(gvec_vfms64s)(void *v1, const void *v2, const void *v3, vfma64(v1, v2, v3, v4, env, true, float_muladd_negate_c, GETPC()); } -static uint64_t vfsq64(uint64_t a, float_status *s) -{ - return float64_sqrt(a, s); -} - -void HELPER(gvec_vfsq64)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - vop64_2(v1, v2, env, false, false, 0, vfsq64, GETPC()); -} - -void HELPER(gvec_vfsq64s)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - vop64_2(v1, v2, env, true, false, 0, vfsq64, GETPC()); -} - static int vftci64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool s, uint16_t i3) { -- cgit v1.1 From 64deb65afe028c85fb413285046c2e81a8d25b4f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:16 +0200 Subject: s390x/tcg: Simplify vfc64() handling Pass the m5 field via simd_data() and don't provide specialized handlers for single-element variants. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-6-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 6 --- target/s390x/translate_vx.c.inc | 45 ++++++-------------- target/s390x/vec_fpu_helper.c | 94 +++++++++++------------------------------ 3 files changed, 38 insertions(+), 107 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 4788c1d..02a1692 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -250,17 +250,11 @@ DEF_HELPER_FLAGS_5(gvec_vfa64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfc64, void, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfk64, void, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfce64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_vfce64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_5(gvec_vfce64_cc, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_5(gvec_vfce64s_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfch64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_vfch64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_5(gvec_vfch64_cc, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_5(gvec_vfch64s_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfche64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_vfche64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_5(gvec_vfche64_cc, void, ptr, cptr, cptr, env, i32) -DEF_HELPER_5(gvec_vfche64s_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcdg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcdlg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 280d45b..604ae11 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2497,7 +2497,6 @@ static DisasJumpType op_vfc(DisasContext *s, DisasOps *o) const uint8_t fpf = get_field(s, m4); const uint8_t m5 = get_field(s, m5); const uint8_t m6 = get_field(s, m6); - const bool se = extract32(m5, 3, 1); const bool cs = extract32(m6, 0, 1); gen_helper_gvec_3_ptr *fn; @@ -2506,37 +2505,21 @@ static DisasJumpType op_vfc(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } - if (cs) { - switch (s->fields.op2) { - case 0xe8: - fn = se ? gen_helper_gvec_vfce64s_cc : gen_helper_gvec_vfce64_cc; - break; - case 0xeb: - fn = se ? gen_helper_gvec_vfch64s_cc : gen_helper_gvec_vfch64_cc; - break; - case 0xea: - fn = se ? gen_helper_gvec_vfche64s_cc : gen_helper_gvec_vfche64_cc; - break; - default: - g_assert_not_reached(); - } - } else { - switch (s->fields.op2) { - case 0xe8: - fn = se ? gen_helper_gvec_vfce64s : gen_helper_gvec_vfce64; - break; - case 0xeb: - fn = se ? gen_helper_gvec_vfch64s : gen_helper_gvec_vfch64; - break; - case 0xea: - fn = se ? gen_helper_gvec_vfche64s : gen_helper_gvec_vfche64; - break; - default: - g_assert_not_reached(); - } + switch (s->fields.op2) { + case 0xe8: + fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64; + break; + case 0xeb: + fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64; + break; + case 0xea: + fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64; + break; + default: + g_assert_not_reached(); } - gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), - get_field(s, v3), cpu_env, 0, fn); + gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), + cpu_env, m5, fn); if (cs) { set_cc_static(s); } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index ab23a59..01ee41d 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -239,8 +239,8 @@ static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, int i; for (i = 0; i < 2; i++) { - const float64 a = s390_vec_read_element64(v2, i); - const float64 b = s390_vec_read_element64(v3, i); + const float64 a = s390_vec_read_float64(v2, i); + const float64 b = s390_vec_read_float64(v3, i); /* swap the order of the parameters, so we can use existing functions */ if (fn(b, a, &env->fpu_status)) { @@ -261,77 +261,31 @@ static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, return 3; } -void HELPER(gvec_vfce64)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vfc64(v1, v2, v3, env, false, float64_eq_quiet, GETPC()); -} - -void HELPER(gvec_vfce64s)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vfc64(v1, v2, v3, env, true, float64_eq_quiet, GETPC()); -} - -void HELPER(gvec_vfce64_cc)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - env->cc_op = vfc64(v1, v2, v3, env, false, float64_eq_quiet, GETPC()); -} - -void HELPER(gvec_vfce64s_cc)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - env->cc_op = vfc64(v1, v2, v3, env, true, float64_eq_quiet, GETPC()); -} - -void HELPER(gvec_vfch64)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vfc64(v1, v2, v3, env, false, float64_lt_quiet, GETPC()); -} - -void HELPER(gvec_vfch64s)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vfc64(v1, v2, v3, env, true, float64_lt_quiet, GETPC()); -} - -void HELPER(gvec_vfch64_cc)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - env->cc_op = vfc64(v1, v2, v3, env, false, float64_lt_quiet, GETPC()); -} - -void HELPER(gvec_vfch64s_cc)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - env->cc_op = vfc64(v1, v2, v3, env, true, float64_lt_quiet, GETPC()); -} - -void HELPER(gvec_vfche64)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vfc64(v1, v2, v3, env, false, float64_le_quiet, GETPC()); -} - -void HELPER(gvec_vfche64s)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - vfc64(v1, v2, v3, env, true, float64_le_quiet, GETPC()); +#define DEF_GVEC_VFC_B(NAME, OP, BITS) \ +void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ + CPUS390XState *env, uint32_t desc) \ +{ \ + const bool se = extract32(simd_data(desc), 3, 1); \ + vfc##BITS##_fn fn = float##BITS##_##OP##_quiet; \ + \ + vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ +} \ + \ +void HELPER(gvec_##NAME##BITS##_cc)(void *v1, const void *v2, const void *v3, \ + CPUS390XState *env, uint32_t desc) \ +{ \ + const bool se = extract32(simd_data(desc), 3, 1); \ + vfc##BITS##_fn fn = float##BITS##_##OP##_quiet; \ + \ + env->cc_op = vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ } -void HELPER(gvec_vfche64_cc)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - env->cc_op = vfc64(v1, v2, v3, env, false, float64_le_quiet, GETPC()); -} +#define DEF_GVEC_VFC(NAME, OP) \ +DEF_GVEC_VFC_B(NAME, OP, 64) -void HELPER(gvec_vfche64s_cc)(void *v1, const void *v2, const void *v3, - CPUS390XState *env, uint32_t desc) -{ - env->cc_op = vfc64(v1, v2, v3, env, true, float64_le_quiet, GETPC()); -} +DEF_GVEC_VFC(vfce, eq) +DEF_GVEC_VFC(vfch, lt) +DEF_GVEC_VFC(vfche, le) static void vfll32(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool s, uintptr_t retaddr) -- cgit v1.1 From 622ebe64ada4bf1bb3ce6bbfd7ea107ed166023c Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:17 +0200 Subject: s390x/tcg: Simplify vftci64() handling Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-7-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 - target/s390x/translate_vx.c.inc | 7 ++----- target/s390x/vec_fpu_helper.c | 29 +++++++++++------------------ 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 02a1692..e832680 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -273,7 +273,6 @@ DEF_HELPER_FLAGS_6(gvec_vfms64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, en DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_4(gvec_vftci64, void, ptr, cptr, env, i32) -DEF_HELPER_4(gvec_vftci64s, void, ptr, cptr, env, i32) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 604ae11..1404471 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2680,17 +2680,14 @@ static DisasJumpType op_vftci(DisasContext *s, DisasOps *o) const uint16_t i3 = get_field(s, i3); const uint8_t fpf = get_field(s, m4); const uint8_t m5 = get_field(s, m5); - gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vftci64; if (fpf != FPF_LONG || extract32(m5, 0, 3)) { gen_program_exception(s, PGM_SPECIFICATION); return DISAS_NORETURN; } - if (extract32(m5, 3, 1)) { - fn = gen_helper_gvec_vftci64s; - } - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, i3, fn); + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, + deposit32(m5, 4, 12, i3), gen_helper_gvec_vftci64); set_cc_static(s); return DISAS_NEXT; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 01ee41d..2ced6fc 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -413,13 +413,15 @@ void HELPER(gvec_vfms64s)(void *v1, const void *v2, const void *v3, vfma64(v1, v2, v3, v4, env, true, float_muladd_negate_c, GETPC()); } -static int vftci64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, - bool s, uint16_t i3) +void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env, + uint32_t desc) { + const uint16_t i3 = extract32(simd_data(desc), 4, 12); + const bool s = extract32(simd_data(desc), 3, 1); int i, match = 0; for (i = 0; i < 2; i++) { - float64 a = s390_vec_read_element64(v2, i); + const float64 a = s390_vec_read_float64(v2, i); if (float64_dcmask(env, a) & i3) { match++; @@ -432,20 +434,11 @@ static int vftci64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, } } - if (match) { - return s || match == 2 ? 0 : 1; + if (match == 2 || (s && match)) { + env->cc_op = 0; + } else if (match) { + env->cc_op = 1; + } else { + env->cc_op = 3; } - return 3; -} - -void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - env->cc_op = vftci64(v1, v2, env, false, simd_data(desc)); -} - -void HELPER(gvec_vftci64s)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - env->cc_op = vftci64(v1, v2, env, true, simd_data(desc)); } -- cgit v1.1 From 34142ffdee57f3fbd5eba1788ebc8e5d50a60022 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:18 +0200 Subject: s390x/tcg: Simplify vfma64() handling Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-8-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 2 -- target/s390x/translate_vx.c.inc | 8 +++----- target/s390x/vec_fpu_helper.c | 42 +++++++++++++++++------------------------ 3 files changed, 20 insertions(+), 32 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index e832680..3c87593 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -267,9 +267,7 @@ DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) -DEF_HELPER_FLAGS_6(gvec_vfma64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) -DEF_HELPER_FLAGS_6(gvec_vfms64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_4(gvec_vftci64, void, ptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 1404471..4b5bf0a 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2589,7 +2589,6 @@ static DisasJumpType op_vfma(DisasContext *s, DisasOps *o) { const uint8_t m5 = get_field(s, m5); const uint8_t fpf = get_field(s, m6); - const bool se = extract32(m5, 3, 1); gen_helper_gvec_4_ptr *fn; if (fpf != FPF_LONG || extract32(m5, 0, 3)) { @@ -2598,13 +2597,12 @@ static DisasJumpType op_vfma(DisasContext *s, DisasOps *o) } if (s->fields.op2 == 0x8f) { - fn = se ? gen_helper_gvec_vfma64s : gen_helper_gvec_vfma64; + fn = gen_helper_gvec_vfma64; } else { - fn = se ? gen_helper_gvec_vfms64s : gen_helper_gvec_vfms64; + fn = gen_helper_gvec_vfms64; } gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2), - get_field(s, v3), get_field(s, v4), cpu_env, - 0, fn); + get_field(s, v3), get_field(s, v4), cpu_env, m5, fn); return DISAS_NEXT; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 2ced6fc..23b38df 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -374,12 +374,12 @@ static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, int i; for (i = 0; i < 2; i++) { - const uint64_t a = s390_vec_read_element64(v2, i); - const uint64_t b = s390_vec_read_element64(v3, i); - const uint64_t c = s390_vec_read_element64(v4, i); - uint64_t ret = float64_muladd(a, b, c, flags, &env->fpu_status); + const float64 a = s390_vec_read_float64(v2, i); + const float64 b = s390_vec_read_float64(v3, i); + const float64 c = s390_vec_read_float64(v4, i); + const float64 ret = float64_muladd(a, b, c, flags, &env->fpu_status); - s390_vec_write_element64(&tmp, i, ret); + s390_vec_write_float64(&tmp, i, ret); vxc = check_ieee_exc(env, i, false, &vec_exc); if (s || vxc) { break; @@ -389,29 +389,21 @@ static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, *v1 = tmp; } -void HELPER(gvec_vfma64)(void *v1, const void *v2, const void *v3, - const void *v4, CPUS390XState *env, uint32_t desc) -{ - vfma64(v1, v2, v3, v4, env, false, 0, GETPC()); -} - -void HELPER(gvec_vfma64s)(void *v1, const void *v2, const void *v3, - const void *v4, CPUS390XState *env, uint32_t desc) -{ - vfma64(v1, v2, v3, v4, env, true, 0, GETPC()); +#define DEF_GVEC_VFMA_B(NAME, FLAGS, BITS) \ +void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ + const void *v4, CPUS390XState *env, \ + uint32_t desc) \ +{ \ + const bool se = extract32(simd_data(desc), 3, 1); \ + \ + vfma##BITS(v1, v2, v3, v4, env, se, FLAGS, GETPC()); \ } -void HELPER(gvec_vfms64)(void *v1, const void *v2, const void *v3, - const void *v4, CPUS390XState *env, uint32_t desc) -{ - vfma64(v1, v2, v3, v4, env, false, float_muladd_negate_c, GETPC()); -} +#define DEF_GVEC_VFMA(NAME, FLAGS) \ + DEF_GVEC_VFMA_B(NAME, FLAGS, 64) -void HELPER(gvec_vfms64s)(void *v1, const void *v2, const void *v3, - const void *v4, CPUS390XState *env, uint32_t desc) -{ - vfma64(v1, v2, v3, v4, env, true, float_muladd_negate_c, GETPC()); -} +DEF_GVEC_VFMA(vfma, 0) +DEF_GVEC_VFMA(vfms, float_muladd_negate_c) void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env, uint32_t desc) -- cgit v1.1 From 860b707bbb1957d710d3469dbdc3b9f72576a7ef Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:19 +0200 Subject: s390x/tcg: Simplify vfll32() handling Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-9-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 - target/s390x/translate_vx.c.inc | 6 +----- target/s390x/vec_fpu_helper.c | 21 +++++---------------- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 3c87593..63039c8 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -262,7 +262,6 @@ DEF_HELPER_FLAGS_4(gvec_vclgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfd64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) -DEF_HELPER_FLAGS_4(gvec_vfll32s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 4b5bf0a..5ff5998 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2570,18 +2570,14 @@ static DisasJumpType op_vfll(DisasContext *s, DisasOps *o) { const uint8_t fpf = get_field(s, m3); const uint8_t m4 = get_field(s, m4); - gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vfll32; if (fpf != FPF_SHORT || extract32(m4, 0, 3)) { gen_program_exception(s, PGM_SPECIFICATION); return DISAS_NORETURN; } - if (extract32(m4, 3, 1)) { - fn = gen_helper_gvec_vfll32s; - } gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, - 0, fn); + m4, gen_helper_gvec_vfll32); return DISAS_NEXT; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 23b38df..7bd3e44 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -287,9 +287,10 @@ DEF_GVEC_VFC(vfce, eq) DEF_GVEC_VFC(vfch, lt) DEF_GVEC_VFC(vfche, le) -static void vfll32(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, - bool s, uintptr_t retaddr) +void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env, + uint32_t desc) { + const bool s = extract32(simd_data(desc), 3, 1); uint8_t vxc, vec_exc = 0; S390Vector tmp = {}; int i; @@ -306,20 +307,8 @@ static void vfll32(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, break; } } - handle_ieee_exc(env, vxc, vec_exc, retaddr); - *v1 = tmp; -} - -void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - vfll32(v1, v2, env, false, GETPC()); -} - -void HELPER(gvec_vfll32s)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - vfll32(v1, v2, env, true, GETPC()); + handle_ieee_exc(env, vxc, vec_exc, GETPC()); + *(S390Vector *)v1 = tmp; } static void vflr64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, -- cgit v1.1 From 977e43d977c0b64a1b582cb4cc1c5711b5bc01a7 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:20 +0200 Subject: s390x/tcg: Simplify vflr64() handling Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-10-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 - target/s390x/translate_vx.c.inc | 3 +-- target/s390x/vec_fpu_helper.c | 29 +++++++---------------------- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 63039c8..0cfb82e 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -263,7 +263,6 @@ DEF_HELPER_FLAGS_5(gvec_vfd64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) -DEF_HELPER_FLAGS_4(gvec_vflr64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 5ff5998..91e2967 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2531,7 +2531,6 @@ static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o) const uint8_t fpf = get_field(s, m3); const uint8_t m4 = get_field(s, m4); const uint8_t erm = get_field(s, m5); - const bool se = extract32(m4, 3, 1); gen_helper_gvec_2_ptr *fn; if (fpf != FPF_LONG || extract32(m4, 0, 2) || erm > 7 || erm == 2) { @@ -2556,7 +2555,7 @@ static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o) fn = gen_helper_gvec_vfi64; break; case 0xc5: - fn = se ? gen_helper_gvec_vflr64s : gen_helper_gvec_vflr64; + fn = gen_helper_gvec_vflr64; break; default: g_assert_not_reached(); diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 7bd3e44..7ca9c89 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -311,9 +311,12 @@ void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env, *(S390Vector *)v1 = tmp; } -static void vflr64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, - bool s, bool XxC, uint8_t erm, uintptr_t retaddr) +void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env, + uint32_t desc) { + const uint8_t erm = extract32(simd_data(desc), 4, 4); + const bool s = extract32(simd_data(desc), 3, 1); + const bool XxC = extract32(simd_data(desc), 2, 1); uint8_t vxc, vec_exc = 0; S390Vector tmp = {}; int i, old_mode; @@ -332,26 +335,8 @@ static void vflr64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, } } s390_restore_bfp_rounding_mode(env, old_mode); - handle_ieee_exc(env, vxc, vec_exc, retaddr); - *v1 = tmp; -} - -void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vflr64(v1, v2, env, false, XxC, erm, GETPC()); -} - -void HELPER(gvec_vflr64s)(void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - const uint8_t erm = extract32(simd_data(desc), 4, 4); - const bool XxC = extract32(simd_data(desc), 2, 1); - - vflr64(v1, v2, env, true, XxC, erm, GETPC()); + handle_ieee_exc(env, vxc, vec_exc, GETPC()); + *(S390Vector *)v1 = tmp; } static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, -- cgit v1.1 From 4da79375c2a368bb548266e90e3d600afc05d165 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:21 +0200 Subject: s390x/tcg: Simplify wfc64() handling ... and prepare for 32/128 bit support. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-11-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/vec_fpu_helper.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 7ca9c89..4af59ea 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -201,8 +201,8 @@ static int wfc64(const S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool signal, uintptr_t retaddr) { /* only the zero-indexed elements are compared */ - const float64 a = s390_vec_read_element64(v1, 0); - const float64 b = s390_vec_read_element64(v2, 0); + const float64 a = s390_vec_read_float64(v1, 0); + const float64 b = s390_vec_read_float64(v2, 0); uint8_t vxc, vec_exc = 0; int cmp; @@ -217,17 +217,18 @@ static int wfc64(const S390Vector *v1, const S390Vector *v2, return float_comp_to_cc(env, cmp); } -void HELPER(gvec_wfc64)(const void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - env->cc_op = wfc64(v1, v2, env, false, GETPC()); +#define DEF_GVEC_WFC_B(NAME, SIGNAL, BITS) \ +void HELPER(gvec_##NAME##BITS)(const void *v1, const void *v2, \ + CPUS390XState *env, uint32_t desc) \ +{ \ + env->cc_op = wfc##BITS(v1, v2, env, SIGNAL, GETPC()); \ } -void HELPER(gvec_wfk64)(const void *v1, const void *v2, CPUS390XState *env, - uint32_t desc) -{ - env->cc_op = wfc64(v1, v2, env, true, GETPC()); -} +#define DEF_GVEC_WFC(NAME, SIGNAL) \ + DEF_GVEC_WFC_B(NAME, SIGNAL, 64) + +DEF_GVEC_WFC(wfc, false) +DEF_GVEC_WFC(wfk, true) typedef bool (*vfc64_fn)(float64 a, float64 b, float_status *status); static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, -- cgit v1.1 From 2a785dfb5071fdb269c77aeb7fa3930e93d413ef Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:22 +0200 Subject: s390x/tcg: Implement VECTOR BIT PERMUTE Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-12-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/translate_vx.c.inc | 8 ++++++++ target/s390x/vec_helper.c | 22 ++++++++++++++++++++++ 4 files changed, 33 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 0cfb82e..e99c964 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -126,6 +126,7 @@ DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_FLAGS_3(probe_write_access, TCG_CALL_NO_WG, void, env, i64, i64) /* === Vector Support Instructions === */ +DEF_HELPER_FLAGS_4(gvec_vbperm, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(vll, TCG_CALL_NO_WG, void, env, ptr, i64, i64) DEF_HELPER_FLAGS_4(gvec_vpk16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_vpk32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 35a0086..1634a6b 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -989,6 +989,8 @@ /* === Vector Support Instructions === */ +/* VECTOR BIT PERMUTE */ + E(0xe785, VBPERM, VRR_c, VE, 0, 0, 0, 0, vbperm, 0, 0, IF_VEC) /* VECTOR GATHER ELEMENT */ E(0xe713, VGEF, VRV, V, la2, 0, 0, 0, vge, 0, ES_32, IF_VEC) E(0xe712, VGEG, VRV, V, la2, 0, 0, 0, vge, 0, ES_64, IF_VEC) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 91e2967..96283d4 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -327,6 +327,14 @@ static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah, tcg_temp_free_i64(bh); } +static DisasJumpType op_vbperm(DisasContext *s, DisasOps *o) +{ + gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), get_field(s, v3), 0, + gen_helper_gvec_vbperm); + + return DISAS_NEXT; +} + static DisasJumpType op_vge(DisasContext *s, DisasOps *o) { const uint8_t es = s->insn->data; diff --git a/target/s390x/vec_helper.c b/target/s390x/vec_helper.c index 986e7cc..599bab0 100644 --- a/target/s390x/vec_helper.c +++ b/target/s390x/vec_helper.c @@ -19,6 +19,28 @@ #include "exec/cpu_ldst.h" #include "exec/exec-all.h" +void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3, + uint32_t desc) +{ + S390Vector tmp = {}; + uint16_t result = 0; + int i; + + for (i = 0; i < 16; i++) { + const uint8_t bit_nr = s390_vec_read_element8(v3, i); + uint16_t bit; + + if (bit_nr >= 128) { + continue; + } + bit = (s390_vec_read_element8(v2, bit_nr / 8) + >> (7 - (bit_nr % 8))) & 1; + result |= (bit << (15 - i)); + } + s390_vec_write_element16(&tmp, 3, result); + *(S390Vector *)v1 = tmp; +} + void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes) { if (likely(bytes >= 16)) { -- cgit v1.1 From 8c18fa5b3eba2b5c4d1285714682db066ea711fa Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:23 +0200 Subject: s390x/tcg: Implement VECTOR MULTIPLY SUM LOGICAL Fortunately, we only need the Doubleword implementation. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-13-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/insn-data.def | 2 ++ target/s390x/translate_vx.c.inc | 50 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 1634a6b..1a3ae7e 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1151,6 +1151,8 @@ F(0xe7a7, VMO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) /* VECTOR MULTIPLY LOGICAL ODD */ F(0xe7a5, VMLO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC) +/* VECTOR MULTIPLY SUM LOGICAL */ + F(0xe7b8, VMSL, VRR_d, VE, 0, 0, 0, 0, vmsl, 0, IF_VEC) /* VECTOR NAND */ F(0xe76e, VNN, VRR_c, VE, 0, 0, 0, 0, vnn, 0, IF_VEC) /* VECTOR NOR */ diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 96283d4..6e75b40 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -1779,6 +1779,56 @@ static DisasJumpType op_vm(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o) +{ + TCGv_i64 l1, h1, l2, h2; + + if (get_field(s, m4) != ES_64) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + l1 = tcg_temp_new_i64(); + h1 = tcg_temp_new_i64(); + l2 = tcg_temp_new_i64(); + h2 = tcg_temp_new_i64(); + + /* Multipy both even elements from v2 and v3 */ + read_vec_element_i64(l1, get_field(s, v2), 0, ES_64); + read_vec_element_i64(h1, get_field(s, v3), 0, ES_64); + tcg_gen_mulu2_i64(l1, h1, l1, h1); + /* Shift result left by one (x2) if requested */ + if (extract32(get_field(s, m6), 3, 1)) { + tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1); + } + + /* Multipy both odd elements from v2 and v3 */ + read_vec_element_i64(l2, get_field(s, v2), 1, ES_64); + read_vec_element_i64(h2, get_field(s, v3), 1, ES_64); + tcg_gen_mulu2_i64(l2, h2, l2, h2); + /* Shift result left by one (x2) if requested */ + if (extract32(get_field(s, m6), 2, 1)) { + tcg_gen_add2_i64(l2, h2, l2, h2, l2, h2); + } + + /* Add both intermediate results */ + tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2); + /* Add whole v4 */ + read_vec_element_i64(h2, get_field(s, v4), 0, ES_64); + read_vec_element_i64(l2, get_field(s, v4), 1, ES_64); + tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2); + + /* Store final result into v1. */ + write_vec_element_i64(h1, get_field(s, v1), 0, ES_64); + write_vec_element_i64(l1, get_field(s, v1), 1, ES_64); + + tcg_temp_free_i64(l1); + tcg_temp_free_i64(h1); + tcg_temp_free_i64(l2); + tcg_temp_free_i64(h2); + return DISAS_NEXT; +} + static DisasJumpType op_vnn(DisasContext *s, DisasOps *o) { gen_gvec_fn_3(nand, ES_8, get_field(s, v1), -- cgit v1.1 From 0987961da96a5f62de5f0519ceaa022c394207c1 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:24 +0200 Subject: s390x/tcg: Implement 32/128 bit for VECTOR FP (ADD|DIVIDE|MULTIPLY|SUBTRACT) In case of 128bit, we always have a single element. Add new helpers for reading/writing 32/128 bit floats. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-14-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 8 ++++ target/s390x/translate_vx.c.inc | 85 ++++++++++++++++++++++++++++++++++++----- target/s390x/vec_fpu_helper.c | 74 +++++++++++++++++++++++++++++++++-- 3 files changed, 153 insertions(+), 14 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index e99c964..2d5e382 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -247,7 +247,9 @@ DEF_HELPER_6(gvec_vstrc_cc_rt16, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_6(gvec_vstrc_cc_rt32, void, ptr, cptr, cptr, cptr, env, i32) /* === Vector Floating-Point Instructions */ +DEF_HELPER_FLAGS_5(gvec_vfa32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfa64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfa128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfc64, void, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfk64, void, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfce64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) @@ -260,15 +262,21 @@ DEF_HELPER_FLAGS_4(gvec_vcdg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcdlg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vclgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfd32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfd64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfd128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfm32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfm128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfs32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfs128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_4(gvec_vftci64, void, ptr, cptr, env, i32) #ifndef CONFIG_USER_ONLY diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 6e75b40..0fbd914 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2501,29 +2501,94 @@ static DisasJumpType op_vfa(DisasContext *s, DisasOps *o) { const uint8_t fpf = get_field(s, m4); const uint8_t m5 = get_field(s, m5); - gen_helper_gvec_3_ptr *fn; - - if (fpf != FPF_LONG || extract32(m5, 0, 3)) { - gen_program_exception(s, PGM_SPECIFICATION); - return DISAS_NORETURN; - } + gen_helper_gvec_3_ptr *fn = NULL; switch (s->fields.op2) { case 0xe3: - fn = gen_helper_gvec_vfa64; + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfa32; + } + break; + case FPF_LONG: + fn = gen_helper_gvec_vfa64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfa128; + } + break; + default: + break; + } break; case 0xe5: - fn = gen_helper_gvec_vfd64; + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfd32; + } + break; + case FPF_LONG: + fn = gen_helper_gvec_vfd64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfd128; + } + break; + default: + break; + } break; case 0xe7: - fn = gen_helper_gvec_vfm64; + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfm32; + } + break; + case FPF_LONG: + fn = gen_helper_gvec_vfm64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfm128; + } + break; + default: + break; + } break; case 0xe2: - fn = gen_helper_gvec_vfs64; + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfs32; + } + break; + case FPF_LONG: + fn = gen_helper_gvec_vfs64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfs128; + } + break; + default: + break; + } break; default: g_assert_not_reached(); } + + if (!fn || extract32(m5, 0, 3)) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), cpu_env, m5, fn); return DISAS_NEXT; diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 4af59ea..3484c16 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -78,16 +78,38 @@ static void handle_ieee_exc(CPUS390XState *env, uint8_t vxc, uint8_t vec_exc, } } +static float32 s390_vec_read_float32(const S390Vector *v, uint8_t enr) +{ + return make_float32(s390_vec_read_element32(v, enr)); +} + static float64 s390_vec_read_float64(const S390Vector *v, uint8_t enr) { return make_float64(s390_vec_read_element64(v, enr)); } +static float128 s390_vec_read_float128(const S390Vector *v) +{ + return make_float128(s390_vec_read_element64(v, 0), + s390_vec_read_element64(v, 1)); +} + +static void s390_vec_write_float32(S390Vector *v, uint8_t enr, float32 data) +{ + return s390_vec_write_element32(v, enr, data); +} + static void s390_vec_write_float64(S390Vector *v, uint8_t enr, float64 data) { return s390_vec_write_element64(v, enr, data); } +static void s390_vec_write_float128(S390Vector *v, float128 data) +{ + s390_vec_write_element64(v, 0, data.high); + s390_vec_write_element64(v, 1, data.low); +} + typedef float64 (*vop64_2_fn)(float64 a, float_status *s); static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool s, bool XxC, uint8_t erm, vop64_2_fn fn, @@ -160,6 +182,29 @@ DEF_GVEC_VOP2_64(vclgd) DEF_GVEC_VOP2(vfi, round_to_int) DEF_GVEC_VOP2(vfsq, sqrt) +typedef float32 (*vop32_3_fn)(float32 a, float32 b, float_status *s); +static void vop32_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, + CPUS390XState *env, bool s, vop32_3_fn fn, + uintptr_t retaddr) +{ + uint8_t vxc, vec_exc = 0; + S390Vector tmp = {}; + int i; + + for (i = 0; i < 4; i++) { + const float32 a = s390_vec_read_float32(v2, i); + const float32 b = s390_vec_read_float32(v3, i); + + s390_vec_write_float32(&tmp, i, fn(a, b, &env->fpu_status)); + vxc = check_ieee_exc(env, i, false, &vec_exc); + if (s || vxc) { + break; + } + } + handle_ieee_exc(env, vxc, vec_exc, retaddr); + *v1 = tmp; +} + typedef float64 (*vop64_3_fn)(float64 a, float64 b, float_status *s); static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, CPUS390XState *env, bool s, vop64_3_fn fn, @@ -183,15 +228,36 @@ static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, *v1 = tmp; } -#define DEF_GVEC_VOP3(NAME, OP) \ -void HELPER(gvec_##NAME##64)(void *v1, const void *v2, const void *v3, \ - CPUS390XState *env, uint32_t desc) \ +typedef float128 (*vop128_3_fn)(float128 a, float128 b, float_status *s); +static void vop128_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, + CPUS390XState *env, bool s, vop128_3_fn fn, + uintptr_t retaddr) +{ + const float128 a = s390_vec_read_float128(v2); + const float128 b = s390_vec_read_float128(v3); + uint8_t vxc, vec_exc = 0; + S390Vector tmp = {}; + + s390_vec_write_float128(&tmp, fn(a, b, &env->fpu_status)); + vxc = check_ieee_exc(env, 0, false, &vec_exc); + handle_ieee_exc(env, vxc, vec_exc, retaddr); + *v1 = tmp; +} + +#define DEF_GVEC_VOP3_B(NAME, OP, BITS) \ +void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ + CPUS390XState *env, uint32_t desc) \ { \ const bool se = extract32(simd_data(desc), 3, 1); \ \ - vop64_3(v1, v2, v3, env, se, float64_##OP, GETPC()); \ + vop##BITS##_3(v1, v2, v3, env, se, float##BITS##_##OP, GETPC()); \ } +#define DEF_GVEC_VOP3(NAME, OP) \ +DEF_GVEC_VOP3_B(NAME, OP, 32) \ +DEF_GVEC_VOP3_B(NAME, OP, 64) \ +DEF_GVEC_VOP3_B(NAME, OP, 128) + DEF_GVEC_VOP3(vfa, add) DEF_GVEC_VOP3(vfs, sub) DEF_GVEC_VOP3(vfd, div) -- cgit v1.1 From acb269a4cdeeafb027c350348f3137916e580746 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:25 +0200 Subject: s390x/tcg: Implement 32/128 bit for VECTOR (LOAD FP INTEGER|FP SQUARE ROOT) Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-15-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 4 +++ target/s390x/translate_vx.c.inc | 74 +++++++++++++++++++++++++++++++++-------- target/s390x/vec_fpu_helper.c | 46 ++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 15 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 2d5e382..28797a6 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -265,7 +265,9 @@ DEF_HELPER_FLAGS_4(gvec_vclgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfd32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfd64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfd128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vfi32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vfi128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) @@ -273,7 +275,9 @@ DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vfsq32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vfsq128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 0fbd914..6241279 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2654,35 +2654,63 @@ static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o) const uint8_t fpf = get_field(s, m3); const uint8_t m4 = get_field(s, m4); const uint8_t erm = get_field(s, m5); - gen_helper_gvec_2_ptr *fn; + gen_helper_gvec_2_ptr *fn = NULL; - if (fpf != FPF_LONG || extract32(m4, 0, 2) || erm > 7 || erm == 2) { - gen_program_exception(s, PGM_SPECIFICATION); - return DISAS_NORETURN; - } switch (s->fields.op2) { case 0xc3: - fn = gen_helper_gvec_vcdg64; + if (fpf == FPF_LONG) { + fn = gen_helper_gvec_vcdg64; + } break; case 0xc1: - fn = gen_helper_gvec_vcdlg64; + if (fpf == FPF_LONG) { + fn = gen_helper_gvec_vcdlg64; + } break; case 0xc2: - fn = gen_helper_gvec_vcgd64; + if (fpf == FPF_LONG) { + fn = gen_helper_gvec_vcgd64; + } break; case 0xc0: - fn = gen_helper_gvec_vclgd64; + if (fpf == FPF_LONG) { + fn = gen_helper_gvec_vclgd64; + } break; case 0xc7: - fn = gen_helper_gvec_vfi64; + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfi32; + } + break; + case FPF_LONG: + fn = gen_helper_gvec_vfi64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfi128; + } + break; + default: + break; + } break; case 0xc5: - fn = gen_helper_gvec_vflr64; + if (fpf == FPF_LONG) { + fn = gen_helper_gvec_vflr64; + } break; default: g_assert_not_reached(); } + + if (!fn || extract32(m4, 0, 2) || erm > 7 || erm == 2) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, deposit32(m4, 4, 4, erm), fn); return DISAS_NEXT; @@ -2780,14 +2808,32 @@ static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o) { const uint8_t fpf = get_field(s, m3); const uint8_t m4 = get_field(s, m4); + gen_helper_gvec_2_ptr *fn = NULL; + + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfsq32; + } + break; + case FPF_LONG: + fn = gen_helper_gvec_vfsq64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfsq128; + } + break; + default: + break; + } - if (fpf != FPF_LONG || extract32(m4, 0, 3)) { + if (!fn || extract32(m4, 0, 3)) { gen_program_exception(s, PGM_SPECIFICATION); return DISAS_NORETURN; } - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, - gen_helper_gvec_vfsq64); + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn); return DISAS_NEXT; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 3484c16..1df8f3d 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -110,6 +110,30 @@ static void s390_vec_write_float128(S390Vector *v, float128 data) s390_vec_write_element64(v, 1, data.low); } +typedef float32 (*vop32_2_fn)(float32 a, float_status *s); +static void vop32_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, + bool s, bool XxC, uint8_t erm, vop32_2_fn fn, + uintptr_t retaddr) +{ + uint8_t vxc, vec_exc = 0; + S390Vector tmp = {}; + int i, old_mode; + + old_mode = s390_swap_bfp_rounding_mode(env, erm); + for (i = 0; i < 4; i++) { + const float32 a = s390_vec_read_float32(v2, i); + + s390_vec_write_float32(&tmp, i, fn(a, &env->fpu_status)); + vxc = check_ieee_exc(env, i, XxC, &vec_exc); + if (s || vxc) { + break; + } + } + s390_restore_bfp_rounding_mode(env, old_mode); + handle_ieee_exc(env, vxc, vec_exc, retaddr); + *v1 = tmp; +} + typedef float64 (*vop64_2_fn)(float64 a, float_status *s); static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool s, bool XxC, uint8_t erm, vop64_2_fn fn, @@ -134,6 +158,24 @@ static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, *v1 = tmp; } +typedef float128 (*vop128_2_fn)(float128 a, float_status *s); +static void vop128_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env, + bool s, bool XxC, uint8_t erm, vop128_2_fn fn, + uintptr_t retaddr) +{ + const float128 a = s390_vec_read_float128(v2); + uint8_t vxc, vec_exc = 0; + S390Vector tmp = {}; + int old_mode; + + old_mode = s390_swap_bfp_rounding_mode(env, erm); + s390_vec_write_float128(&tmp, fn(a, &env->fpu_status)); + vxc = check_ieee_exc(env, 0, XxC, &vec_exc); + s390_restore_bfp_rounding_mode(env, old_mode); + handle_ieee_exc(env, vxc, vec_exc, retaddr); + *v1 = tmp; +} + static float64 vcdg64(float64 a, float_status *s) { return int64_to_float64(a, s); @@ -173,7 +215,9 @@ void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, CPUS390XState *env, \ DEF_GVEC_VOP2_FN(NAME, NAME##64, 64) #define DEF_GVEC_VOP2(NAME, OP) \ -DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64) +DEF_GVEC_VOP2_FN(NAME, float32_##OP, 32) \ +DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64) \ +DEF_GVEC_VOP2_FN(NAME, float128_##OP, 128) DEF_GVEC_VOP2_64(vcdg) DEF_GVEC_VOP2_64(vcdlg) -- cgit v1.1 From e384332cb53bd5b4d813cc38b5d19b3648047e14 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:26 +0200 Subject: s390x/tcg: Implement 32/128 bit for VECTOR FP COMPARE * In addition to 32/128bit variants, we also have to support the "Signal-on-QNaN (SQ)" bit. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-16-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 12 ++++++++ target/s390x/translate_vx.c.inc | 57 ++++++++++++++++++++++++++++++------ target/s390x/vec_fpu_helper.c | 64 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 121 insertions(+), 12 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 28797a6..1468361 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -252,12 +252,24 @@ DEF_HELPER_FLAGS_5(gvec_vfa64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfa128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfc64, void, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfk64, void, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfce32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_5(gvec_vfce32_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfce64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_5(gvec_vfce64_cc, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfce128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_5(gvec_vfce128_cc, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfch32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_5(gvec_vfch32_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfch64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_5(gvec_vfch64_cc, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfch128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_5(gvec_vfch128_cc, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfche32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_5(gvec_vfche32_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfche64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_5(gvec_vfche64_cc, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfche128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_5(gvec_vfche128_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcdg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcdlg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vcgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 6241279..6f6ef6b 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2621,26 +2621,65 @@ static DisasJumpType op_vfc(DisasContext *s, DisasOps *o) const uint8_t m5 = get_field(s, m5); const uint8_t m6 = get_field(s, m6); const bool cs = extract32(m6, 0, 1); - gen_helper_gvec_3_ptr *fn; - - if (fpf != FPF_LONG || extract32(m5, 0, 3) || extract32(m6, 1, 3)) { - gen_program_exception(s, PGM_SPECIFICATION); - return DISAS_NORETURN; - } + const bool sq = extract32(m5, 2, 1); + gen_helper_gvec_3_ptr *fn = NULL; switch (s->fields.op2) { case 0xe8: - fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64; + switch (fpf) { + case FPF_SHORT: + fn = cs ? gen_helper_gvec_vfce32_cc : gen_helper_gvec_vfce32; + break; + case FPF_LONG: + fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64; + break; + case FPF_EXT: + fn = cs ? gen_helper_gvec_vfce128_cc : gen_helper_gvec_vfce128; + break; + default: + break; + } break; case 0xeb: - fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64; + switch (fpf) { + case FPF_SHORT: + fn = cs ? gen_helper_gvec_vfch32_cc : gen_helper_gvec_vfch32; + break; + case FPF_LONG: + fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64; + break; + case FPF_EXT: + fn = cs ? gen_helper_gvec_vfch128_cc : gen_helper_gvec_vfch128; + break; + default: + break; + } break; case 0xea: - fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64; + switch (fpf) { + case FPF_SHORT: + fn = cs ? gen_helper_gvec_vfche32_cc : gen_helper_gvec_vfche32; + break; + case FPF_LONG: + fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64; + break; + case FPF_EXT: + fn = cs ? gen_helper_gvec_vfche128_cc : gen_helper_gvec_vfche128; + break; + default: + break; + } break; default: g_assert_not_reached(); } + + if (!fn || extract32(m5, 0, 2) || extract32(m6, 1, 3) || + (!s390_has_feat(S390_FEAT_VECTOR_ENH) && (fpf != FPF_LONG || sq))) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), cpu_env, m5, fn); if (cs) { diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 1df8f3d..67dcd8b 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -340,6 +340,38 @@ void HELPER(gvec_##NAME##BITS)(const void *v1, const void *v2, \ DEF_GVEC_WFC(wfc, false) DEF_GVEC_WFC(wfk, true) +typedef bool (*vfc32_fn)(float32 a, float32 b, float_status *status); +static int vfc32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, + CPUS390XState *env, bool s, vfc32_fn fn, uintptr_t retaddr) +{ + uint8_t vxc, vec_exc = 0; + S390Vector tmp = {}; + int match = 0; + int i; + + for (i = 0; i < 4; i++) { + const float32 a = s390_vec_read_float32(v2, i); + const float32 b = s390_vec_read_float32(v3, i); + + /* swap the order of the parameters, so we can use existing functions */ + if (fn(b, a, &env->fpu_status)) { + match++; + s390_vec_write_element32(&tmp, i, -1u); + } + vxc = check_ieee_exc(env, i, false, &vec_exc); + if (s || vxc) { + break; + } + } + + handle_ieee_exc(env, vxc, vec_exc, retaddr); + *v1 = tmp; + if (match) { + return s || match == 4 ? 0 : 1; + } + return 3; +} + typedef bool (*vfc64_fn)(float64 a, float64 b, float_status *status); static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr) @@ -372,12 +404,35 @@ static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, return 3; } +typedef bool (*vfc128_fn)(float128 a, float128 b, float_status *status); +static int vfc128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, + CPUS390XState *env, bool s, vfc128_fn fn, uintptr_t retaddr) +{ + const float128 a = s390_vec_read_float128(v2); + const float128 b = s390_vec_read_float128(v3); + uint8_t vxc, vec_exc = 0; + S390Vector tmp = {}; + bool match = false; + + /* swap the order of the parameters, so we can use existing functions */ + if (fn(b, a, &env->fpu_status)) { + match = true; + s390_vec_write_element64(&tmp, 0, -1ull); + s390_vec_write_element64(&tmp, 1, -1ull); + } + vxc = check_ieee_exc(env, 0, false, &vec_exc); + handle_ieee_exc(env, vxc, vec_exc, retaddr); + *v1 = tmp; + return match ? 0 : 3; +} + #define DEF_GVEC_VFC_B(NAME, OP, BITS) \ void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ CPUS390XState *env, uint32_t desc) \ { \ const bool se = extract32(simd_data(desc), 3, 1); \ - vfc##BITS##_fn fn = float##BITS##_##OP##_quiet; \ + const bool sq = extract32(simd_data(desc), 2, 1); \ + vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet; \ \ vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ } \ @@ -386,13 +441,16 @@ void HELPER(gvec_##NAME##BITS##_cc)(void *v1, const void *v2, const void *v3, \ CPUS390XState *env, uint32_t desc) \ { \ const bool se = extract32(simd_data(desc), 3, 1); \ - vfc##BITS##_fn fn = float##BITS##_##OP##_quiet; \ + const bool sq = extract32(simd_data(desc), 2, 1); \ + vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet; \ \ env->cc_op = vfc##BITS(v1, v2, v3, env, se, fn, GETPC()); \ } #define DEF_GVEC_VFC(NAME, OP) \ -DEF_GVEC_VFC_B(NAME, OP, 64) +DEF_GVEC_VFC_B(NAME, OP, 32) \ +DEF_GVEC_VFC_B(NAME, OP, 64) \ +DEF_GVEC_VFC_B(NAME, OP, 128) \ DEF_GVEC_VFC(vfce, eq) DEF_GVEC_VFC(vfch, lt) -- cgit v1.1 From 1c6b5b47da8d9c8797cdf866fa180466b56a9204 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:27 +0200 Subject: s390x/tcg: Implement 32/128 bit for VECTOR FP COMPARE (AND SIGNAL) SCALAR Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-17-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 4 ++++ target/s390x/translate_vx.c.inc | 38 +++++++++++++++++++++++++++-------- target/s390x/vec_fpu_helper.c | 44 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 1468361..dca436f 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -250,8 +250,12 @@ DEF_HELPER_6(gvec_vstrc_cc_rt32, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfa32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfa64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfa128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_4(gvec_wfc32, void, cptr, cptr, env, i32) +DEF_HELPER_4(gvec_wfk32, void, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfc64, void, cptr, cptr, env, i32) DEF_HELPER_4(gvec_wfk64, void, cptr, cptr, env, i32) +DEF_HELPER_4(gvec_wfc128, void, cptr, cptr, env, i32) +DEF_HELPER_4(gvec_wfk128, void, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfce32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_5(gvec_vfce32_cc, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfce64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 6f6ef6b..822a9d0 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2598,19 +2598,41 @@ static DisasJumpType op_wfc(DisasContext *s, DisasOps *o) { const uint8_t fpf = get_field(s, m3); const uint8_t m4 = get_field(s, m4); + gen_helper_gvec_2_ptr *fn = NULL; - if (fpf != FPF_LONG || m4) { + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_wfk32; + if (s->fields.op2 == 0xcb) { + fn = gen_helper_gvec_wfc32; + } + } + break; + case FPF_LONG: + fn = gen_helper_gvec_wfk64; + if (s->fields.op2 == 0xcb) { + fn = gen_helper_gvec_wfc64; + } + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_wfk128; + if (s->fields.op2 == 0xcb) { + fn = gen_helper_gvec_wfc128; + } + } + break; + default: + break; + }; + + if (!fn || m4) { gen_program_exception(s, PGM_SPECIFICATION); return DISAS_NORETURN; } - if (s->fields.op2 == 0xcb) { - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), - cpu_env, 0, gen_helper_gvec_wfc64); - } else { - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), - cpu_env, 0, gen_helper_gvec_wfk64); - } + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, 0, fn); set_cc_static(s); return DISAS_NEXT; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 67dcd8b..fba5261 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -307,6 +307,26 @@ DEF_GVEC_VOP3(vfs, sub) DEF_GVEC_VOP3(vfd, div) DEF_GVEC_VOP3(vfm, mul) +static int wfc32(const S390Vector *v1, const S390Vector *v2, + CPUS390XState *env, bool signal, uintptr_t retaddr) +{ + /* only the zero-indexed elements are compared */ + const float32 a = s390_vec_read_float32(v1, 0); + const float32 b = s390_vec_read_float32(v2, 0); + uint8_t vxc, vec_exc = 0; + int cmp; + + if (signal) { + cmp = float32_compare(a, b, &env->fpu_status); + } else { + cmp = float32_compare_quiet(a, b, &env->fpu_status); + } + vxc = check_ieee_exc(env, 0, false, &vec_exc); + handle_ieee_exc(env, vxc, vec_exc, retaddr); + + return float_comp_to_cc(env, cmp); +} + static int wfc64(const S390Vector *v1, const S390Vector *v2, CPUS390XState *env, bool signal, uintptr_t retaddr) { @@ -327,6 +347,26 @@ static int wfc64(const S390Vector *v1, const S390Vector *v2, return float_comp_to_cc(env, cmp); } +static int wfc128(const S390Vector *v1, const S390Vector *v2, + CPUS390XState *env, bool signal, uintptr_t retaddr) +{ + /* only the zero-indexed elements are compared */ + const float128 a = s390_vec_read_float128(v1); + const float128 b = s390_vec_read_float128(v2); + uint8_t vxc, vec_exc = 0; + int cmp; + + if (signal) { + cmp = float128_compare(a, b, &env->fpu_status); + } else { + cmp = float128_compare_quiet(a, b, &env->fpu_status); + } + vxc = check_ieee_exc(env, 0, false, &vec_exc); + handle_ieee_exc(env, vxc, vec_exc, retaddr); + + return float_comp_to_cc(env, cmp); +} + #define DEF_GVEC_WFC_B(NAME, SIGNAL, BITS) \ void HELPER(gvec_##NAME##BITS)(const void *v1, const void *v2, \ CPUS390XState *env, uint32_t desc) \ @@ -335,7 +375,9 @@ void HELPER(gvec_##NAME##BITS)(const void *v1, const void *v2, \ } #define DEF_GVEC_WFC(NAME, SIGNAL) \ - DEF_GVEC_WFC_B(NAME, SIGNAL, 64) + DEF_GVEC_WFC_B(NAME, SIGNAL, 32) \ + DEF_GVEC_WFC_B(NAME, SIGNAL, 64) \ + DEF_GVEC_WFC_B(NAME, SIGNAL, 128) DEF_GVEC_WFC(wfc, false) DEF_GVEC_WFC(wfk, true) -- cgit v1.1 From 2e96005ed8509275f7396adacc3353e9189ce518 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:28 +0200 Subject: s390x/tcg: Implement 64 bit for VECTOR FP LOAD LENGTHENED 64 bit -> 128 bit, there is only a single final element. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-18-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 + target/s390x/translate_vx.c.inc | 19 ++++++++++++++++--- target/s390x/vec_fpu_helper.c | 13 +++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index dca436f..b5ba159 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -285,6 +285,7 @@ DEF_HELPER_FLAGS_4(gvec_vfi32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfi128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vfll64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 822a9d0..472afca 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2781,14 +2781,27 @@ static DisasJumpType op_vfll(DisasContext *s, DisasOps *o) { const uint8_t fpf = get_field(s, m3); const uint8_t m4 = get_field(s, m4); + gen_helper_gvec_2_ptr *fn = NULL; - if (fpf != FPF_SHORT || extract32(m4, 0, 3)) { + switch (fpf) { + case FPF_SHORT: + fn = gen_helper_gvec_vfll32; + break; + case FPF_LONG: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfll64; + } + break; + default: + break; + } + + if (!fn || extract32(m4, 0, 3)) { gen_program_exception(s, PGM_SPECIFICATION); return DISAS_NORETURN; } - gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, - m4, gen_helper_gvec_vfll32); + gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn); return DISAS_NEXT; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index fba5261..75e3212 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -522,6 +522,19 @@ void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env, *(S390Vector *)v1 = tmp; } +void HELPER(gvec_vfll64)(void *v1, const void *v2, CPUS390XState *env, + uint32_t desc) +{ + /* load from even element */ + const float128 ret = float64_to_float128(s390_vec_read_float64(v2, 0), + &env->fpu_status); + uint8_t vxc, vec_exc = 0; + + vxc = check_ieee_exc(env, 0, false, &vec_exc); + handle_ieee_exc(env, vxc, vec_exc, GETPC()); + s390_vec_write_float128(v1, ret); +} + void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env, uint32_t desc) { -- cgit v1.1 From 9cbc8be05aebc339546ed36334cb9e7b01e74b99 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:29 +0200 Subject: s390x/tcg: Implement 128 bit for VECTOR FP LOAD ROUNDED 128 bit -> 64 bit, there is only a single element to process. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-19-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 + target/s390x/translate_vx.c.inc | 11 ++++++++++- target/s390x/vec_fpu_helper.c | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index b5ba159..02e6967 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -287,6 +287,7 @@ DEF_HELPER_FLAGS_4(gvec_vfi128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfll64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) +DEF_HELPER_FLAGS_4(gvec_vflr128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 472afca..e94c9f9 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2759,8 +2759,17 @@ static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o) } break; case 0xc5: - if (fpf == FPF_LONG) { + switch (fpf) { + case FPF_LONG: fn = gen_helper_gvec_vflr64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vflr128; + } + break; + default: + break; } break; default: diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 75e3212..0fb82bd 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -563,6 +563,25 @@ void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env, *(S390Vector *)v1 = tmp; } +void HELPER(gvec_vflr128)(void *v1, const void *v2, CPUS390XState *env, + uint32_t desc) +{ + const uint8_t erm = extract32(simd_data(desc), 4, 4); + const bool XxC = extract32(simd_data(desc), 2, 1); + uint8_t vxc, vec_exc = 0; + int old_mode; + float64 ret; + + old_mode = s390_swap_bfp_rounding_mode(env, erm); + ret = float128_to_float64(s390_vec_read_float128(v2), &env->fpu_status); + vxc = check_ieee_exc(env, 0, XxC, &vec_exc); + s390_restore_bfp_rounding_mode(env, old_mode); + handle_ieee_exc(env, vxc, vec_exc, GETPC()); + + /* place at even element, odd element is unpredictable */ + s390_vec_write_float64(v1, 0, ret); +} + static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, const S390Vector *v4, CPUS390XState *env, bool s, int flags, uintptr_t retaddr) -- cgit v1.1 From 390eeb35757ffeeed6811370625e11a1c6b1d565 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:30 +0200 Subject: s390x/tcg: Implement 32/128 bit for VECTOR FP PERFORM SIGN OPERATION Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-20-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/translate_vx.c.inc | 106 +++++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 33 deletions(-) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index e94c9f9..4d1ccb4 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2842,48 +2842,88 @@ static DisasJumpType op_vfpso(DisasContext *s, DisasOps *o) const uint8_t fpf = get_field(s, m3); const uint8_t m4 = get_field(s, m4); const uint8_t m5 = get_field(s, m5); + const bool se = extract32(m4, 3, 1); TCGv_i64 tmp; - if (fpf != FPF_LONG || extract32(m4, 0, 3) || m5 > 2) { + if ((fpf != FPF_LONG && !s390_has_feat(S390_FEAT_VECTOR_ENH)) || + extract32(m4, 0, 3) || m5 > 2) { gen_program_exception(s, PGM_SPECIFICATION); return DISAS_NORETURN; } - if (extract32(m4, 3, 1)) { - tmp = tcg_temp_new_i64(); - read_vec_element_i64(tmp, v2, 0, ES_64); - switch (m5) { - case 0: - /* sign bit is inverted (complement) */ - tcg_gen_xori_i64(tmp, tmp, 1ull << 63); - break; - case 1: - /* sign bit is set to one (negative) */ - tcg_gen_ori_i64(tmp, tmp, 1ull << 63); - break; - case 2: - /* sign bit is set to zero (positive) */ - tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1); - break; + switch (fpf) { + case FPF_SHORT: + if (!se) { + switch (m5) { + case 0: + /* sign bit is inverted (complement) */ + gen_gvec_fn_2i(xori, ES_32, v1, v2, 1ull << 31); + break; + case 1: + /* sign bit is set to one (negative) */ + gen_gvec_fn_2i(ori, ES_32, v1, v2, 1ull << 31); + break; + case 2: + /* sign bit is set to zero (positive) */ + gen_gvec_fn_2i(andi, ES_32, v1, v2, (1ull << 31) - 1); + break; + } + return DISAS_NEXT; } - write_vec_element_i64(tmp, v1, 0, ES_64); - tcg_temp_free_i64(tmp); - } else { - switch (m5) { - case 0: - /* sign bit is inverted (complement) */ - gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63); - break; - case 1: - /* sign bit is set to one (negative) */ - gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63); - break; - case 2: - /* sign bit is set to zero (positive) */ - gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1); - break; + break; + case FPF_LONG: + if (!se) { + switch (m5) { + case 0: + /* sign bit is inverted (complement) */ + gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63); + break; + case 1: + /* sign bit is set to one (negative) */ + gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63); + break; + case 2: + /* sign bit is set to zero (positive) */ + gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1); + break; + } + return DISAS_NEXT; } + break; + case FPF_EXT: + /* Only a single element. */ + break; + default: + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; } + + /* With a single element, we are only interested in bit 0. */ + tmp = tcg_temp_new_i64(); + read_vec_element_i64(tmp, v2, 0, ES_64); + switch (m5) { + case 0: + /* sign bit is inverted (complement) */ + tcg_gen_xori_i64(tmp, tmp, 1ull << 63); + break; + case 1: + /* sign bit is set to one (negative) */ + tcg_gen_ori_i64(tmp, tmp, 1ull << 63); + break; + case 2: + /* sign bit is set to zero (positive) */ + tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1); + break; + } + write_vec_element_i64(tmp, v1, 0, ES_64); + + if (fpf == FPF_EXT) { + read_vec_element_i64(tmp, v2, 1, ES_64); + write_vec_element_i64(tmp, v1, 1, ES_64); + } + + tcg_temp_free_i64(tmp); + return DISAS_NEXT; } -- cgit v1.1 From a38b5a0eab9538543a241582d80cf0eb6ce97f1f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:31 +0200 Subject: s390x/tcg: Implement 32/128 bit for VECTOR FP TEST DATA CLASS IMMEDIATE Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-21-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 2 ++ target/s390x/translate_vx.c.inc | 23 ++++++++++++++++++-- target/s390x/vec_fpu_helper.c | 47 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 02e6967..bae73b9 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -299,7 +299,9 @@ DEF_HELPER_FLAGS_4(gvec_vfsq128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfs128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_4(gvec_vftci32, void, ptr, cptr, env, i32) DEF_HELPER_4(gvec_vftci64, void, ptr, cptr, env, i32) +DEF_HELPER_4(gvec_vftci128, void, ptr, cptr, env, i32) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 4d1ccb4..765f75d 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2965,14 +2965,33 @@ static DisasJumpType op_vftci(DisasContext *s, DisasOps *o) const uint16_t i3 = get_field(s, i3); const uint8_t fpf = get_field(s, m4); const uint8_t m5 = get_field(s, m5); + gen_helper_gvec_2_ptr *fn = NULL; - if (fpf != FPF_LONG || extract32(m5, 0, 3)) { + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vftci32; + } + break; + case FPF_LONG: + fn = gen_helper_gvec_vftci64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vftci128; + } + break; + default: + break; + } + + if (!fn || extract32(m5, 0, 3)) { gen_program_exception(s, PGM_SPECIFICATION); return DISAS_NORETURN; } gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, - deposit32(m5, 4, 12, i3), gen_helper_gvec_vftci64); + deposit32(m5, 4, 12, i3), fn); set_cc_static(s); return DISAS_NEXT; } diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 0fb82bd..6984f77 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -622,6 +622,36 @@ void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ DEF_GVEC_VFMA(vfma, 0) DEF_GVEC_VFMA(vfms, float_muladd_negate_c) +void HELPER(gvec_vftci32)(void *v1, const void *v2, CPUS390XState *env, + uint32_t desc) +{ + uint16_t i3 = extract32(simd_data(desc), 4, 12); + bool s = extract32(simd_data(desc), 3, 1); + int i, match = 0; + + for (i = 0; i < 4; i++) { + float32 a = s390_vec_read_float32(v2, i); + + if (float32_dcmask(env, a) & i3) { + match++; + s390_vec_write_element32(v1, i, -1u); + } else { + s390_vec_write_element32(v1, i, 0); + } + if (s) { + break; + } + } + + if (match == 4 || (s && match)) { + env->cc_op = 0; + } else if (match) { + env->cc_op = 1; + } else { + env->cc_op = 3; + } +} + void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env, uint32_t desc) { @@ -651,3 +681,20 @@ void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env, env->cc_op = 3; } } + +void HELPER(gvec_vftci128)(void *v1, const void *v2, CPUS390XState *env, + uint32_t desc) +{ + const float128 a = s390_vec_read_float128(v2); + uint16_t i3 = extract32(simd_data(desc), 4, 12); + + if (float128_dcmask(env, a) & i3) { + env->cc_op = 0; + s390_vec_write_element64(v1, 0, -1ull); + s390_vec_write_element64(v1, 1, -1ull); + } else { + env->cc_op = 3; + s390_vec_write_element64(v1, 0, 0); + s390_vec_write_element64(v1, 1, 0); + } +} -- cgit v1.1 From e257abc8de8011160fec3e85fcf54db9bc7ae2c6 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:32 +0200 Subject: s390x/tcg: Implement 32/128 bit for VECTOR FP MULTIPLY AND (ADD|SUBTRACT) Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-22-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 4 ++++ target/s390x/translate_vx.c.inc | 47 +++++++++++++++++++++++++++++++++++------ target/s390x/vec_fpu_helper.c | 44 +++++++++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index bae73b9..2366756 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -291,8 +291,12 @@ DEF_HELPER_FLAGS_4(gvec_vflr128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfma32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfma128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfms32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfms128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 765f75d..17d41b1 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2818,18 +2818,51 @@ static DisasJumpType op_vfma(DisasContext *s, DisasOps *o) { const uint8_t m5 = get_field(s, m5); const uint8_t fpf = get_field(s, m6); - gen_helper_gvec_4_ptr *fn; + gen_helper_gvec_4_ptr *fn = NULL; - if (fpf != FPF_LONG || extract32(m5, 0, 3)) { + if (s->fields.op2 == 0x8f) { + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfma32; + } + break; + case FPF_LONG: + fn = gen_helper_gvec_vfma64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfma128; + } + break; + default: + break; + } + } else { + switch (fpf) { + case FPF_SHORT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfms32; + } + break; + case FPF_LONG: + fn = gen_helper_gvec_vfms64; + break; + case FPF_EXT: + if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { + fn = gen_helper_gvec_vfms128; + } + break; + default: + break; + } + } + + if (!fn || extract32(m5, 0, 3)) { gen_program_exception(s, PGM_SPECIFICATION); return DISAS_NORETURN; } - if (s->fields.op2 == 0x8f) { - fn = gen_helper_gvec_vfma64; - } else { - fn = gen_helper_gvec_vfms64; - } gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), get_field(s, v4), cpu_env, m5, fn); return DISAS_NEXT; diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 6984f77..29ccc60 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -582,6 +582,30 @@ void HELPER(gvec_vflr128)(void *v1, const void *v2, CPUS390XState *env, s390_vec_write_float64(v1, 0, ret); } +static void vfma32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, + const S390Vector *v4, CPUS390XState *env, bool s, int flags, + uintptr_t retaddr) +{ + uint8_t vxc, vec_exc = 0; + S390Vector tmp = {}; + int i; + + for (i = 0; i < 4; i++) { + const float32 a = s390_vec_read_float32(v2, i); + const float32 b = s390_vec_read_float32(v3, i); + const float32 c = s390_vec_read_float32(v4, i); + float32 ret = float32_muladd(a, b, c, flags, &env->fpu_status); + + s390_vec_write_float32(&tmp, i, ret); + vxc = check_ieee_exc(env, i, false, &vec_exc); + if (s || vxc) { + break; + } + } + handle_ieee_exc(env, vxc, vec_exc, retaddr); + *v1 = tmp; +} + static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, const S390Vector *v4, CPUS390XState *env, bool s, int flags, uintptr_t retaddr) @@ -606,6 +630,22 @@ static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, *v1 = tmp; } +static void vfma128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, + const S390Vector *v4, CPUS390XState *env, bool s, int flags, + uintptr_t retaddr) +{ + const float128 a = s390_vec_read_float128(v2); + const float128 b = s390_vec_read_float128(v3); + const float128 c = s390_vec_read_float128(v4); + uint8_t vxc, vec_exc = 0; + float128 ret; + + ret = float128_muladd(a, b, c, flags, &env->fpu_status); + vxc = check_ieee_exc(env, 0, false, &vec_exc); + handle_ieee_exc(env, vxc, vec_exc, retaddr); + s390_vec_write_float128(v1, ret); +} + #define DEF_GVEC_VFMA_B(NAME, FLAGS, BITS) \ void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ const void *v4, CPUS390XState *env, \ @@ -617,7 +657,9 @@ void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ } #define DEF_GVEC_VFMA(NAME, FLAGS) \ - DEF_GVEC_VFMA_B(NAME, FLAGS, 64) + DEF_GVEC_VFMA_B(NAME, FLAGS, 32) \ + DEF_GVEC_VFMA_B(NAME, FLAGS, 64) \ + DEF_GVEC_VFMA_B(NAME, FLAGS, 128) DEF_GVEC_VFMA(vfma, 0) DEF_GVEC_VFMA(vfms, float_muladd_negate_c) -- cgit v1.1 From f02497306ec2efb8315f604597ddf8142f00336d Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:33 +0200 Subject: s390x/tcg: Implement VECTOR FP NEGATIVE MULTIPLY AND (ADD|SUBTRACT) Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-23-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 6 ++++++ target/s390x/insn-data.def | 4 ++++ target/s390x/translate_vx.c.inc | 39 +++++++++++++++++++++++++++++++++++++-- target/s390x/vec_fpu_helper.c | 2 ++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 2366756..913967c 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -297,6 +297,12 @@ DEF_HELPER_FLAGS_6(gvec_vfma128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, en DEF_HELPER_FLAGS_6(gvec_vfms32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfms128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfnma32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfnma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfnma128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfnms32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfnms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_vfnms128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_4(gvec_vfsq128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 1a3ae7e..19b02df 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1259,6 +1259,10 @@ F(0xe78f, VFMA, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC) /* VECTOR FP MULTIPLY AND SUBTRACT */ F(0xe78e, VFMS, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC) +/* VECTOR FP NEGATIVE MULTIPLY AND ADD */ + F(0xe79f, VFNMA, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC) +/* VECTOR FP NEGATIVE MULTIPLY AND SUBTRACT */ + F(0xe79e, VFNMS, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC) /* VECTOR FP PERFORM SIGN OPERATION */ F(0xe7cc, VFPSO, VRR_a, V, 0, 0, 0, 0, vfpso, 0, IF_VEC) /* VECTOR FP SQUARE ROOT */ diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 17d41b1..200d83e 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2820,7 +2820,8 @@ static DisasJumpType op_vfma(DisasContext *s, DisasOps *o) const uint8_t fpf = get_field(s, m6); gen_helper_gvec_4_ptr *fn = NULL; - if (s->fields.op2 == 0x8f) { + switch (s->fields.op2) { + case 0x8f: switch (fpf) { case FPF_SHORT: if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { @@ -2838,7 +2839,8 @@ static DisasJumpType op_vfma(DisasContext *s, DisasOps *o) default: break; } - } else { + break; + case 0x8e: switch (fpf) { case FPF_SHORT: if (s390_has_feat(S390_FEAT_VECTOR_ENH)) { @@ -2856,6 +2858,39 @@ static DisasJumpType op_vfma(DisasContext *s, DisasOps *o) default: break; } + break; + case 0x9f: + switch (fpf) { + case FPF_SHORT: + fn = gen_helper_gvec_vfnma32; + break; + case FPF_LONG: + fn = gen_helper_gvec_vfnma64; + break; + case FPF_EXT: + fn = gen_helper_gvec_vfnma128; + break; + default: + break; + } + break; + case 0x9e: + switch (fpf) { + case FPF_SHORT: + fn = gen_helper_gvec_vfnms32; + break; + case FPF_LONG: + fn = gen_helper_gvec_vfnms64; + break; + case FPF_EXT: + fn = gen_helper_gvec_vfnms128; + break; + default: + break; + } + break; + default: + g_assert_not_reached(); } if (!fn || extract32(m5, 0, 3)) { diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index 29ccc60..dc9bcc9 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -663,6 +663,8 @@ void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ DEF_GVEC_VFMA(vfma, 0) DEF_GVEC_VFMA(vfms, float_muladd_negate_c) +DEF_GVEC_VFMA(vfnma, float_muladd_negate_result) +DEF_GVEC_VFMA(vfnms, float_muladd_negate_c | float_muladd_negate_result) void HELPER(gvec_vftci32)(void *v1, const void *v2, CPUS390XState *env, uint32_t desc) -- cgit v1.1 From da4807527f3bda115606b4647fdc2f87928d0f15 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:34 +0200 Subject: s390x/tcg: Implement VECTOR FP (MAXIMUM|MINIMUM) For IEEE functions, we can reuse the softfloat implementations. For the other functions, implement it generically for 32bit/64bit/128bit - carefully taking care of all weird special cases according to the tables defined in the PoP. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-24-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 6 + target/s390x/insn-data.def | 4 + target/s390x/internal.h | 9 ++ target/s390x/translate_vx.c.inc | 44 ++++++ target/s390x/vec_fpu_helper.c | 328 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 391 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 913967c..ba045f5 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -291,6 +291,12 @@ DEF_HELPER_FLAGS_4(gvec_vflr128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_5(gvec_vfm128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfmax32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfmax64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfmax128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfmin32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfmin64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_vfmin128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) DEF_HELPER_FLAGS_6(gvec_vfma128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 19b02df..3e55942 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1253,6 +1253,10 @@ F(0xe7c4, VFLL, VRR_a, V, 0, 0, 0, 0, vfll, 0, IF_VEC) /* VECTOR FP LOAD ROUNDED */ F(0xe7c5, VFLR, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC) +/* VECTOR FP MAXIMUM */ + F(0xe7ef, VFMAX, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC) +/* VECTOR FP MINIMUM */ + F(0xe7ee, VFMIN, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC) /* VECTOR FP MULTIPLY */ F(0xe7e7, VFM, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC) /* VECTOR FP MULTIPLY AND ADD */ diff --git a/target/s390x/internal.h b/target/s390x/internal.h index 11515bb..d62dfc4 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -288,6 +288,15 @@ uint8_t s390_softfloat_exc_to_ieee(unsigned int exc); int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3); void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode); int float_comp_to_cc(CPUS390XState *env, int float_compare); + +#define DCMASK_ZERO 0x0c00 +#define DCMASK_NORMAL 0x0300 +#define DCMASK_SUBNORMAL 0x00c0 +#define DCMASK_INFINITY 0x0030 +#define DCMASK_QUIET_NAN 0x000c +#define DCMASK_SIGNALING_NAN 0x0003 +#define DCMASK_NAN 0x000f +#define DCMASK_NEGATIVE 0x0555 uint16_t float32_dcmask(CPUS390XState *env, float32 f1); uint16_t float64_dcmask(CPUS390XState *env, float64 f1); uint16_t float128_dcmask(CPUS390XState *env, float128 f1); diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc index 200d83e..a9d51b1 100644 --- a/target/s390x/translate_vx.c.inc +++ b/target/s390x/translate_vx.c.inc @@ -2814,6 +2814,50 @@ static DisasJumpType op_vfll(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_vfmax(DisasContext *s, DisasOps *o) +{ + const uint8_t fpf = get_field(s, m4); + const uint8_t m6 = get_field(s, m6); + const uint8_t m5 = get_field(s, m5); + gen_helper_gvec_3_ptr *fn; + + if (m6 == 5 || m6 == 6 || m6 == 7 || m6 > 13) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + switch (fpf) { + case FPF_SHORT: + if (s->fields.op2 == 0xef) { + fn = gen_helper_gvec_vfmax32; + } else { + fn = gen_helper_gvec_vfmin32; + } + break; + case FPF_LONG: + if (s->fields.op2 == 0xef) { + fn = gen_helper_gvec_vfmax64; + } else { + fn = gen_helper_gvec_vfmin64; + } + break; + case FPF_EXT: + if (s->fields.op2 == 0xef) { + fn = gen_helper_gvec_vfmax128; + } else { + fn = gen_helper_gvec_vfmin128; + } + break; + default: + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3), + cpu_env, deposit32(m5, 4, 4, m6), fn); + return DISAS_NEXT; +} + static DisasJumpType op_vfma(DisasContext *s, DisasOps *o) { const uint8_t m5 = get_field(s, m5); diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index dc9bcc9..8e2b274 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -742,3 +742,331 @@ void HELPER(gvec_vftci128)(void *v1, const void *v2, CPUS390XState *env, s390_vec_write_element64(v1, 1, 0); } } + +typedef enum S390MinMaxType { + S390_MINMAX_TYPE_IEEE = 0, + S390_MINMAX_TYPE_JAVA, + S390_MINMAX_TYPE_C_MACRO, + S390_MINMAX_TYPE_CPP, + S390_MINMAX_TYPE_F, +} S390MinMaxType; + +typedef enum S390MinMaxRes { + S390_MINMAX_RES_MINMAX = 0, + S390_MINMAX_RES_A, + S390_MINMAX_RES_B, + S390_MINMAX_RES_SILENCE_A, + S390_MINMAX_RES_SILENCE_B, +} S390MinMaxRes; + +static S390MinMaxRes vfmin_res(uint16_t dcmask_a, uint16_t dcmask_b, + S390MinMaxType type, float_status *s) +{ + const bool neg_a = dcmask_a & DCMASK_NEGATIVE; + const bool nan_a = dcmask_a & DCMASK_NAN; + const bool nan_b = dcmask_b & DCMASK_NAN; + + g_assert(type > S390_MINMAX_TYPE_IEEE && type <= S390_MINMAX_TYPE_F); + + if (unlikely((dcmask_a | dcmask_b) & DCMASK_NAN)) { + const bool sig_a = dcmask_a & DCMASK_SIGNALING_NAN; + const bool sig_b = dcmask_b & DCMASK_SIGNALING_NAN; + + if ((dcmask_a | dcmask_b) & DCMASK_SIGNALING_NAN) { + s->float_exception_flags |= float_flag_invalid; + } + switch (type) { + case S390_MINMAX_TYPE_JAVA: + if (sig_a) { + return S390_MINMAX_RES_SILENCE_A; + } else if (sig_b) { + return S390_MINMAX_RES_SILENCE_B; + } + return nan_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B; + case S390_MINMAX_TYPE_F: + return nan_b ? S390_MINMAX_RES_A : S390_MINMAX_RES_B; + case S390_MINMAX_TYPE_C_MACRO: + s->float_exception_flags |= float_flag_invalid; + return S390_MINMAX_RES_B; + case S390_MINMAX_TYPE_CPP: + s->float_exception_flags |= float_flag_invalid; + return S390_MINMAX_RES_A; + default: + g_assert_not_reached(); + } + } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) { + switch (type) { + case S390_MINMAX_TYPE_JAVA: + return neg_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B; + case S390_MINMAX_TYPE_C_MACRO: + return S390_MINMAX_RES_B; + case S390_MINMAX_TYPE_F: + return !neg_a ? S390_MINMAX_RES_B : S390_MINMAX_RES_A; + case S390_MINMAX_TYPE_CPP: + return S390_MINMAX_RES_A; + default: + g_assert_not_reached(); + } + } + return S390_MINMAX_RES_MINMAX; +} + +static S390MinMaxRes vfmax_res(uint16_t dcmask_a, uint16_t dcmask_b, + S390MinMaxType type, float_status *s) +{ + g_assert(type > S390_MINMAX_TYPE_IEEE && type <= S390_MINMAX_TYPE_F); + + if (unlikely((dcmask_a | dcmask_b) & DCMASK_NAN)) { + const bool sig_a = dcmask_a & DCMASK_SIGNALING_NAN; + const bool sig_b = dcmask_b & DCMASK_SIGNALING_NAN; + const bool nan_a = dcmask_a & DCMASK_NAN; + const bool nan_b = dcmask_b & DCMASK_NAN; + + if ((dcmask_a | dcmask_b) & DCMASK_SIGNALING_NAN) { + s->float_exception_flags |= float_flag_invalid; + } + switch (type) { + case S390_MINMAX_TYPE_JAVA: + if (sig_a) { + return S390_MINMAX_RES_SILENCE_A; + } else if (sig_b) { + return S390_MINMAX_RES_SILENCE_B; + } + return nan_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B; + case S390_MINMAX_TYPE_F: + return nan_b ? S390_MINMAX_RES_A : S390_MINMAX_RES_B; + case S390_MINMAX_TYPE_C_MACRO: + s->float_exception_flags |= float_flag_invalid; + return S390_MINMAX_RES_B; + case S390_MINMAX_TYPE_CPP: + s->float_exception_flags |= float_flag_invalid; + return S390_MINMAX_RES_A; + default: + g_assert_not_reached(); + } + } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) { + const bool neg_a = dcmask_a & DCMASK_NEGATIVE; + + switch (type) { + case S390_MINMAX_TYPE_JAVA: + case S390_MINMAX_TYPE_F: + return neg_a ? S390_MINMAX_RES_B : S390_MINMAX_RES_A; + case S390_MINMAX_TYPE_C_MACRO: + return S390_MINMAX_RES_B; + case S390_MINMAX_TYPE_CPP: + return S390_MINMAX_RES_A; + default: + g_assert_not_reached(); + } + } + return S390_MINMAX_RES_MINMAX; +} + +static S390MinMaxRes vfminmax_res(uint16_t dcmask_a, uint16_t dcmask_b, + S390MinMaxType type, bool is_min, + float_status *s) +{ + return is_min ? vfmin_res(dcmask_a, dcmask_b, type, s) : + vfmax_res(dcmask_a, dcmask_b, type, s); +} + +static void vfminmax32(S390Vector *v1, const S390Vector *v2, + const S390Vector *v3, CPUS390XState *env, + S390MinMaxType type, bool is_min, bool is_abs, bool se, + uintptr_t retaddr) +{ + float_status *s = &env->fpu_status; + uint8_t vxc, vec_exc = 0; + S390Vector tmp = {}; + int i; + + for (i = 0; i < 4; i++) { + float32 a = s390_vec_read_float32(v2, i); + float32 b = s390_vec_read_float32(v3, i); + float32 result; + + if (type != S390_MINMAX_TYPE_IEEE) { + S390MinMaxRes res; + + if (is_abs) { + a = float32_abs(a); + b = float32_abs(b); + } + + res = vfminmax_res(float32_dcmask(env, a), float32_dcmask(env, b), + type, is_min, s); + switch (res) { + case S390_MINMAX_RES_MINMAX: + result = is_min ? float32_min(a, b, s) : float32_max(a, b, s); + break; + case S390_MINMAX_RES_A: + result = a; + break; + case S390_MINMAX_RES_B: + result = b; + break; + case S390_MINMAX_RES_SILENCE_A: + result = float32_silence_nan(a, s); + break; + case S390_MINMAX_RES_SILENCE_B: + result = float32_silence_nan(b, s); + break; + default: + g_assert_not_reached(); + } + } else if (!is_abs) { + result = is_min ? float32_minnum(a, b, &env->fpu_status) : + float32_maxnum(a, b, &env->fpu_status); + } else { + result = is_min ? float32_minnummag(a, b, &env->fpu_status) : + float32_maxnummag(a, b, &env->fpu_status); + } + + s390_vec_write_float32(&tmp, i, result); + vxc = check_ieee_exc(env, i, false, &vec_exc); + if (se || vxc) { + break; + } + } + handle_ieee_exc(env, vxc, vec_exc, retaddr); + *v1 = tmp; +} + +static void vfminmax64(S390Vector *v1, const S390Vector *v2, + const S390Vector *v3, CPUS390XState *env, + S390MinMaxType type, bool is_min, bool is_abs, bool se, + uintptr_t retaddr) +{ + float_status *s = &env->fpu_status; + uint8_t vxc, vec_exc = 0; + S390Vector tmp = {}; + int i; + + for (i = 0; i < 2; i++) { + float64 a = s390_vec_read_float64(v2, i); + float64 b = s390_vec_read_float64(v3, i); + float64 result; + + if (type != S390_MINMAX_TYPE_IEEE) { + S390MinMaxRes res; + + if (is_abs) { + a = float64_abs(a); + b = float64_abs(b); + } + + res = vfminmax_res(float64_dcmask(env, a), float64_dcmask(env, b), + type, is_min, s); + switch (res) { + case S390_MINMAX_RES_MINMAX: + result = is_min ? float64_min(a, b, s) : float64_max(a, b, s); + break; + case S390_MINMAX_RES_A: + result = a; + break; + case S390_MINMAX_RES_B: + result = b; + break; + case S390_MINMAX_RES_SILENCE_A: + result = float64_silence_nan(a, s); + break; + case S390_MINMAX_RES_SILENCE_B: + result = float64_silence_nan(b, s); + break; + default: + g_assert_not_reached(); + } + } else if (!is_abs) { + result = is_min ? float64_minnum(a, b, &env->fpu_status) : + float64_maxnum(a, b, &env->fpu_status); + } else { + result = is_min ? float64_minnummag(a, b, &env->fpu_status) : + float64_maxnummag(a, b, &env->fpu_status); + } + + s390_vec_write_float64(&tmp, i, result); + vxc = check_ieee_exc(env, i, false, &vec_exc); + if (se || vxc) { + break; + } + } + handle_ieee_exc(env, vxc, vec_exc, retaddr); + *v1 = tmp; +} + +static void vfminmax128(S390Vector *v1, const S390Vector *v2, + const S390Vector *v3, CPUS390XState *env, + S390MinMaxType type, bool is_min, bool is_abs, bool se, + uintptr_t retaddr) +{ + float128 a = s390_vec_read_float128(v2); + float128 b = s390_vec_read_float128(v3); + float_status *s = &env->fpu_status; + uint8_t vxc, vec_exc = 0; + float128 result; + + if (type != S390_MINMAX_TYPE_IEEE) { + S390MinMaxRes res; + + if (is_abs) { + a = float128_abs(a); + b = float128_abs(b); + } + + res = vfminmax_res(float128_dcmask(env, a), float128_dcmask(env, b), + type, is_min, s); + switch (res) { + case S390_MINMAX_RES_MINMAX: + result = is_min ? float128_min(a, b, s) : float128_max(a, b, s); + break; + case S390_MINMAX_RES_A: + result = a; + break; + case S390_MINMAX_RES_B: + result = b; + break; + case S390_MINMAX_RES_SILENCE_A: + result = float128_silence_nan(a, s); + break; + case S390_MINMAX_RES_SILENCE_B: + result = float128_silence_nan(b, s); + break; + default: + g_assert_not_reached(); + } + } else if (!is_abs) { + result = is_min ? float128_minnum(a, b, &env->fpu_status) : + float128_maxnum(a, b, &env->fpu_status); + } else { + result = is_min ? float128_minnummag(a, b, &env->fpu_status) : + float128_maxnummag(a, b, &env->fpu_status); + } + + vxc = check_ieee_exc(env, 0, false, &vec_exc); + handle_ieee_exc(env, vxc, vec_exc, retaddr); + s390_vec_write_float128(v1, result); +} + +#define DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, BITS) \ +void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3, \ + CPUS390XState *env, uint32_t desc) \ +{ \ + const bool se = extract32(simd_data(desc), 3, 1); \ + uint8_t type = extract32(simd_data(desc), 4, 4); \ + bool is_abs = false; \ + \ + if (type >= 8) { \ + is_abs = true; \ + type -= 8; \ + } \ + \ + vfminmax##BITS(v1, v2, v3, env, type, IS_MIN, is_abs, se, GETPC()); \ +} + +#define DEF_GVEC_VFMINMAX(NAME, IS_MIN) \ + DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 32) \ + DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 64) \ + DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 128) + +DEF_GVEC_VFMINMAX(vfmax, false) +DEF_GVEC_VFMINMAX(vfmin, true) -- cgit v1.1 From da215c239439539ffcbc0f79fba7b867eb3d8030 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:35 +0200 Subject: linux-user: elf: s390x: Prepare for Vector enhancements facility Let's check for S390_FEAT_VECTOR_ENH and set HWCAP_S390_VXRS_EXT accordingly. Add all missing HWCAP defined in upstream Linux. Cc: Laurent Vivier Acked-by: Laurent Vivier Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-25-david@redhat.com> Signed-off-by: Cornelia Huck --- include/elf.h | 7 +++++++ linux-user/elfload.c | 1 + 2 files changed, 8 insertions(+) diff --git a/include/elf.h b/include/elf.h index 033bcc9..811bf4a 100644 --- a/include/elf.h +++ b/include/elf.h @@ -605,6 +605,13 @@ typedef struct { #define HWCAP_S390_HIGH_GPRS 512 #define HWCAP_S390_TE 1024 #define HWCAP_S390_VXRS 2048 +#define HWCAP_S390_VXRS_BCD 4096 +#define HWCAP_S390_VXRS_EXT 8192 +#define HWCAP_S390_GS 16384 +#define HWCAP_S390_VXRS_EXT2 32768 +#define HWCAP_S390_VXRS_PDE 65536 +#define HWCAP_S390_SORT 131072 +#define HWCAP_S390_DFLT 262144 /* M68K specific definitions. */ /* We use the top 24 bits to encode information about the diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 17ab06f..4b01723 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1376,6 +1376,7 @@ static uint32_t get_elf_hwcap(void) hwcap |= HWCAP_S390_ETF3EH; } GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS); + GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT); return hwcap; } -- cgit v1.1 From 8a9b7ed32d491693ed57d025d8a7d26f7a6a7d14 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:36 +0200 Subject: s390x/tcg: We support Vector enhancements facility Everything is wired up and all new instructions are implemented. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-26-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/gen-features.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index a6ec918..219b1f9 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -720,6 +720,7 @@ static uint16_t qemu_MAX[] = { S390_FEAT_INSTRUCTION_EXEC_PROT, S390_FEAT_MISC_INSTRUCTION_EXT2, S390_FEAT_MSA_EXT_8, + S390_FEAT_VECTOR_ENH, }; /****** END FEATURE DEFS ******/ -- cgit v1.1 From 463e50da8bf81bb3eff108e4bdd8fa7aadb12f4c Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 8 Jun 2021 11:23:37 +0200 Subject: s390x/cpumodel: Bump up QEMU model to a stripped-down IBM z14 GA2 TCG implements everything we need to run basic z14 OS+software. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20210608092337.12221-27-david@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 3 +++ target/s390x/cpu_models.c | 4 ++-- target/s390x/gen-features.c | 15 +++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 7af27ca..e4b18ae 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -802,7 +802,10 @@ DEFINE_CCW_MACHINE(6_1, "6.1", true); static void ccw_machine_6_0_instance_options(MachineState *machine) { + static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V6_0 }; + ccw_machine_6_1_instance_options(machine); + s390_set_qemu_cpu_model(0x2964, 13, 2, qemu_cpu_feat); } static void ccw_machine_6_0_class_options(MachineClass *mc) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 050dcf2..94090a6 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -90,8 +90,8 @@ static S390CPUDef s390_cpu_defs[] = { CPUDEF_INIT(0x8562, 15, 1, 47, 0x08000000U, "gen15b", "IBM z15 T02 GA1"), }; -#define QEMU_MAX_CPU_TYPE 0x2964 -#define QEMU_MAX_CPU_GEN 13 +#define QEMU_MAX_CPU_TYPE 0x3906 +#define QEMU_MAX_CPU_GEN 14 #define QEMU_MAX_CPU_EC_GA 2 static const S390FeatInit qemu_max_cpu_feat_init = { S390_FEAT_LIST_QEMU_MAX }; static S390FeatBitmap qemu_max_cpu_feat; diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 219b1f9..242c95e 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -706,23 +706,25 @@ static uint16_t qemu_V4_1[] = { S390_FEAT_VECTOR, }; -static uint16_t qemu_LATEST[] = { +static uint16_t qemu_V6_0[] = { S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2, S390_FEAT_ESOP, }; -/* add all new definitions before this point */ -static uint16_t qemu_MAX[] = { - /* generates a dependency warning, leave it out for now */ - S390_FEAT_MSA_EXT_5, - /* features introduced after the z13 */ +static uint16_t qemu_LATEST[] = { S390_FEAT_INSTRUCTION_EXEC_PROT, S390_FEAT_MISC_INSTRUCTION_EXT2, S390_FEAT_MSA_EXT_8, S390_FEAT_VECTOR_ENH, }; +/* add all new definitions before this point */ +static uint16_t qemu_MAX[] = { + /* generates a dependency warning, leave it out for now */ + S390_FEAT_MSA_EXT_5, +}; + /****** END FEATURE DEFS ******/ #define _YEARS "2016" @@ -839,6 +841,7 @@ static FeatGroupDefSpec QemuFeatDef[] = { QEMU_FEAT_INITIALIZER(V3_1), QEMU_FEAT_INITIALIZER(V4_0), QEMU_FEAT_INITIALIZER(V4_1), + QEMU_FEAT_INITIALIZER(V6_0), QEMU_FEAT_INITIALIZER(LATEST), QEMU_FEAT_INITIALIZER(MAX), }; -- cgit v1.1 From 3af448b38677e7be5ccda6a65e06150abd1005b6 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 25 May 2021 16:20:32 +0200 Subject: configure: Check whether we can compile the s390-ccw bios with -msoft-float The -msoft-float switch is not available in older versions of Clang. Since we rely on the compiler to not generate floating point instructions unexpectedly, we block those old compilers now via a test in the configure script. Note that for some weird reasons, the Clang compiler only complains about the missing soft-float support if no other flags are passed via "-Wl,..." to the linker. So we have to use "compile_object" instead of "compile_prog" for this check. Signed-off-by: Thomas Huth Message-Id: <20210525142032.156989-1-thuth@redhat.com> Signed-off-by: Cornelia Huck --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 262ab71..931f6ac 100755 --- a/configure +++ b/configure @@ -5424,7 +5424,7 @@ if test "$cpu" = "s390x" ; then write_c_skeleton compile_prog "-march=z900" "" has_z900=$? - if [ $has_z900 = 0 ] || compile_prog "-march=z10" ""; then + if [ $has_z900 = 0 ] || compile_object "-march=z10 -msoft-float -Werror"; then if [ $has_z900 != 0 ]; then echo "WARNING: Your compiler does not support the z900!" echo " The s390-ccw bios will only work with guest CPUs >= z10." -- cgit v1.1 From e2b2a8649bcd4769f453497b2abffbe44c7f86ad Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 14 Jun 2021 20:07:40 -0700 Subject: target/s390x: Expose load_psw and get_psw_mask to cpu.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename to s390_cpu_set_psw and s390_cpu_get_psw_mask at the same time. Adjust so that they compile for user-only. Signed-off-by: Richard Henderson Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Tested-by: jonathan.albrecht Tested-by: Message-Id: <20210615030744.1252385-2-richard.henderson@linaro.org> Signed-off-by: Cornelia Huck --- target/s390x/cc_helper.c | 2 +- target/s390x/cpu.h | 3 ++ target/s390x/excp_helper.c | 28 ++++++++------- target/s390x/helper.c | 89 +++++++++++++++++++++++++--------------------- target/s390x/internal.h | 5 --- target/s390x/sigp.c | 3 +- 6 files changed, 69 insertions(+), 61 deletions(-) diff --git a/target/s390x/cc_helper.c b/target/s390x/cc_helper.c index e7039d0..e7a74d6 100644 --- a/target/s390x/cc_helper.c +++ b/target/s390x/cc_helper.c @@ -509,7 +509,7 @@ uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, #ifndef CONFIG_USER_ONLY void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) { - load_psw(env, mask, addr); + s390_cpu_set_psw(env, mask, addr); cpu_loop_exit(env_cpu(env)); } diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 2464d40..b26ae8f 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -845,6 +845,9 @@ int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf, int s390_cpu_restart(S390CPU *cpu); void s390_init_sigp(void); +/* helper.c */ +void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); +uint64_t s390_cpu_get_psw_mask(CPUS390XState *env); /* outside of target/s390x/ */ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index 20625c2..9c36142 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -252,7 +252,7 @@ static void do_program_interrupt(CPUS390XState *env) lowcore->pgm_ilen = cpu_to_be16(ilen); lowcore->pgm_code = cpu_to_be16(env->int_pgm_code); - lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->program_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env)); lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->program_new_psw.mask); addr = be64_to_cpu(lowcore->program_new_psw.addr); @@ -260,7 +260,7 @@ static void do_program_interrupt(CPUS390XState *env) cpu_unmap_lowcore(lowcore); - load_psw(env, mask, addr); + s390_cpu_set_psw(env, mask, addr); } static void do_svc_interrupt(CPUS390XState *env) @@ -272,14 +272,14 @@ static void do_svc_interrupt(CPUS390XState *env) lowcore->svc_code = cpu_to_be16(env->int_svc_code); lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen); - lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->svc_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env)); lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen); mask = be64_to_cpu(lowcore->svc_new_psw.mask); addr = be64_to_cpu(lowcore->svc_new_psw.addr); cpu_unmap_lowcore(lowcore); - load_psw(env, mask, addr); + s390_cpu_set_psw(env, mask, addr); /* When a PER event is pending, the PER exception has to happen immediately after the SERVICE CALL one. */ @@ -348,12 +348,12 @@ static void do_ext_interrupt(CPUS390XState *env) mask = be64_to_cpu(lowcore->external_new_psw.mask); addr = be64_to_cpu(lowcore->external_new_psw.addr); - lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->external_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env)); lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); cpu_unmap_lowcore(lowcore); - load_psw(env, mask, addr); + s390_cpu_set_psw(env, mask, addr); } static void do_io_interrupt(CPUS390XState *env) @@ -373,7 +373,7 @@ static void do_io_interrupt(CPUS390XState *env) lowcore->subchannel_nr = cpu_to_be16(io->nr); lowcore->io_int_parm = cpu_to_be32(io->parm); lowcore->io_int_word = cpu_to_be32(io->word); - lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->io_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env)); lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->io_new_psw.mask); addr = be64_to_cpu(lowcore->io_new_psw.addr); @@ -381,7 +381,7 @@ static void do_io_interrupt(CPUS390XState *env) cpu_unmap_lowcore(lowcore); g_free(io); - load_psw(env, mask, addr); + s390_cpu_set_psw(env, mask, addr); } typedef struct MchkExtSaveArea { @@ -457,14 +457,14 @@ static void do_mchk_interrupt(CPUS390XState *env) lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8); lowcore->mcic = cpu_to_be64(mcic); - lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->mcck_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env)); lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->mcck_new_psw.mask); addr = be64_to_cpu(lowcore->mcck_new_psw.addr); cpu_unmap_lowcore(lowcore); - load_psw(env, mask, addr); + s390_cpu_set_psw(env, mask, addr); } void s390_cpu_do_interrupt(CPUState *cs) @@ -592,9 +592,11 @@ void s390x_cpu_debug_excp_handler(CPUState *cs) and MVCS instrutions are not used. */ env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46; - /* Remove all watchpoints to re-execute the code. A PER exception - will be triggered, it will call load_psw which will recompute - the watchpoints. */ + /* + * Remove all watchpoints to re-execute the code. A PER exception + * will be triggered, it will call s390_cpu_set_psw which will + * recompute the watchpoints. + */ cpu_watchpoint_remove_all(cs, BP_CPU); cpu_loop_exit_noexc(cs); } diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 7678994..d311903 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -104,44 +104,6 @@ void s390_handle_wait(S390CPU *cpu) } } -void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) -{ - uint64_t old_mask = env->psw.mask; - - env->psw.addr = addr; - env->psw.mask = mask; - - /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */ - if (!tcg_enabled()) { - return; - } - env->cc_op = (mask >> 44) & 3; - - if ((old_mask ^ mask) & PSW_MASK_PER) { - s390_cpu_recompute_watchpoints(env_cpu(env)); - } - - if (mask & PSW_MASK_WAIT) { - s390_handle_wait(env_archcpu(env)); - } -} - -uint64_t get_psw_mask(CPUS390XState *env) -{ - uint64_t r = env->psw.mask; - - if (tcg_enabled()) { - env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, - env->cc_vr); - - r &= ~PSW_MASK_CC; - assert(!(env->cc_op & ~3)); - r |= (uint64_t)env->cc_op << 44; - } - - return r; -} - LowCore *cpu_map_lowcore(CPUS390XState *env) { LowCore *lowcore; @@ -168,7 +130,7 @@ void do_restart_interrupt(CPUS390XState *env) lowcore = cpu_map_lowcore(env); - lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->restart_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env)); lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->restart_new_psw.mask); addr = be64_to_cpu(lowcore->restart_new_psw.addr); @@ -176,7 +138,7 @@ void do_restart_interrupt(CPUS390XState *env) cpu_unmap_lowcore(lowcore); env->pending_int &= ~INTERRUPT_RESTART; - load_psw(env, mask, addr); + s390_cpu_set_psw(env, mask, addr); } void s390_cpu_recompute_watchpoints(CPUState *cs) @@ -266,7 +228,7 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch) sa->grs[i] = cpu_to_be64(cpu->env.regs[i]); } sa->psw.addr = cpu_to_be64(cpu->env.psw.addr); - sa->psw.mask = cpu_to_be64(get_psw_mask(&cpu->env)); + sa->psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(&cpu->env)); sa->prefix = cpu_to_be32(cpu->env.psa); sa->fpc = cpu_to_be32(cpu->env.fpc); sa->todpr = cpu_to_be32(cpu->env.todpr); @@ -323,8 +285,53 @@ int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len) cpu_physical_memory_unmap(sa, len, 1, len); return 0; } +#else +/* For user-only, tcg is always enabled. */ +#define tcg_enabled() true #endif /* CONFIG_USER_ONLY */ +void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) +{ +#ifndef CONFIG_USER_ONLY + uint64_t old_mask = env->psw.mask; +#endif + + env->psw.addr = addr; + env->psw.mask = mask; + + /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */ + if (!tcg_enabled()) { + return; + } + env->cc_op = (mask >> 44) & 3; + +#ifndef CONFIG_USER_ONLY + if ((old_mask ^ mask) & PSW_MASK_PER) { + s390_cpu_recompute_watchpoints(env_cpu(env)); + } + + if (mask & PSW_MASK_WAIT) { + s390_handle_wait(env_archcpu(env)); + } +#endif +} + +uint64_t s390_cpu_get_psw_mask(CPUS390XState *env) +{ + uint64_t r = env->psw.mask; + + if (tcg_enabled()) { + env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, + env->cc_vr); + + r &= ~PSW_MASK_CC; + assert(!(env->cc_op & ~3)); + r |= (uint64_t)env->cc_op << 44; + } + + return r; +} + void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags) { S390CPU *cpu = S390_CPU(cs); diff --git a/target/s390x/internal.h b/target/s390x/internal.h index d62dfc4..9256275 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -235,10 +235,6 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, const char *cc_name(enum cc_op cc_op); uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr); -#ifndef CONFIG_USER_ONLY -void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); -#endif /* CONFIG_USER_ONLY */ - /* cpu.c */ #ifndef CONFIG_USER_ONLY @@ -312,7 +308,6 @@ void s390_cpu_gdb_init(CPUState *cs); void s390_cpu_dump_state(CPUState *cpu, FILE *f, int flags); void do_restart_interrupt(CPUS390XState *env); #ifndef CONFIG_USER_ONLY -uint64_t get_psw_mask(CPUS390XState *env); void s390_cpu_recompute_watchpoints(CPUState *cs); void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c index c604f17..c2d5cdf 100644 --- a/target/s390x/sigp.c +++ b/target/s390x/sigp.c @@ -235,7 +235,8 @@ static void sigp_restart(CPUState *cs, run_on_cpu_data arg) cpu_synchronize_state(cs); /* * Set OPERATING (and unhalting) before loading the restart PSW. - * load_psw() will then properly halt the CPU again if necessary (TCG). + * s390_cpu_set_psw() will then properly halt the CPU again if + * necessary (TCG). */ s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); do_restart_interrupt(&cpu->env); -- cgit v1.1 From 3c11c2ebb062ffb5d7dcad44ab0fb60505ad5cac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 14 Jun 2021 20:07:41 -0700 Subject: target/s390x: Do not modify cpu state in s390_cpu_get_psw_mask We want to use this function for debugging, and debug should not modify cpu state (even non-architectural cpu state) lest we introduce heisenbugs. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Tested-by: jonathan.albrecht Tested-by: Message-Id: <20210615030744.1252385-3-richard.henderson@linaro.org> Signed-off-by: Cornelia Huck --- target/s390x/helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/s390x/helper.c b/target/s390x/helper.c index d311903..559fc35 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -321,12 +321,12 @@ uint64_t s390_cpu_get_psw_mask(CPUS390XState *env) uint64_t r = env->psw.mask; if (tcg_enabled()) { - env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, - env->cc_vr); + uint64_t cc = calc_cc(env, env->cc_op, env->cc_src, + env->cc_dst, env->cc_vr); + assert(cc <= 3); r &= ~PSW_MASK_CC; - assert(!(env->cc_op & ~3)); - r |= (uint64_t)env->cc_op << 44; + r |= cc << 44; } return r; -- cgit v1.1 From d09e6c921301d4377c73e0bc9010b52f201862dd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 14 Jun 2021 20:07:42 -0700 Subject: target/s390x: Improve s390_cpu_dump_state vs cc_op Use s390_cpu_get_psw_mask so that we print the correct architectural value of psw.mask. Do not print cc_op unless tcg_enabled. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Tested-by: jonathan.albrecht Tested-by: Message-Id: <20210615030744.1252385-4-richard.henderson@linaro.org> Signed-off-by: Cornelia Huck --- target/s390x/helper.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 559fc35..1445b74 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -338,12 +338,14 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags) CPUS390XState *env = &cpu->env; int i; - if (env->cc_op > 3) { - qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %15s\n", - env->psw.mask, env->psw.addr, cc_name(env->cc_op)); + qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64, + s390_cpu_get_psw_mask(env), env->psw.addr); + if (!tcg_enabled()) { + qemu_fprintf(f, "\n"); + } else if (env->cc_op > 3) { + qemu_fprintf(f, " cc %15s\n", cc_name(env->cc_op)); } else { - qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %02x\n", - env->psw.mask, env->psw.addr, env->cc_op); + qemu_fprintf(f, " cc %02x\n", env->cc_op); } for (i = 0; i < 16; i++) { -- cgit v1.1 From deb60cc77b6743b65d1e830300b6d56ba538b103 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 14 Jun 2021 20:07:43 -0700 Subject: target/s390x: Use s390_cpu_{set_psw, get_psw_mask} in gdbstub No change in behaviour, as gdbstub was correctly written to install and extract the cc value. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Tested-by: jonathan.albrecht Tested-by: Message-Id: <20210615030744.1252385-5-richard.henderson@linaro.org> Signed-off-by: Cornelia Huck --- target/s390x/gdbstub.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c index d6fce5f..5b4e38a 100644 --- a/target/s390x/gdbstub.c +++ b/target/s390x/gdbstub.c @@ -31,18 +31,10 @@ int s390_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; - uint64_t val; - int cc_op; switch (n) { case S390_PSWM_REGNUM: - if (tcg_enabled()) { - cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, - env->cc_vr); - val = deposit64(env->psw.mask, 44, 2, cc_op); - return gdb_get_regl(mem_buf, val); - } - return gdb_get_regl(mem_buf, env->psw.mask); + return gdb_get_regl(mem_buf, s390_cpu_get_psw_mask(env)); case S390_PSWA_REGNUM: return gdb_get_regl(mem_buf, env->psw.addr); case S390_R0_REGNUM ... S390_R15_REGNUM: @@ -59,10 +51,7 @@ int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case S390_PSWM_REGNUM: - env->psw.mask = tmpl; - if (tcg_enabled()) { - env->cc_op = extract64(tmpl, 44, 2); - } + s390_cpu_set_psw(env, tmpl, env->psw.addr); break; case S390_PSWA_REGNUM: env->psw.addr = tmpl; -- cgit v1.1 From 10b81272b305da375c3c3e9ec86f2e35df702f2e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 14 Jun 2021 20:07:44 -0700 Subject: linux-user/s390x: Save and restore psw.mask properly At present, we're referencing env->psw.mask directly, which fails to ensure that env->cc_op is incorporated or updated. Use s390_cpu_{set_psw,get_psw_mask} to fix this. Mirror the kernel's cleaning of the psw.mask in save_sigregs and restore_sigregs. Ignore PSW_MASK_RI for now, as qemu does not support that. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Tested-by: jonathan.albrecht Tested-by: Message-Id: <20210615030744.1252385-6-richard.henderson@linaro.org> Signed-off-by: Cornelia Huck --- linux-user/s390x/signal.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index ef136da..bf8a8fb 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -112,15 +112,23 @@ get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size) return (sp - frame_size) & -8ul; } +#define PSW_USER_BITS (PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \ + PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_ASC_PRIMARY) +#define PSW_MASK_USER (PSW_MASK_ASC | PSW_MASK_CC | PSW_MASK_PM | \ + PSW_MASK_64 | PSW_MASK_32) + static void save_sigregs(CPUS390XState *env, target_sigregs *sregs) { + uint64_t psw_mask = s390_cpu_get_psw_mask(env); int i; /* * Copy a 'clean' PSW mask to the user to avoid leaking * information about whether PER is currently on. + * TODO: qemu does not support PSW_MASK_RI; it will never be set. */ - __put_user(env->psw.mask, &sregs->regs.psw.mask); + psw_mask = PSW_USER_BITS | (psw_mask & PSW_MASK_USER); + __put_user(psw_mask, &sregs->regs.psw.mask); __put_user(env->psw.addr, &sregs->regs.psw.addr); for (i = 0; i < 16; i++) { @@ -289,7 +297,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) { - target_ulong prev_addr; + uint64_t prev_addr, prev_mask, mask, addr; int i; for (i = 0; i < 16; i++) { @@ -297,9 +305,28 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) } prev_addr = env->psw.addr; - __get_user(env->psw.mask, &sc->regs.psw.mask); - __get_user(env->psw.addr, &sc->regs.psw.addr); - trace_user_s390x_restore_sigregs(env, env->psw.addr, prev_addr); + __get_user(mask, &sc->regs.psw.mask); + __get_user(addr, &sc->regs.psw.addr); + trace_user_s390x_restore_sigregs(env, addr, prev_addr); + + /* + * Use current psw.mask to preserve PER bit. + * TODO: + * if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI)) + * return -EINVAL; + * Simply do not allow it to be set in mask. + */ + prev_mask = s390_cpu_get_psw_mask(env); + mask = (prev_mask & ~PSW_MASK_USER) | (mask & PSW_MASK_USER); + /* Check for invalid user address space control. */ + if ((mask & PSW_MASK_ASC) == PSW_ASC_HOME) { + mask = (mask & ~PSW_MASK_ASC) | PSW_ASC_PRIMARY; + } + /* Check for invalid amode. */ + if (mask & PSW_MASK_64) { + mask |= PSW_MASK_32; + } + s390_cpu_set_psw(env, mask, addr); for (i = 0; i < 16; i++) { __get_user(env->aregs[i], &sc->regs.acrs[i]); -- cgit v1.1 From 3fdc622ad79636f3d7f8bed50a53bc28af1850e1 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Fri, 18 Jun 2021 01:25:34 +0200 Subject: s390x/css: Introduce an ESW struct The Interrupt Response Block is comprised of several other structures concatenated together, but only the 12-byte Subchannel-Status Word (SCSW) is defined as a proper struct. Everything else is a simple array of 32-bit words. Let's define a proper struct for the 20-byte Extended-Status Word (ESW) so that we can make good decisions about the sense data that would go into the ECW area for virtual vs passthrough devices. [CH: adapted ESW definition to build with mingw, as discussed] Signed-off-by: Eric Farman Message-Id: <20210617232537.1337506-2-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 19 +++++++++++++------ include/hw/s390x/ioinst.h | 12 +++++++++++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index bed46f5..2025507 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1335,6 +1335,14 @@ static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src) } } +static void copy_esw_to_guest(ESW *dest, const ESW *src) +{ + dest->word0 = cpu_to_be32(src->word0); + dest->erw = cpu_to_be32(src->erw); + dest->word2 = cpu_to_be64(src->word2); + dest->word4 = cpu_to_be32(src->word4); +} + IOInstEnding css_do_stsch(SubchDev *sch, SCHIB *schib) { int ret; @@ -1604,9 +1612,8 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src, const PMCW *pmcw, copy_scsw_to_guest(&dest->scsw, &src->scsw); - for (i = 0; i < ARRAY_SIZE(dest->esw); i++) { - dest->esw[i] = cpu_to_be32(src->esw[i]); - } + copy_esw_to_guest(&dest->esw, &src->esw); + for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) { dest->ecw[i] = cpu_to_be32(src->ecw[i]); } @@ -1655,9 +1662,9 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len) SCSW_CSTAT_CHN_CTRL_CHK | SCSW_CSTAT_INTF_CTRL_CHK)) { irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF; - irb.esw[0] = 0x04804000; + irb.esw.word0 = 0x04804000; } else { - irb.esw[0] = 0x00800000; + irb.esw.word0 = 0x00800000; } /* If a unit check is pending, copy sense data. */ if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) && @@ -1670,7 +1677,7 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len) for (i = 0; i < ARRAY_SIZE(irb.ecw); i++) { irb.ecw[i] = be32_to_cpu(irb.ecw[i]); } - irb.esw[1] = 0x01000000 | (sizeof(sch->sense_data) << 8); + irb.esw.erw = ESW_ERW_SENSE | (sizeof(sch->sense_data) << 8); } } /* Store the irb to the guest. */ diff --git a/include/hw/s390x/ioinst.h b/include/hw/s390x/ioinst.h index c6737a3..3771fff 100644 --- a/include/hw/s390x/ioinst.h +++ b/include/hw/s390x/ioinst.h @@ -123,10 +123,20 @@ typedef struct SCHIB { uint8_t mda[4]; } QEMU_PACKED SCHIB; +/* format-0 extended-status word */ +typedef struct ESW { + uint32_t word0; /* subchannel logout for format 0 */ + uint32_t erw; + uint64_t word2; /* failing-storage address for format 0 */ + uint32_t word4; /* secondary-CCW address for format 0 */ +} QEMU_PACKED ESW; + +#define ESW_ERW_SENSE 0x01000000 + /* interruption response block */ typedef struct IRB { SCSW scsw; - uint32_t esw[5]; + ESW esw; uint32_t ecw[8]; uint32_t emw[8]; } IRB; -- cgit v1.1 From 1b01dedaed41c2ca6129475c22b7b778b109fae8 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Fri, 18 Jun 2021 01:25:35 +0200 Subject: s390x/css: Split out the IRB sense data Let's move this logic into its own routine, so it can be reused later. Signed-off-by: Eric Farman Reviewed-by: Thomas Huth Message-Id: <20210617232537.1337506-3-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 2025507..26bd014 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1639,6 +1639,17 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src, const PMCW *pmcw, *irb_len = sizeof(*dest); } +static void build_irb_sense_data(SubchDev *sch, IRB *irb) +{ + int i; + + /* Attention: sense_data is already BE! */ + memcpy(irb->ecw, sch->sense_data, sizeof(sch->sense_data)); + for (i = 0; i < ARRAY_SIZE(irb->ecw); i++) { + irb->ecw[i] = be32_to_cpu(irb->ecw[i]); + } +} + int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len) { SCHIB *schib = &sch->curr_status; @@ -1669,14 +1680,8 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len) /* If a unit check is pending, copy sense data. */ if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) && (schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) { - int i; - irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL; - /* Attention: sense_data is already BE! */ - memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data)); - for (i = 0; i < ARRAY_SIZE(irb.ecw); i++) { - irb.ecw[i] = be32_to_cpu(irb.ecw[i]); - } + build_irb_sense_data(sch, &irb); irb.esw.erw = ESW_ERW_SENSE | (sizeof(sch->sense_data) << 8); } } -- cgit v1.1 From 0599a046acf1b625e97cef0aa702b5d86528c642 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Fri, 18 Jun 2021 01:25:36 +0200 Subject: s390x/css: Refactor IRB construction Currently, all subchannel types have "sense data" copied into the IRB.ECW space, and a couple flags enabled in the IRB.SCSW and IRB.ESW. But for passthrough (vfio-ccw) subchannels, this data isn't populated in the first place, so enabling those flags leads to unexpected behavior if the guest tries to process the sense data (zeros) in the IRB.ECW. Let's add a subchannel callback that builds these portions of the IRB, and move the existing code into a routine for those virtual subchannels. The passthrough subchannels will be able to piggy-back onto this later. Signed-off-by: Eric Farman Message-Id: <20210617232537.1337506-4-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/3270-ccw.c | 1 + hw/s390x/css.c | 45 +++++++++++++++++++++++++++++---------------- hw/s390x/virtio-ccw.c | 1 + include/hw/s390x/css.h | 2 ++ 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index 13e93d8..69e6783 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -129,6 +129,7 @@ static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp) EMULATED_CCW_3270_CHPID_TYPE); sch->do_subchannel_work = do_subchannel_work_virtual; sch->ccw_cb = emulated_ccw_3270_cb; + sch->irb_cb = build_irb_virtual; ck->init(dev, &err); if (err) { diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 26bd014..1a3aad5 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1650,6 +1650,30 @@ static void build_irb_sense_data(SubchDev *sch, IRB *irb) } } +void build_irb_virtual(SubchDev *sch, IRB *irb) +{ + SCHIB *schib = &sch->curr_status; + uint16_t stctl = schib->scsw.ctrl & SCSW_CTRL_MASK_STCTL; + + if (stctl & SCSW_STCTL_STATUS_PEND) { + if (schib->scsw.cstat & (SCSW_CSTAT_DATA_CHECK | + SCSW_CSTAT_CHN_CTRL_CHK | + SCSW_CSTAT_INTF_CTRL_CHK)) { + irb->scsw.flags |= SCSW_FLAGS_MASK_ESWF; + irb->esw.word0 = 0x04804000; + } else { + irb->esw.word0 = 0x00800000; + } + /* If a unit check is pending, copy sense data. */ + if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) && + (schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) { + irb->scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL; + build_irb_sense_data(sch, irb); + irb->esw.erw = ESW_ERW_SENSE | (sizeof(sch->sense_data) << 8); + } + } +} + int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len) { SCHIB *schib = &sch->curr_status; @@ -1668,23 +1692,12 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len) /* Copy scsw from current status. */ irb.scsw = schib->scsw; - if (stctl & SCSW_STCTL_STATUS_PEND) { - if (schib->scsw.cstat & (SCSW_CSTAT_DATA_CHECK | - SCSW_CSTAT_CHN_CTRL_CHK | - SCSW_CSTAT_INTF_CTRL_CHK)) { - irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF; - irb.esw.word0 = 0x04804000; - } else { - irb.esw.word0 = 0x00800000; - } - /* If a unit check is pending, copy sense data. */ - if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) && - (schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) { - irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL; - build_irb_sense_data(sch, &irb); - irb.esw.erw = ESW_ERW_SENSE | (sizeof(sch->sense_data) << 8); - } + + /* Build other IRB data, if necessary */ + if (sch->irb_cb) { + sch->irb_cb(sch, &irb); } + /* Store the irb to the guest. */ p = schib->pmcw; copy_irb_to_guest(target_irb, &irb, &p, irb_len); diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 220b9ef..d68888f 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -753,6 +753,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) sch->id.reserved = 0xff; sch->id.cu_type = VIRTIO_CCW_CU_TYPE; sch->do_subchannel_work = do_subchannel_work_virtual; + sch->irb_cb = build_irb_virtual; ccw_dev->sch = sch; dev->indicators = NULL; dev->revision = -1; diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index bba7593..7c23a13 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -138,6 +138,7 @@ struct SubchDev { int (*ccw_cb) (SubchDev *, CCW1); void (*disable_cb)(SubchDev *); IOInstEnding (*do_subchannel_work) (SubchDev *); + void (*irb_cb)(SubchDev *, IRB *); SenseId id; void *driver_data; }; @@ -215,6 +216,7 @@ void css_clear_sei_pending(void); IOInstEnding s390_ccw_cmd_request(SubchDev *sch); IOInstEnding do_subchannel_work_virtual(SubchDev *sub); IOInstEnding do_subchannel_work_passthrough(SubchDev *sub); +void build_irb_virtual(SubchDev *sch, IRB *irb); int s390_ccw_halt(SubchDev *sch); int s390_ccw_clear(SubchDev *sch); -- cgit v1.1 From c626710fc755628d0d6b88aab0514c9238a84522 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Fri, 18 Jun 2021 01:25:37 +0200 Subject: s390x/css: Add passthrough IRB Wire in the subchannel callback for building the IRB ESW and ECW space for passthrough devices, and copy the hardware's ESW into the IRB we are building. If the hardware presented concurrent sense, then copy that sense data into the IRB's ECW space. Signed-off-by: Eric Farman Message-Id: <20210617232537.1337506-5-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 16 +++++++++++++++- hw/s390x/s390-ccw.c | 1 + hw/vfio/ccw.c | 4 ++++ include/hw/s390x/css.h | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 1a3aad5..133ddea 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1335,7 +1335,7 @@ static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src) } } -static void copy_esw_to_guest(ESW *dest, const ESW *src) +void copy_esw_to_guest(ESW *dest, const ESW *src) { dest->word0 = cpu_to_be32(src->word0); dest->erw = cpu_to_be32(src->erw); @@ -1650,6 +1650,20 @@ static void build_irb_sense_data(SubchDev *sch, IRB *irb) } } +void build_irb_passthrough(SubchDev *sch, IRB *irb) +{ + /* Copy ESW from hardware */ + irb->esw = sch->esw; + + /* + * If (irb->esw.erw & ESW_ERW_SENSE) is true, then the contents + * of the ECW is sense data. If false, then it is model-dependent + * information. Either way, copy it into the IRB for the guest to + * read/decide what to do with. + */ + build_irb_sense_data(sch, irb); +} + void build_irb_virtual(SubchDev *sch, IRB *irb) { SCHIB *schib = &sch->curr_status; diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index c227c77..2fc8bb9 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -124,6 +124,7 @@ static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp) } sch->driver_data = cdev; sch->do_subchannel_work = do_subchannel_work_passthrough; + sch->irb_cb = build_irb_passthrough; ccw_dev->sch = sch; ret = css_sch_build_schib(sch, &cdev->hostid); diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 139a3d9..000992f 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -321,6 +321,7 @@ static void vfio_ccw_io_notifier_handler(void *opaque) SCHIB *schib = &sch->curr_status; SCSW s; IRB irb; + ESW esw; int size; if (!event_notifier_test_and_clear(&vcdev->io_notifier)) { @@ -371,6 +372,9 @@ static void vfio_ccw_io_notifier_handler(void *opaque) copy_scsw_to_guest(&s, &irb.scsw); schib->scsw = s; + copy_esw_to_guest(&esw, &irb.esw); + sch->esw = esw; + /* If a uint check is pending, copy sense data. */ if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) && (schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) { diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index 7c23a13..10ed1df 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -141,6 +141,7 @@ struct SubchDev { void (*irb_cb)(SubchDev *, IRB *); SenseId id; void *driver_data; + ESW esw; }; static inline void sch_gen_unit_exception(SubchDev *sch) @@ -202,6 +203,7 @@ int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id); unsigned int css_find_free_chpid(uint8_t cssid); uint16_t css_build_subchannel_id(SubchDev *sch); void copy_scsw_to_guest(SCSW *dest, const SCSW *src); +void copy_esw_to_guest(ESW *dest, const ESW *src); void css_inject_io_interrupt(SubchDev *sch); void css_reset(void); void css_reset_sch(SubchDev *sch); @@ -216,6 +218,7 @@ void css_clear_sei_pending(void); IOInstEnding s390_ccw_cmd_request(SubchDev *sch); IOInstEnding do_subchannel_work_virtual(SubchDev *sub); IOInstEnding do_subchannel_work_passthrough(SubchDev *sub); +void build_irb_passthrough(SubchDev *sch, IRB *irb); void build_irb_virtual(SubchDev *sch, IRB *irb); int s390_ccw_halt(SubchDev *sch); -- cgit v1.1