diff options
author | Emilio G. Cota <cota@braap.org> | 2016-06-27 15:01:58 -0400 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2016-10-26 08:29:01 -0700 |
commit | a7cee522f3529c2fc85379237b391ea98823271e (patch) | |
tree | 2ecba6c87b96b997033bf17cc57ba89488d02f55 | |
parent | ae03f8de45427042ecd10b0941a005f21ecc064c (diff) |
target-i386: emulate LOCK'ed OP instructions using atomic helpers
[rth: Eliminate some unnecessary temporaries.]
Signed-off-by: Emilio G. Cota <cota@braap.org>
Message-Id: <1467054136-10430-13-git-send-email-cota@braap.org>
Signed-off-by: Richard Henderson <rth@twiddle.net>
-rw-r--r-- | target-i386/translate.c | 76 |
1 files changed, 58 insertions, 18 deletions
diff --git a/target-i386/translate.c b/target-i386/translate.c index dd1b408642..b9f58f8e32 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1257,55 +1257,95 @@ static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d) { if (d != OR_TMP0) { gen_op_mov_v_reg(ot, cpu_T0, d); - } else { + } else if (!(s1->prefix & PREFIX_LOCK)) { gen_op_ld_v(s1, ot, cpu_T0, cpu_A0); } switch(op) { case OP_ADCL: gen_compute_eflags_c(s1, cpu_tmp4); - tcg_gen_add_tl(cpu_T0, cpu_T0, cpu_T1); - tcg_gen_add_tl(cpu_T0, cpu_T0, cpu_tmp4); - gen_op_st_rm_T0_A0(s1, ot, d); + if (s1->prefix & PREFIX_LOCK) { + tcg_gen_add_tl(cpu_T0, cpu_tmp4, cpu_T1); + tcg_gen_atomic_add_fetch_tl(cpu_T0, cpu_A0, cpu_T0, + s1->mem_index, ot | MO_LE); + } else { + tcg_gen_add_tl(cpu_T0, cpu_T0, cpu_T1); + tcg_gen_add_tl(cpu_T0, cpu_T0, cpu_tmp4); + gen_op_st_rm_T0_A0(s1, ot, d); + } gen_op_update3_cc(cpu_tmp4); set_cc_op(s1, CC_OP_ADCB + ot); break; case OP_SBBL: gen_compute_eflags_c(s1, cpu_tmp4); - tcg_gen_sub_tl(cpu_T0, cpu_T0, cpu_T1); - tcg_gen_sub_tl(cpu_T0, cpu_T0, cpu_tmp4); - gen_op_st_rm_T0_A0(s1, ot, d); + if (s1->prefix & PREFIX_LOCK) { + tcg_gen_add_tl(cpu_T0, cpu_T1, cpu_tmp4); + tcg_gen_neg_tl(cpu_T0, cpu_T0); + tcg_gen_atomic_add_fetch_tl(cpu_T0, cpu_A0, cpu_T0, + s1->mem_index, ot | MO_LE); + } else { + tcg_gen_sub_tl(cpu_T0, cpu_T0, cpu_T1); + tcg_gen_sub_tl(cpu_T0, cpu_T0, cpu_tmp4); + gen_op_st_rm_T0_A0(s1, ot, d); + } gen_op_update3_cc(cpu_tmp4); set_cc_op(s1, CC_OP_SBBB + ot); break; case OP_ADDL: - tcg_gen_add_tl(cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s1, ot, d); + if (s1->prefix & PREFIX_LOCK) { + tcg_gen_atomic_add_fetch_tl(cpu_T0, cpu_A0, cpu_T1, + s1->mem_index, ot | MO_LE); + } else { + tcg_gen_add_tl(cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s1, ot, d); + } gen_op_update2_cc(); set_cc_op(s1, CC_OP_ADDB + ot); break; case OP_SUBL: - tcg_gen_mov_tl(cpu_cc_srcT, cpu_T0); - tcg_gen_sub_tl(cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s1, ot, d); + if (s1->prefix & PREFIX_LOCK) { + tcg_gen_neg_tl(cpu_T0, cpu_T1); + tcg_gen_atomic_fetch_add_tl(cpu_cc_srcT, cpu_A0, cpu_T0, + s1->mem_index, ot | MO_LE); + tcg_gen_sub_tl(cpu_T0, cpu_cc_srcT, cpu_T1); + } else { + tcg_gen_mov_tl(cpu_cc_srcT, cpu_T0); + tcg_gen_sub_tl(cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s1, ot, d); + } gen_op_update2_cc(); set_cc_op(s1, CC_OP_SUBB + ot); break; default: case OP_ANDL: - tcg_gen_and_tl(cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s1, ot, d); + if (s1->prefix & PREFIX_LOCK) { + tcg_gen_atomic_and_fetch_tl(cpu_T0, cpu_A0, cpu_T1, + s1->mem_index, ot | MO_LE); + } else { + tcg_gen_and_tl(cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s1, ot, d); + } gen_op_update1_cc(); set_cc_op(s1, CC_OP_LOGICB + ot); break; case OP_ORL: - tcg_gen_or_tl(cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s1, ot, d); + if (s1->prefix & PREFIX_LOCK) { + tcg_gen_atomic_or_fetch_tl(cpu_T0, cpu_A0, cpu_T1, + s1->mem_index, ot | MO_LE); + } else { + tcg_gen_or_tl(cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s1, ot, d); + } gen_op_update1_cc(); set_cc_op(s1, CC_OP_LOGICB + ot); break; case OP_XORL: - tcg_gen_xor_tl(cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s1, ot, d); + if (s1->prefix & PREFIX_LOCK) { + tcg_gen_atomic_xor_fetch_tl(cpu_T0, cpu_A0, cpu_T1, + s1->mem_index, ot | MO_LE); + } else { + tcg_gen_xor_tl(cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s1, ot, d); + } gen_op_update1_cc(); set_cc_op(s1, CC_OP_LOGICB + ot); break; |