If possible, modify conditionally the input arguments to generate the flags requested by dfv; this way CCMP can use CC_OP_SUB* instead of having to compute the carry-out vector by hand. This happens relatively often for dfv=0, and also for dfv=sf for code produced by clang.
Of the combinations that cannot be optimized, both GCC and clang generate dfv=zf. GCC also generates OS and OSZ. Do not bother doing this for CTEST; the savings are modest because it does not need complex code to compute the carry-out vector (CC_SRC is always 0). In addition, trivially replacing the arguments to the AND would only support dfv=0 (produced by -2 & 2) or dfv=S (produced by -2 & -2), because TEST cannot produce any value where CF or OF are not zero. Signed-off-by: Paolo Bonzini <[email protected]> --- target/i386/tcg/emit.c.inc | 56 ++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 1144953abb1..7641b2fc104 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -1749,6 +1749,53 @@ static void gen_dfv_movcond(DisasContext *s, X86DecodedInsn *decode, int cond, u decode->cc_dst, tcg_constant_tl(dst)); } +static bool gen_ccmp_movcond(DisasContext *s, int cond, uint32_t dfv, MemOp ot) +{ + target_ulong op0, op1, max_int; + if (cond == CCMP_T) { + return true; + } + + /* + * For some values of dfv, it's possible to overwrite operands + * instead of using CC_OP_CCMP. The weird "16"s are to set AF==0. + */ + max_int = MAKE_64BIT_MASK(0, (8 << ot) - 1); + switch(dfv) { + case 0: + op0 = 1, op1 = 0; + break; + case CC_P|CC_C: + op0 = 1, op1 = -16; + break; + case CC_S: + op0 = -3, op1 = 0; + break; + case CC_S|CC_P|CC_C: + op0 = 0, op1 = 16; + break; + case CC_O: + /* + * While for >8-bit results -max_int has 1 in the lower byte, for 8-bit + * results -max_int is 0x81, so it flips the parity flag. Compensate + * in op1. + */ + op0 = -max_int, op1 = 16 + (ot == MO_8); + break; + case CC_O|CC_S|CC_P|CC_C: + /* Same here. */ + op0 = max_int, op1 = -1 - (ot == MO_8); + break; + default: + return false; + } + + CCPrepare cc = gen_prepare_cc(s, cond, NULL); + tcg_gen_movcond_tl(cc.cond, s->T0, cc.reg, cc.reg2, s->T0, tcg_constant_tl(op0)); + tcg_gen_movcond_tl(cc.cond, s->T1, cc.reg, cc.reg2, s->T1, tcg_constant_tl(op1)); + return true; +} + static void gen_SUB(DisasContext *s, X86DecodedInsn *decode); static void gen_CMP(DisasContext *s, X86DecodedInsn *decode) { @@ -1757,16 +1804,15 @@ static void gen_CMP(DisasContext *s, X86DecodedInsn *decode) MemOp ot = decode->op[1].ot; TCGv cout; - switch (cond) { - case CCMP_T: + if (gen_ccmp_movcond(s, cond, dfv, ot)) { + /* Including CCMP_T, aka "normal" CMP. */ gen_SUB(s, decode); return; - case CCMP_F: + } + if (cond == CCMP_F) { decode->cc_op = CC_OP_EFLAGS; decode->cc_src = tcg_constant_tl(dfv); return; - default: - break; } decode->cc_op = CC_OP_CCMPB + ot; -- 2.55.0
