target-s390: Convert FLOGR
Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
683bb9a888
commit
102bf2c635
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user