aboutsummaryrefslogtreecommitdiff
path: root/target-i386/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-i386/translate.c')
-rw-r--r--target-i386/translate.c147
1 files changed, 93 insertions, 54 deletions
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 5c9211f7db..06f0fbced0 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <signal.h>
+#include "qemu/host-utils.h"
#include "cpu.h"
#include "disas/disas.h"
#include "tcg-op.h"
@@ -47,6 +48,14 @@
#define REX_B(s) 0
#endif
+#ifdef TARGET_X86_64
+# define ctztl ctz64
+# define clztl clz64
+#else
+# define ctztl ctz32
+# define clztl clz32
+#endif
+
//#define MACRO_TEST 1
/* global register indexes */
@@ -881,11 +890,21 @@ static void gen_compute_eflags(DisasContext *s)
tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32);
}
+typedef struct CCPrepare {
+ TCGCond cond;
+ TCGv reg;
+ TCGv reg2;
+ target_ulong imm;
+ target_ulong mask;
+ bool use_reg2;
+ bool no_setcond;
+} CCPrepare;
+
/* compute eflags.C to reg */
-static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv)
+static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
{
TCGv t0, t1;
- int size;
+ int size, shift;
switch (s->cc_op) {
case CC_OP_SUBB ... CC_OP_SUBQ:
@@ -904,9 +923,8 @@ static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv)
t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false);
t0 = gen_ext_tl(reg, cpu_cc_dst, size, false);
add_sub:
- tcg_gen_setcond_tl(inv ? TCG_COND_GEU : TCG_COND_LTU, reg, t0, t1);
- inv = false;
- break;
+ return (CCPrepare) { .cond = TCG_COND_LTU, .reg = t0,
+ .reg2 = t1, .mask = -1, .use_reg2 = true };
case CC_OP_SBBB ... CC_OP_SBBQ:
/* (DATA_TYPE)(CC_DST + CC_SRC + 1) <= (DATA_TYPE)CC_SRC */
@@ -929,42 +947,33 @@ static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv)
t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false);
t0 = gen_ext_tl(reg, cpu_cc_dst, size, false);
adc_sbb:
- tcg_gen_setcond_tl(inv ? TCG_COND_GTU : TCG_COND_LEU, reg, t0, t1);
- inv = false;
- break;
+ return (CCPrepare) { .cond = TCG_COND_LEU, .reg = t0,
+ .reg2 = t1, .mask = -1, .use_reg2 = true };
case CC_OP_LOGICB ... CC_OP_LOGICQ:
- tcg_gen_movi_tl(reg, 0);
- break;
+ return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
case CC_OP_INCB ... CC_OP_INCQ:
case CC_OP_DECB ... CC_OP_DECQ:
- if (inv) {
- tcg_gen_xori_tl(reg, cpu_cc_src, 1);
- } else {
- tcg_gen_mov_tl(reg, cpu_cc_src);
- }
- inv = false;
- break;
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = -1, .no_setcond = true };
case CC_OP_SHLB ... CC_OP_SHLQ:
/* (CC_SRC >> (DATA_BITS - 1)) & 1 */
size = s->cc_op - CC_OP_SHLB;
- tcg_gen_shri_tl(reg, cpu_cc_src, (8 << size) - 1);
- tcg_gen_andi_tl(reg, reg, 1);
- break;
+ shift = (8 << size) - 1;
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = (target_ulong)1 << shift };
case CC_OP_MULB ... CC_OP_MULQ:
- tcg_gen_setcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE,
- reg, cpu_cc_src, 0);
- inv = false;
- break;
+ return (CCPrepare) { .cond = TCG_COND_NE,
+ .reg = cpu_cc_src, .mask = -1 };
case CC_OP_EFLAGS:
case CC_OP_SARB ... CC_OP_SARQ:
/* CC_SRC & 1 */
- tcg_gen_andi_tl(reg, cpu_cc_src, 1);
- break;
+ return (CCPrepare) { .cond = TCG_COND_NE,
+ .reg = cpu_cc_src, .mask = CC_C };
default:
/* The need to compute only C from CC_OP_DYNAMIC is important
@@ -972,74 +981,104 @@ static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv)
gen_update_cc_op(s);
gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op);
tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32);
- break;
- }
- if (inv) {
- tcg_gen_xori_tl(reg, reg, 1);
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg,
+ .mask = -1, .no_setcond = true };
}
}
/* compute eflags.P to reg */
-static void gen_compute_eflags_p(DisasContext *s, TCGv reg)
+static CCPrepare gen_prepare_eflags_p(DisasContext *s, TCGv reg)
{
gen_compute_eflags(s);
- tcg_gen_shri_tl(reg, cpu_cc_src, 2);
- tcg_gen_andi_tl(reg, reg, 1);
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = CC_P };
}
/* compute eflags.S to reg */
-static void gen_compute_eflags_s(DisasContext *s, TCGv reg, bool inv)
+static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg)
{
switch (s->cc_op) {
case CC_OP_DYNAMIC:
gen_compute_eflags(s);
/* FALLTHRU */
case CC_OP_EFLAGS:
- tcg_gen_shri_tl(reg, cpu_cc_src, 7);
- tcg_gen_andi_tl(reg, reg, 1);
- if (inv) {
- tcg_gen_xori_tl(reg, reg, 1);
- }
- break;
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = CC_S };
default:
{
int size = (s->cc_op - CC_OP_ADDB) & 3;
TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true);
- tcg_gen_setcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, reg, t0, 0);
+ return (CCPrepare) { .cond = TCG_COND_LT, .reg = t0, .mask = -1 };
}
- break;
}
}
/* compute eflags.O to reg */
-static void gen_compute_eflags_o(DisasContext *s, TCGv reg)
+static CCPrepare gen_prepare_eflags_o(DisasContext *s, TCGv reg)
{
gen_compute_eflags(s);
- tcg_gen_shri_tl(reg, cpu_cc_src, 11);
- tcg_gen_andi_tl(reg, reg, 1);
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = CC_O };
}
/* compute eflags.Z to reg */
-static void gen_compute_eflags_z(DisasContext *s, TCGv reg, bool inv)
+static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
{
switch (s->cc_op) {
case CC_OP_DYNAMIC:
gen_compute_eflags(s);
/* FALLTHRU */
case CC_OP_EFLAGS:
- tcg_gen_shri_tl(reg, cpu_cc_src, 6);
- tcg_gen_andi_tl(reg, reg, 1);
- if (inv) {
- tcg_gen_xori_tl(reg, reg, 1);
- }
- break;
+ return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
+ .mask = CC_Z };
default:
{
int size = (s->cc_op - CC_OP_ADDB) & 3;
TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false);
- tcg_gen_setcondi_tl(inv ? TCG_COND_NE : TCG_COND_EQ, reg, t0, 0);
+ return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 };
}
- break;
+ }
+}
+
+#define gen_compute_eflags_c(s, reg, inv) \
+ gen_do_setcc(reg, gen_prepare_eflags_c(s, reg), inv)
+#define gen_compute_eflags_p(s, reg) \
+ gen_do_setcc(reg, gen_prepare_eflags_p(s, reg), false)
+#define gen_compute_eflags_s(s, reg, inv) \
+ gen_do_setcc(reg, gen_prepare_eflags_s(s, reg), inv)
+#define gen_compute_eflags_o(s, reg) \
+ gen_do_setcc(reg, gen_prepare_eflags_o(s, reg), false)
+#define gen_compute_eflags_z(s, reg, inv) \
+ gen_do_setcc(reg, gen_prepare_eflags_z(s, reg), inv)
+
+static void gen_do_setcc(TCGv reg, struct CCPrepare cc, bool inv)
+{
+ if (inv) {
+ cc.cond = tcg_invert_cond(cc.cond);
+ }
+
+ if (cc.no_setcond) {
+ if (cc.cond == TCG_COND_EQ) {
+ tcg_gen_xori_tl(reg, cc.reg, 1);
+ } else {
+ tcg_gen_mov_tl(reg, cc.reg);
+ }
+ return;
+ }
+
+ if (cc.cond == TCG_COND_NE && !cc.use_reg2 && cc.imm == 0 &&
+ cc.mask != 0 && (cc.mask & (cc.mask - 1)) == 0) {
+ tcg_gen_shri_tl(reg, cc.reg, ctztl(cc.mask));
+ tcg_gen_andi_tl(reg, reg, 1);
+ return;
+ }
+ if (cc.mask != -1) {
+ tcg_gen_andi_tl(reg, cc.reg, cc.mask);
+ }
+ if (cc.use_reg2) {
+ tcg_gen_setcond_tl(cc.cond, reg, cc.reg, cc.reg2);
+ } else {
+ tcg_gen_setcondi_tl(cc.cond, reg, cc.reg, cc.imm);
}
}