diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2023-08-05 15:43:23 -0700 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2023-08-24 11:22:42 -0700 |
commit | 6950f68b62e4913513a40b574de0219b7ae15b9f (patch) | |
tree | a02bb78d5223a2f0d3b6d43b4a475b31c88801ed /tcg | |
parent | 78ddf0dc75229865ba637cfffd53cc605cc33ca1 (diff) |
tcg/i386: Use CMP+SBB in tcg_out_setcond
Use the carry bit to optimize some forms of setcond.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'tcg')
-rw-r--r-- | tcg/i386/tcg-target.c.inc | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 1542afd94d..4d7b745a52 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1531,6 +1531,56 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, TCGArg dest, TCGArg arg1, TCGArg arg2, int const_arg2) { + bool inv = false; + + switch (cond) { + case TCG_COND_NE: + inv = true; + /* fall through */ + case TCG_COND_EQ: + /* If arg2 is 0, convert to LTU/GEU vs 1. */ + if (const_arg2 && arg2 == 0) { + arg2 = 1; + goto do_ltu; + } + break; + + case TCG_COND_LEU: + inv = true; + /* fall through */ + case TCG_COND_GTU: + /* If arg2 is a register, swap for LTU/GEU. */ + if (!const_arg2) { + TCGReg t = arg1; + arg1 = arg2; + arg2 = t; + goto do_ltu; + } + break; + + case TCG_COND_GEU: + inv = true; + /* fall through */ + case TCG_COND_LTU: + do_ltu: + /* + * Relying on the carry bit, use SBB to produce -1 if LTU, 0 if GEU. + * We can then use NEG or INC to produce the desired result. + * This is always smaller than the SETCC expansion. + */ + tcg_out_cmp(s, arg1, arg2, const_arg2, rexw); + tgen_arithr(s, ARITH_SBB, dest, dest); /* T:-1 F:0 */ + if (inv) { + tgen_arithi(s, ARITH_ADD, dest, 1, 0); /* T:0 F:1 */ + } else { + tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_NEG, dest); /* T:1 F:0 */ + } + return; + + default: + break; + } + tcg_out_cmp(s, arg1, arg2, const_arg2, rexw); tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest); tcg_out_ext8u(s, dest, dest); |