aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-s390x/cc_helper.c8
-rw-r--r--target-s390x/cpu.h2
-rw-r--r--target-s390x/helper.h2
-rw-r--r--target-s390x/insn-data.def3
-rw-r--r--target-s390x/int_helper.c22
-rw-r--r--target-s390x/translate.c66
6 files changed, 53 insertions, 50 deletions
diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c
index f1038be1b5..e3bed16bd3 100644
--- a/target-s390x/cc_helper.c
+++ b/target-s390x/cc_helper.c
@@ -399,6 +399,11 @@ static uint32_t cc_calc_sla_64(uint64_t src, int shift)
return 2;
}
+static uint32_t cc_calc_flogr(uint64_t dst)
+{
+ return dst ? 2 : 0;
+}
+
static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
uint64_t src, uint64_t dst, uint64_t vr)
{
@@ -504,6 +509,9 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
case CC_OP_SLA_64:
r = cc_calc_sla_64(src, dst);
break;
+ case CC_OP_FLOGR:
+ r = cc_calc_flogr(dst);
+ break;
case CC_OP_NZ_F32:
r = set_cc_nz_f32(dst);
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index f1d4dc67f4..dc7bbc67f6 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -478,6 +478,7 @@ enum cc_op {
CC_OP_ICM, /* insert characters under mask */
CC_OP_SLA_32, /* Calculate shift left signed (32bit) */
CC_OP_SLA_64, /* Calculate shift left signed (64bit) */
+ CC_OP_FLOGR, /* find leftmost one */
CC_OP_MAX
};
@@ -521,6 +522,7 @@ static const char *cc_names[] = {
[CC_OP_ICM] = "CC_OP_ICM",
[CC_OP_SLA_32] = "CC_OP_SLA_32",
[CC_OP_SLA_64] = "CC_OP_SLA_64",
+ [CC_OP_FLOGR] = "CC_OP_FLOGR",
};
static inline const char *cc_name(int cc_op)
diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index d9f630ecc3..e64b46d755 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -69,7 +69,7 @@ DEF_HELPER_4(msdb, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64)
DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64)
DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64)
-DEF_HELPER_3(flogr, i32, env, i32, i64)
+DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_2(sqeb, i64, env, i64)
DEF_HELPER_2(sqdb, i64, env, i64)
DEF_HELPER_3(sqxb, i64, env, i64, i64)
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def
index d5e1c5c1cd..771baafa37 100644
--- a/target-s390x/insn-data.def
+++ b/target-s390x/insn-data.def
@@ -220,6 +220,9 @@
/* EXTRACT FPC */
C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0)
+/* FIND LEFTMOST ONE */
+ C(0xb983, FLOGR, RRE, EI, 0, r2_o, r1_P, 0, flogr, 0)
+
/* INSERT CHARACTER */
C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0)
C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0)
diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c
index 839c0e1500..dc16de206c 100644
--- a/target-s390x/int_helper.c
+++ b/target-s390x/int_helper.c
@@ -165,26 +165,10 @@ int64_t HELPER(nabs_i64)(int64_t val)
}
}
-/* find leftmost one */
-uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2)
+/* count leading zeros, for find leftmost one */
+uint64_t HELPER(clz)(uint64_t v)
{
- uint64_t res = 0;
- uint64_t ov2 = v2;
-
- while (!(v2 & 0x8000000000000000ULL) && v2) {
- v2 <<= 1;
- res++;
- }
-
- if (!v2) {
- env->regs[r1] = 64;
- env->regs[r1 + 1] = 0;
- return 0;
- } else {
- env->regs[r1] = res;
- env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res);
- return 2;
- }
+ return clz64(v);
}
uint64_t HELPER(cvd)(int32_t bin)
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 47ccc6740a..e674c93ffe 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -620,6 +620,7 @@ static void gen_op_calc_cc(DisasContext *s)
case CC_OP_COMP_64:
case CC_OP_NZ_F32:
case CC_OP_NZ_F64:
+ case CC_OP_FLOGR:
/* 1 argument */
gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy);
break;
@@ -852,6 +853,20 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
account_inline_branch(s, old_cc_op);
break;
+ case CC_OP_FLOGR:
+ switch (mask & 0xa) {
+ case 8: /* src == 0 -> no one bit found */
+ cond = TCG_COND_EQ;
+ break;
+ case 2: /* src != 0 -> one bit found */
+ cond = TCG_COND_NE;
+ break;
+ default:
+ goto do_dynamic;
+ }
+ account_inline_branch(s, old_cc_op);
+ break;
+
default:
do_dynamic:
/* Calculate cc value. */
@@ -888,6 +903,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
case CC_OP_LTGT0_64:
case CC_OP_NZ:
+ case CC_OP_FLOGR:
c->u.s64.a = cc_dst;
c->u.s64.b = tcg_const_i64(0);
c->g1 = true;
@@ -1414,29 +1430,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3,
#undef FP_HELPER
}
-static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1,
- int r2)
-{
- TCGv_i64 tmp;
- TCGv_i32 tmp32_1;
-
- LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2);
- switch (op) {
- case 0x83: /* FLOGR R1,R2 [RRE] */
- tmp = load_reg(r2);
- tmp32_1 = tcg_const_i32(r1);
- gen_helper_flogr(cc_op, cpu_env, tmp32_1, tmp);
- set_cc_static(s);
- tcg_temp_free_i64(tmp);
- tcg_temp_free_i32(tmp32_1);
- break;
- default:
- LOG_DISAS("illegal b9 operation 0x%x\n", op);
- gen_illegal_opcode(s);
- break;
- }
-}
-
static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
{
unsigned char opc;
@@ -1460,13 +1453,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
r2 = insn & 0xf;
disas_b3(env, s, op, r3, r1, r2);
break;
- case 0xb9:
- insn = ld_code4(env, s->pc);
- r1 = (insn >> 4) & 0xf;
- r2 = insn & 0xf;
- op = (insn >> 16) & 0xff;
- disas_b9(env, s, op, r1, r2);
- break;
default:
qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc);
gen_illegal_opcode(s);
@@ -2330,6 +2316,26 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o)
return NO_EXIT;
}
+static ExitStatus op_flogr(DisasContext *s, DisasOps *o)
+{
+ /* We'll use the original input for cc computation, since we get to
+ compare that against 0, which ought to be better than comparing
+ the real output against 64. It also lets cc_dst be a convenient
+ temporary during our computation. */
+ gen_op_update1_cc_i64(s, CC_OP_FLOGR, o->in2);
+
+ /* R1 = IN ? CLZ(IN) : 64. */
+ gen_helper_clz(o->out, o->in2);
+
+ /* R1+1 = IN & ~(found bit). Note that we may attempt to shift this
+ value by 64, which is undefined. But since the shift is 64 iff the
+ input is zero, we still get the correct result after and'ing. */
+ tcg_gen_movi_i64(o->out2, 0x8000000000000000ull);
+ tcg_gen_shr_i64(o->out2, o->out2, o->out);
+ tcg_gen_andc_i64(o->out2, cc_dst, o->out2);
+ return NO_EXIT;
+}
+
static ExitStatus op_icm(DisasContext *s, DisasOps *o)
{
int m3 = get_field(s->fields, m3);