diff options
-rw-r--r-- | target-s390x/cc_helper.c | 8 | ||||
-rw-r--r-- | target-s390x/cpu.h | 2 | ||||
-rw-r--r-- | target-s390x/helper.h | 2 | ||||
-rw-r--r-- | target-s390x/insn-data.def | 3 | ||||
-rw-r--r-- | target-s390x/int_helper.c | 22 | ||||
-rw-r--r-- | target-s390x/translate.c | 66 |
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); |