diff options
Diffstat (limited to 'target/s390x/translate.c')
-rw-r--r-- | target/s390x/translate.c | 287 |
1 files changed, 155 insertions, 132 deletions
diff --git a/target/s390x/translate.c b/target/s390x/translate.c index be32938..3d5c0d6 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -600,17 +600,9 @@ static void gen_op_calc_cc(DisasContext *s) dummy = tcg_const_i64(0); /* FALLTHRU */ case CC_OP_ADD_64: - case CC_OP_ADDU_64: - case CC_OP_ADDC_64: case CC_OP_SUB_64: - case CC_OP_SUBU_64: - case CC_OP_SUBB_64: case CC_OP_ADD_32: - case CC_OP_ADDU_32: - case CC_OP_ADDC_32: case CC_OP_SUB_32: - case CC_OP_SUBU_32: - case CC_OP_SUBB_32: local_cc_op = tcg_const_i32(s->cc_op); break; case CC_OP_CONST0: @@ -650,6 +642,7 @@ static void gen_op_calc_cc(DisasContext *s) /* 1 argument */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); break; + case CC_OP_ADDU: case CC_OP_ICM: case CC_OP_LTGT_32: case CC_OP_LTGT_64: @@ -659,6 +652,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_TM_64: case CC_OP_SLA_32: case CC_OP_SLA_64: + case CC_OP_SUBU: case CC_OP_NZ_F128: case CC_OP_VC: case CC_OP_MULS_64: @@ -666,17 +660,9 @@ static void gen_op_calc_cc(DisasContext *s) gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; case CC_OP_ADD_64: - case CC_OP_ADDU_64: - case CC_OP_ADDC_64: case CC_OP_SUB_64: - case CC_OP_SUBU_64: - case CC_OP_SUBB_64: case CC_OP_ADD_32: - case CC_OP_ADDU_32: - case CC_OP_ADDC_32: case CC_OP_SUB_32: - case CC_OP_SUBU_32: - case CC_OP_SUBB_32: /* 3 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr); break; @@ -849,42 +835,20 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) account_inline_branch(s, old_cc_op); break; - case CC_OP_ADDU_32: - case CC_OP_ADDU_64: + case CC_OP_ADDU: + case CC_OP_SUBU: switch (mask) { - case 8 | 2: /* vr == 0 */ + case 8 | 2: /* result == 0 */ cond = TCG_COND_EQ; break; - case 4 | 1: /* vr != 0 */ + case 4 | 1: /* result != 0 */ cond = TCG_COND_NE; break; - case 8 | 4: /* no carry -> vr >= src */ - cond = TCG_COND_GEU; + case 8 | 4: /* !carry (borrow) */ + cond = old_cc_op == CC_OP_ADDU ? TCG_COND_EQ : TCG_COND_NE; break; - case 2 | 1: /* carry -> vr < src */ - cond = TCG_COND_LTU; - break; - default: - goto do_dynamic; - } - account_inline_branch(s, old_cc_op); - break; - - case CC_OP_SUBU_32: - case CC_OP_SUBU_64: - /* Note that CC=0 is impossible; treat it as dont-care. */ - switch (mask & 7) { - case 2: /* zero -> op1 == op2 */ - cond = TCG_COND_EQ; - break; - case 4 | 1: /* !zero -> op1 != op2 */ - cond = TCG_COND_NE; - break; - case 4: /* borrow (!carry) -> op1 < op2 */ - cond = TCG_COND_LTU; - break; - case 2 | 1: /* !borrow (carry) -> op1 >= op2 */ - cond = TCG_COND_GEU; + case 2 | 1: /* carry (!borrow) */ + cond = old_cc_op == CC_OP_ADDU ? TCG_COND_NE : TCG_COND_EQ; break; default: goto do_dynamic; @@ -919,7 +883,6 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) break; case CC_OP_LTGT_32: case CC_OP_LTUGTU_32: - case CC_OP_SUBU_32: c->is_64 = false; c->u.s32.a = tcg_temp_new_i32(); tcg_gen_extrl_i64_i32(c->u.s32.a, cc_src); @@ -936,7 +899,6 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) break; case CC_OP_LTGT_64: case CC_OP_LTUGTU_64: - case CC_OP_SUBU_64: c->u.s64.a = cc_src; c->u.s64.b = cc_dst; c->g1 = c->g2 = true; @@ -950,26 +912,22 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst); break; - case CC_OP_ADDU_32: - c->is_64 = false; - c->u.s32.a = tcg_temp_new_i32(); - c->u.s32.b = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(c->u.s32.a, cc_vr); - if (cond == TCG_COND_EQ || cond == TCG_COND_NE) { - tcg_gen_movi_i32(c->u.s32.b, 0); - } else { - tcg_gen_extrl_i64_i32(c->u.s32.b, cc_src); - } - break; - - case CC_OP_ADDU_64: - c->u.s64.a = cc_vr; + case CC_OP_ADDU: + case CC_OP_SUBU: + c->is_64 = true; + c->u.s64.b = tcg_const_i64(0); c->g1 = true; - if (cond == TCG_COND_EQ || cond == TCG_COND_NE) { - c->u.s64.b = tcg_const_i64(0); - } else { - c->u.s64.b = cc_src; - c->g2 = true; + switch (mask) { + case 8 | 2: + case 4 | 1: /* result */ + c->u.s64.a = cc_dst; + break; + case 8 | 4: + case 2 | 1: /* carry */ + c->u.s64.a = cc_src; + break; + default: + g_assert_not_reached(); } break; @@ -1445,38 +1403,60 @@ static DisasJumpType op_add(DisasContext *s, DisasOps *o) return DISAS_NEXT; } -static DisasJumpType op_addc(DisasContext *s, DisasOps *o) +static DisasJumpType op_addu64(DisasContext *s, DisasOps *o) { - DisasCompare cmp; - TCGv_i64 carry; + tcg_gen_movi_i64(cc_src, 0); + tcg_gen_add2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src); + return DISAS_NEXT; +} + +/* Compute carry into cc_src. */ +static void compute_carry(DisasContext *s) +{ + switch (s->cc_op) { + case CC_OP_ADDU: + /* The carry value is already in cc_src (1,0). */ + break; + case CC_OP_SUBU: + tcg_gen_addi_i64(cc_src, cc_src, 1); + break; + default: + gen_op_calc_cc(s); + /* fall through */ + case CC_OP_STATIC: + /* The carry flag is the msb of CC; compute into cc_src. */ + tcg_gen_extu_i32_i64(cc_src, cc_op); + tcg_gen_shri_i64(cc_src, cc_src, 1); + break; + } +} +static DisasJumpType op_addc32(DisasContext *s, DisasOps *o) +{ + compute_carry(s); tcg_gen_add_i64(o->out, o->in1, o->in2); + tcg_gen_add_i64(o->out, o->out, cc_src); + return DISAS_NEXT; +} - /* The carry flag is the msb of CC, therefore the branch mask that would - create that comparison is 3. Feeding the generated comparison to - setcond produces the carry flag that we desire. */ - disas_jcc(s, &cmp, 3); - carry = tcg_temp_new_i64(); - if (cmp.is_64) { - tcg_gen_setcond_i64(cmp.cond, carry, cmp.u.s64.a, cmp.u.s64.b); - } else { - TCGv_i32 t = tcg_temp_new_i32(); - tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b); - tcg_gen_extu_i32_i64(carry, t); - tcg_temp_free_i32(t); - } - free_compare(&cmp); +static DisasJumpType op_addc64(DisasContext *s, DisasOps *o) +{ + compute_carry(s); + + TCGv_i64 zero = tcg_const_i64(0); + tcg_gen_add2_i64(o->out, cc_src, o->in1, zero, cc_src, zero); + tcg_gen_add2_i64(o->out, cc_src, o->out, cc_src, o->in2, zero); + tcg_temp_free_i64(zero); - tcg_gen_add_i64(o->out, o->out, carry); - tcg_temp_free_i64(carry); return DISAS_NEXT; } static DisasJumpType op_asi(DisasContext *s, DisasOps *o) { - o->in1 = tcg_temp_new_i64(); + bool non_atomic = !s390_has_feat(S390_FEAT_STFLE_45); - if (!s390_has_feat(S390_FEAT_STFLE_45)) { + o->in1 = tcg_temp_new_i64(); + if (non_atomic) { tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); } else { /* Perform the atomic addition in memory. */ @@ -1487,7 +1467,30 @@ static DisasJumpType op_asi(DisasContext *s, DisasOps *o) /* Recompute also for atomic case: needed for setting CC. */ tcg_gen_add_i64(o->out, o->in1, o->in2); - if (!s390_has_feat(S390_FEAT_STFLE_45)) { + if (non_atomic) { + tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); + } + return DISAS_NEXT; +} + +static DisasJumpType op_asiu64(DisasContext *s, DisasOps *o) +{ + bool non_atomic = !s390_has_feat(S390_FEAT_STFLE_45); + + o->in1 = tcg_temp_new_i64(); + if (non_atomic) { + tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); + } else { + /* Perform the atomic addition in memory. */ + tcg_gen_atomic_fetch_add_i64(o->in1, o->addr1, o->in2, get_mem_index(s), + s->insn->data); + } + + /* Recompute also for atomic case: needed for setting CC. */ + tcg_gen_movi_i64(cc_src, 0); + tcg_gen_add2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src); + + if (non_atomic) { tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); } return DISAS_NEXT; @@ -4732,29 +4735,58 @@ static DisasJumpType op_sub(DisasContext *s, DisasOps *o) return DISAS_NEXT; } -static DisasJumpType op_subb(DisasContext *s, DisasOps *o) +static DisasJumpType op_subu64(DisasContext *s, DisasOps *o) { - DisasCompare cmp; - TCGv_i64 borrow; - - tcg_gen_sub_i64(o->out, o->in1, o->in2); + tcg_gen_movi_i64(cc_src, 0); + tcg_gen_sub2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src); + return DISAS_NEXT; +} - /* The !borrow flag is the msb of CC. Since we want the inverse of - that, we ask for a comparison of CC=0 | CC=1 -> mask of 8 | 4. */ - disas_jcc(s, &cmp, 8 | 4); - borrow = tcg_temp_new_i64(); - if (cmp.is_64) { - tcg_gen_setcond_i64(cmp.cond, borrow, cmp.u.s64.a, cmp.u.s64.b); - } else { - TCGv_i32 t = tcg_temp_new_i32(); - tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b); - tcg_gen_extu_i32_i64(borrow, t); - tcg_temp_free_i32(t); +/* Compute borrow (0, -1) into cc_src. */ +static void compute_borrow(DisasContext *s) +{ + switch (s->cc_op) { + case CC_OP_SUBU: + /* The borrow value is already in cc_src (0,-1). */ + break; + default: + gen_op_calc_cc(s); + /* fall through */ + case CC_OP_STATIC: + /* The carry flag is the msb of CC; compute into cc_src. */ + tcg_gen_extu_i32_i64(cc_src, cc_op); + tcg_gen_shri_i64(cc_src, cc_src, 1); + /* fall through */ + case CC_OP_ADDU: + /* Convert carry (1,0) to borrow (0,-1). */ + tcg_gen_subi_i64(cc_src, cc_src, 1); + break; } - free_compare(&cmp); +} + +static DisasJumpType op_subb32(DisasContext *s, DisasOps *o) +{ + compute_borrow(s); + + /* Borrow is {0, -1}, so add to subtract. */ + tcg_gen_add_i64(o->out, o->in1, cc_src); + tcg_gen_sub_i64(o->out, o->out, o->in2); + return DISAS_NEXT; +} + +static DisasJumpType op_subb64(DisasContext *s, DisasOps *o) +{ + compute_borrow(s); + + /* + * Borrow is {0, -1}, so add to subtract; replicate the + * borrow input to produce 128-bit -1 for the addition. + */ + TCGv_i64 zero = tcg_const_i64(0); + tcg_gen_add2_i64(o->out, cc_src, o->in1, zero, cc_src, cc_src); + tcg_gen_sub2_i64(o->out, cc_src, o->out, cc_src, o->in2, zero); + tcg_temp_free_i64(zero); - tcg_gen_sub_i64(o->out, o->out, borrow); - tcg_temp_free_i64(borrow); return DISAS_NEXT; } @@ -5185,22 +5217,14 @@ static void cout_adds64(DisasContext *s, DisasOps *o) static void cout_addu32(DisasContext *s, DisasOps *o) { - gen_op_update3_cc_i64(s, CC_OP_ADDU_32, o->in1, o->in2, o->out); + tcg_gen_shri_i64(cc_src, o->out, 32); + tcg_gen_ext32u_i64(cc_dst, o->out); + gen_op_update2_cc_i64(s, CC_OP_ADDU, cc_src, cc_dst); } static void cout_addu64(DisasContext *s, DisasOps *o) { - gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); -} - -static void cout_addc32(DisasContext *s, DisasOps *o) -{ - gen_op_update3_cc_i64(s, CC_OP_ADDC_32, o->in1, o->in2, o->out); -} - -static void cout_addc64(DisasContext *s, DisasOps *o) -{ - gen_op_update3_cc_i64(s, CC_OP_ADDC_64, o->in1, o->in2, o->out); + gen_op_update2_cc_i64(s, CC_OP_ADDU, cc_src, o->out); } static void cout_cmps32(DisasContext *s, DisasOps *o) @@ -5291,22 +5315,14 @@ static void cout_subs64(DisasContext *s, DisasOps *o) static void cout_subu32(DisasContext *s, DisasOps *o) { - gen_op_update3_cc_i64(s, CC_OP_SUBU_32, o->in1, o->in2, o->out); + tcg_gen_sari_i64(cc_src, o->out, 32); + tcg_gen_ext32u_i64(cc_dst, o->out); + gen_op_update2_cc_i64(s, CC_OP_SUBU, cc_src, cc_dst); } static void cout_subu64(DisasContext *s, DisasOps *o) { - gen_op_update3_cc_i64(s, CC_OP_SUBU_64, o->in1, o->in2, o->out); -} - -static void cout_subb32(DisasContext *s, DisasOps *o) -{ - gen_op_update3_cc_i64(s, CC_OP_SUBB_32, o->in1, o->in2, o->out); -} - -static void cout_subb64(DisasContext *s, DisasOps *o) -{ - gen_op_update3_cc_i64(s, CC_OP_SUBB_64, o->in1, o->in2, o->out); + gen_op_update2_cc_i64(s, CC_OP_SUBU, cc_src, o->out); } static void cout_tm32(DisasContext *s, DisasOps *o) @@ -5637,6 +5653,13 @@ static void in1_r2_sr32(DisasContext *s, DisasOps *o) } #define SPEC_in1_r2_sr32 0 +static void in1_r2_32u(DisasContext *s, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(s, r2)]); +} +#define SPEC_in1_r2_32u 0 + static void in1_r3(DisasContext *s, DisasOps *o) { o->in1 = load_reg(get_field(s, r3)); |