aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2021-06-08 11:23:30 +0200
committerCornelia Huck <cohuck@redhat.com>2021-06-21 08:48:21 +0200
commit390eeb35757ffeeed6811370625e11a1c6b1d565 (patch)
tree79f7250ce9fe513a736ce17c11acb55f8c7b12a1
parent9cbc8be05aebc339546ed36334cb9e7b01e74b99 (diff)
downloadqemu-390eeb35757ffeeed6811370625e11a1c6b1d565.zip
qemu-390eeb35757ffeeed6811370625e11a1c6b1d565.tar.gz
qemu-390eeb35757ffeeed6811370625e11a1c6b1d565.tar.bz2
s390x/tcg: Implement 32/128 bit for VECTOR FP PERFORM SIGN OPERATION
Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: David Hildenbrand <david@redhat.com> Message-Id: <20210608092337.12221-20-david@redhat.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
-rw-r--r--target/s390x/translate_vx.c.inc106
1 files 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;
}