aboutsummaryrefslogtreecommitdiff
path: root/target/s390x
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2019-04-11 10:00:25 +0200
committerDavid Hildenbrand <david@redhat.com>2019-05-17 10:54:13 +0200
commitff825c6d6408cc1deae408821b6fd9d1127cc70b (patch)
treed0894a608095b256ba5afffd167a31e88c794d0a /target/s390x
parent751a564f79b6a1f1fd7a7866af3a0af6468d9c4f (diff)
downloadqemu-ff825c6d6408cc1deae408821b6fd9d1127cc70b.zip
qemu-ff825c6d6408cc1deae408821b6fd9d1127cc70b.tar.gz
qemu-ff825c6d6408cc1deae408821b6fd9d1127cc70b.tar.bz2
s390x/tcg: Implement VECTOR COMPARE *
To carry out the comparison, we can reuse the existing gvec comparison function. In case the CC is to be computed, save the result vector and compute the CC lazily. The result is a vector consisting of all 1's for elements that matched and 0's for elements that didn't match. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: David Hildenbrand <david@redhat.com>
Diffstat (limited to 'target/s390x')
-rw-r--r--target/s390x/cc_helper.c17
-rw-r--r--target/s390x/helper.c1
-rw-r--r--target/s390x/insn-data.def6
-rw-r--r--target/s390x/internal.h1
-rw-r--r--target/s390x/translate.c1
-rw-r--r--target/s390x/translate_vx.inc.c28
6 files changed, 54 insertions, 0 deletions
diff --git a/target/s390x/cc_helper.c b/target/s390x/cc_helper.c
index 0e467bf..a00294f 100644
--- a/target/s390x/cc_helper.c
+++ b/target/s390x/cc_helper.c
@@ -402,6 +402,20 @@ static uint32_t cc_calc_lcbb(uint64_t dst)
return dst == 16 ? 0 : 3;
}
+static uint32_t cc_calc_vc(uint64_t low, uint64_t high)
+{
+ if (high == -1ull && low == -1ull) {
+ /* all elements match */
+ return 0;
+ } else if (high == 0 && low == 0) {
+ /* no elements match */
+ return 3;
+ } else {
+ /* some elements but not all match */
+ return 1;
+ }
+}
+
static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
uint64_t src, uint64_t dst, uint64_t vr)
{
@@ -514,6 +528,9 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
case CC_OP_LCBB:
r = cc_calc_lcbb(dst);
break;
+ case CC_OP_VC:
+ r = cc_calc_vc(src, dst);
+ break;
case CC_OP_NZ_F32:
r = set_cc_nz_f32(dst);
diff --git a/target/s390x/helper.c b/target/s390x/helper.c
index f957a2c..3c8f0a7 100644
--- a/target/s390x/helper.c
+++ b/target/s390x/helper.c
@@ -418,6 +418,7 @@ const char *cc_name(enum cc_op cc_op)
[CC_OP_SLA_64] = "CC_OP_SLA_64",
[CC_OP_FLOGR] = "CC_OP_FLOGR",
[CC_OP_LCBB] = "CC_OP_LCBB",
+ [CC_OP_VC] = "CC_OP_VC",
};
return cc_names[cc_op];
diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
index 52e398f..1d159cb 100644
--- a/target/s390x/insn-data.def
+++ b/target/s390x/insn-data.def
@@ -1078,6 +1078,12 @@
F(0xe7db, VEC, VRR_a, V, 0, 0, 0, 0, vec, cmps64, IF_VEC)
/* VECTOR ELEMENT COMPARE LOGICAL */
F(0xe7d9, VECL, VRR_a, V, 0, 0, 0, 0, vec, cmpu64, IF_VEC)
+/* VECTOR COMPARE EQUAL */
+ E(0xe7f8, VCEQ, VRR_b, V, 0, 0, 0, 0, vc, 0, TCG_COND_EQ, IF_VEC)
+/* VECTOR COMPARE HIGH */
+ E(0xe7fb, VCH, VRR_b, V, 0, 0, 0, 0, vc, 0, TCG_COND_GT, IF_VEC)
+/* VECTOR COMPARE HIGH LOGICAL */
+ E(0xe7f9, VCHL, VRR_b, V, 0, 0, 0, 0, vc, 0, TCG_COND_GTU, IF_VEC)
#ifndef CONFIG_USER_ONLY
/* COMPARE AND SWAP AND PURGE */
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
index 56534b3..9893fc0 100644
--- a/target/s390x/internal.h
+++ b/target/s390x/internal.h
@@ -200,6 +200,7 @@ enum cc_op {
CC_OP_SLA_64, /* Calculate shift left signed (64bit) */
CC_OP_FLOGR, /* find leftmost one */
CC_OP_LCBB, /* load count to block boundary */
+ CC_OP_VC, /* vector compare result */
CC_OP_MAX
};
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index e8e8a79..da8f5b4 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -572,6 +572,7 @@ static void gen_op_calc_cc(DisasContext *s)
case CC_OP_SLA_32:
case CC_OP_SLA_64:
case CC_OP_NZ_F128:
+ case CC_OP_VC:
/* 2 arguments */
gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy);
break;
diff --git a/target/s390x/translate_vx.inc.c b/target/s390x/translate_vx.inc.c
index 4d5af6e..199742f 100644
--- a/target/s390x/translate_vx.inc.c
+++ b/target/s390x/translate_vx.inc.c
@@ -1389,3 +1389,31 @@ static DisasJumpType op_vec(DisasContext *s, DisasOps *o)
read_vec_element_i64(o->in2, get_field(s->fields, v2), enr, es);
return DISAS_NEXT;
}
+
+static DisasJumpType op_vc(DisasContext *s, DisasOps *o)
+{
+ const uint8_t es = get_field(s->fields, m4);
+ TCGCond cond = s->insn->data;
+
+ if (es > ES_64) {
+ gen_program_exception(s, PGM_SPECIFICATION);
+ return DISAS_NORETURN;
+ }
+
+ tcg_gen_gvec_cmp(cond, es,
+ vec_full_reg_offset(get_field(s->fields, v1)),
+ vec_full_reg_offset(get_field(s->fields, v2)),
+ vec_full_reg_offset(get_field(s->fields, v3)), 16, 16);
+ if (get_field(s->fields, m5) & 0x1) {
+ TCGv_i64 low = tcg_temp_new_i64();
+ TCGv_i64 high = tcg_temp_new_i64();
+
+ read_vec_element_i64(high, get_field(s->fields, v1), 0, ES_64);
+ read_vec_element_i64(low, get_field(s->fields, v1), 1, ES_64);
+ gen_op_update2_cc_i64(s, CC_OP_VC, low, high);
+
+ tcg_temp_free_i64(low);
+ tcg_temp_free_i64(high);
+ }
+ return DISAS_NEXT;
+}