target-s390: Convert FLOGR

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2012-08-24 07:39:11 -07:00
parent 683bb9a888
commit 102bf2c635
6 changed files with 53 additions and 50 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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);