Skip to content

Commit ceb9ee0

Browse files
committed
tcg/optimize: Handle TCG_COND_TST{EQ,NE}
Fold constant comparisons. Canonicalize "tst x,x" to equality vs zero. Canonicalize "tst x,sign" to sign test vs zero. Fold double-word comparisons with zero parts. Fold setcond of "tst x,pow2" to a bit extract. Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Signed-off-by: Richard Henderson <[email protected]>
1 parent 7e64b11 commit ceb9ee0

File tree

1 file changed

+218
-22
lines changed

1 file changed

+218
-22
lines changed

tcg/optimize.c

+218-22
Original file line numberDiff line numberDiff line change
@@ -625,9 +625,15 @@ static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c)
625625
return x <= y;
626626
case TCG_COND_GTU:
627627
return x > y;
628-
default:
629-
g_assert_not_reached();
628+
case TCG_COND_TSTEQ:
629+
return (x & y) == 0;
630+
case TCG_COND_TSTNE:
631+
return (x & y) != 0;
632+
case TCG_COND_ALWAYS:
633+
case TCG_COND_NEVER:
634+
break;
630635
}
636+
g_assert_not_reached();
631637
}
632638

633639
static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c)
@@ -653,12 +659,18 @@ static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c)
653659
return x <= y;
654660
case TCG_COND_GTU:
655661
return x > y;
656-
default:
657-
g_assert_not_reached();
662+
case TCG_COND_TSTEQ:
663+
return (x & y) == 0;
664+
case TCG_COND_TSTNE:
665+
return (x & y) != 0;
666+
case TCG_COND_ALWAYS:
667+
case TCG_COND_NEVER:
668+
break;
658669
}
670+
g_assert_not_reached();
659671
}
660672

661-
static bool do_constant_folding_cond_eq(TCGCond c)
673+
static int do_constant_folding_cond_eq(TCGCond c)
662674
{
663675
switch (c) {
664676
case TCG_COND_GT:
@@ -673,9 +685,14 @@ static bool do_constant_folding_cond_eq(TCGCond c)
673685
case TCG_COND_LEU:
674686
case TCG_COND_EQ:
675687
return 1;
676-
default:
677-
g_assert_not_reached();
688+
case TCG_COND_TSTEQ:
689+
case TCG_COND_TSTNE:
690+
return -1;
691+
case TCG_COND_ALWAYS:
692+
case TCG_COND_NEVER:
693+
break;
678694
}
695+
g_assert_not_reached();
679696
}
680697

681698
/*
@@ -703,8 +720,10 @@ static int do_constant_folding_cond(TCGType type, TCGArg x,
703720
} else if (arg_is_const_val(y, 0)) {
704721
switch (c) {
705722
case TCG_COND_LTU:
723+
case TCG_COND_TSTNE:
706724
return 0;
707725
case TCG_COND_GEU:
726+
case TCG_COND_TSTEQ:
708727
return 1;
709728
default:
710729
return -1;
@@ -777,14 +796,38 @@ static int do_constant_folding_cond1(OptContext *ctx, TCGArg dest,
777796
}
778797

779798
r = do_constant_folding_cond(ctx->type, *p1, *p2, cond);
780-
return r;
799+
if (r >= 0) {
800+
return r;
801+
}
802+
if (!is_tst_cond(cond)) {
803+
return -1;
804+
}
805+
806+
/*
807+
* TSTNE x,x -> NE x,0
808+
* TSTNE x,-1 -> NE x,0
809+
*/
810+
if (args_are_copies(*p1, *p2) || arg_is_const_val(*p2, -1)) {
811+
*p2 = arg_new_constant(ctx, 0);
812+
*pcond = tcg_tst_eqne_cond(cond);
813+
return -1;
814+
}
815+
816+
/* TSTNE x,sign -> LT x,0 */
817+
if (arg_is_const_val(*p2, (ctx->type == TCG_TYPE_I32
818+
? INT32_MIN : INT64_MIN))) {
819+
*p2 = arg_new_constant(ctx, 0);
820+
*pcond = tcg_tst_ltge_cond(cond);
821+
}
822+
return -1;
781823
}
782824

783825
static int do_constant_folding_cond2(OptContext *ctx, TCGArg *args)
784826
{
785827
TCGArg al, ah, bl, bh;
786828
TCGCond c;
787829
bool swap;
830+
int r;
788831

789832
swap = swap_commutative2(args, args + 2);
790833
c = args[4];
@@ -806,21 +849,54 @@ static int do_constant_folding_cond2(OptContext *ctx, TCGArg *args)
806849
tcg_target_ulong alv = arg_info(al)->val;
807850
tcg_target_ulong ahv = arg_info(ah)->val;
808851
uint64_t a = deposit64(alv, 32, 32, ahv);
809-
return do_constant_folding_cond_64(a, b, c);
852+
853+
r = do_constant_folding_cond_64(a, b, c);
854+
if (r >= 0) {
855+
return r;
856+
}
810857
}
858+
811859
if (b == 0) {
812860
switch (c) {
813861
case TCG_COND_LTU:
862+
case TCG_COND_TSTNE:
814863
return 0;
815864
case TCG_COND_GEU:
865+
case TCG_COND_TSTEQ:
816866
return 1;
817867
default:
818868
break;
819869
}
820870
}
871+
872+
/* TSTNE x,-1 -> NE x,0 */
873+
if (b == -1 && is_tst_cond(c)) {
874+
args[3] = args[2] = arg_new_constant(ctx, 0);
875+
args[4] = tcg_tst_eqne_cond(c);
876+
return -1;
877+
}
878+
879+
/* TSTNE x,sign -> LT x,0 */
880+
if (b == INT64_MIN && is_tst_cond(c)) {
881+
/* bl must be 0, so copy that to bh */
882+
args[3] = bl;
883+
args[4] = tcg_tst_ltge_cond(c);
884+
return -1;
885+
}
821886
}
887+
822888
if (args_are_copies(al, bl) && args_are_copies(ah, bh)) {
823-
return do_constant_folding_cond_eq(c);
889+
r = do_constant_folding_cond_eq(c);
890+
if (r >= 0) {
891+
return r;
892+
}
893+
894+
/* TSTNE x,x -> NE x,0 */
895+
if (is_tst_cond(c)) {
896+
args[3] = args[2] = arg_new_constant(ctx, 0);
897+
args[4] = tcg_tst_eqne_cond(c);
898+
return -1;
899+
}
824900
}
825901
return -1;
826902
}
@@ -1284,24 +1360,37 @@ static bool fold_brcond2(OptContext *ctx, TCGOp *op)
12841360
case 0:
12851361
goto do_brcond_const;
12861362
case 1:
1287-
op->opc = INDEX_op_brcond_i32;
1288-
op->args[1] = op->args[2];
1289-
op->args[2] = cond;
1290-
op->args[3] = label;
1291-
break;
1363+
goto do_brcond_low;
1364+
}
1365+
break;
1366+
1367+
case TCG_COND_TSTEQ:
1368+
case TCG_COND_TSTNE:
1369+
if (arg_is_const_val(op->args[2], 0)) {
1370+
goto do_brcond_high;
1371+
}
1372+
if (arg_is_const_val(op->args[3], 0)) {
1373+
goto do_brcond_low;
12921374
}
12931375
break;
12941376

12951377
default:
12961378
break;
12971379

1380+
do_brcond_low:
1381+
op->opc = INDEX_op_brcond_i32;
1382+
op->args[1] = op->args[2];
1383+
op->args[2] = cond;
1384+
op->args[3] = label;
1385+
return fold_brcond(ctx, op);
1386+
12981387
do_brcond_high:
12991388
op->opc = INDEX_op_brcond_i32;
13001389
op->args[0] = op->args[1];
13011390
op->args[1] = op->args[3];
13021391
op->args[2] = cond;
13031392
op->args[3] = label;
1304-
break;
1393+
return fold_brcond(ctx, op);
13051394

13061395
do_brcond_const:
13071396
if (i == 0) {
@@ -1967,13 +2056,107 @@ static bool fold_remainder(OptContext *ctx, TCGOp *op)
19672056
return false;
19682057
}
19692058

2059+
static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg)
2060+
{
2061+
TCGOpcode and_opc, sub_opc, xor_opc, neg_opc, shr_opc, uext_opc, sext_opc;
2062+
TCGCond cond = op->args[3];
2063+
TCGArg ret, src1, src2;
2064+
TCGOp *op2;
2065+
uint64_t val;
2066+
int sh;
2067+
bool inv;
2068+
2069+
if (!is_tst_cond(cond) || !arg_is_const(op->args[2])) {
2070+
return;
2071+
}
2072+
2073+
src2 = op->args[2];
2074+
val = arg_info(src2)->val;
2075+
if (!is_power_of_2(val)) {
2076+
return;
2077+
}
2078+
sh = ctz64(val);
2079+
2080+
switch (ctx->type) {
2081+
case TCG_TYPE_I32:
2082+
and_opc = INDEX_op_and_i32;
2083+
sub_opc = INDEX_op_sub_i32;
2084+
xor_opc = INDEX_op_xor_i32;
2085+
shr_opc = INDEX_op_shr_i32;
2086+
neg_opc = INDEX_op_neg_i32;
2087+
if (TCG_TARGET_extract_i32_valid(sh, 1)) {
2088+
uext_opc = TCG_TARGET_HAS_extract_i32 ? INDEX_op_extract_i32 : 0;
2089+
sext_opc = TCG_TARGET_HAS_sextract_i32 ? INDEX_op_sextract_i32 : 0;
2090+
}
2091+
break;
2092+
case TCG_TYPE_I64:
2093+
and_opc = INDEX_op_and_i64;
2094+
sub_opc = INDEX_op_sub_i64;
2095+
xor_opc = INDEX_op_xor_i64;
2096+
shr_opc = INDEX_op_shr_i64;
2097+
neg_opc = INDEX_op_neg_i64;
2098+
if (TCG_TARGET_extract_i64_valid(sh, 1)) {
2099+
uext_opc = TCG_TARGET_HAS_extract_i64 ? INDEX_op_extract_i64 : 0;
2100+
sext_opc = TCG_TARGET_HAS_sextract_i64 ? INDEX_op_sextract_i64 : 0;
2101+
}
2102+
break;
2103+
default:
2104+
g_assert_not_reached();
2105+
}
2106+
2107+
ret = op->args[0];
2108+
src1 = op->args[1];
2109+
inv = cond == TCG_COND_TSTEQ;
2110+
2111+
if (sh && sext_opc && neg && !inv) {
2112+
op->opc = sext_opc;
2113+
op->args[1] = src1;
2114+
op->args[2] = sh;
2115+
op->args[3] = 1;
2116+
return;
2117+
} else if (sh && uext_opc) {
2118+
op->opc = uext_opc;
2119+
op->args[1] = src1;
2120+
op->args[2] = sh;
2121+
op->args[3] = 1;
2122+
} else {
2123+
if (sh) {
2124+
op2 = tcg_op_insert_before(ctx->tcg, op, shr_opc, 3);
2125+
op2->args[0] = ret;
2126+
op2->args[1] = src1;
2127+
op2->args[2] = arg_new_constant(ctx, sh);
2128+
src1 = ret;
2129+
}
2130+
op->opc = and_opc;
2131+
op->args[1] = src1;
2132+
op->args[2] = arg_new_constant(ctx, 1);
2133+
}
2134+
2135+
if (neg && inv) {
2136+
op2 = tcg_op_insert_after(ctx->tcg, op, sub_opc, 3);
2137+
op2->args[0] = ret;
2138+
op2->args[1] = ret;
2139+
op2->args[2] = arg_new_constant(ctx, 1);
2140+
} else if (inv) {
2141+
op2 = tcg_op_insert_after(ctx->tcg, op, xor_opc, 3);
2142+
op2->args[0] = ret;
2143+
op2->args[1] = ret;
2144+
op2->args[2] = arg_new_constant(ctx, 1);
2145+
} else if (neg) {
2146+
op2 = tcg_op_insert_after(ctx->tcg, op, neg_opc, 2);
2147+
op2->args[0] = ret;
2148+
op2->args[1] = ret;
2149+
}
2150+
}
2151+
19702152
static bool fold_setcond(OptContext *ctx, TCGOp *op)
19712153
{
19722154
int i = do_constant_folding_cond1(ctx, op->args[0], &op->args[1],
19732155
&op->args[2], &op->args[3]);
19742156
if (i >= 0) {
19752157
return tcg_opt_gen_movi(ctx, op, op->args[0], i);
19762158
}
2159+
fold_setcond_tst_pow2(ctx, op, false);
19772160

19782161
ctx->z_mask = 1;
19792162
ctx->s_mask = smask_from_zmask(1);
@@ -1987,13 +2170,13 @@ static bool fold_negsetcond(OptContext *ctx, TCGOp *op)
19872170
if (i >= 0) {
19882171
return tcg_opt_gen_movi(ctx, op, op->args[0], -i);
19892172
}
2173+
fold_setcond_tst_pow2(ctx, op, true);
19902174

19912175
/* Value is {0,-1} so all bits are repetitions of the sign. */
19922176
ctx->s_mask = -1;
19932177
return false;
19942178
}
19952179

1996-
19972180
static bool fold_setcond2(OptContext *ctx, TCGOp *op)
19982181
{
19992182
TCGCond cond;
@@ -2041,22 +2224,35 @@ static bool fold_setcond2(OptContext *ctx, TCGOp *op)
20412224
case 0:
20422225
goto do_setcond_const;
20432226
case 1:
2044-
op->args[2] = op->args[3];
2045-
op->args[3] = cond;
2046-
op->opc = INDEX_op_setcond_i32;
2047-
break;
2227+
goto do_setcond_low;
2228+
}
2229+
break;
2230+
2231+
case TCG_COND_TSTEQ:
2232+
case TCG_COND_TSTNE:
2233+
if (arg_is_const_val(op->args[2], 0)) {
2234+
goto do_setcond_high;
2235+
}
2236+
if (arg_is_const_val(op->args[4], 0)) {
2237+
goto do_setcond_low;
20482238
}
20492239
break;
20502240

20512241
default:
20522242
break;
20532243

2244+
do_setcond_low:
2245+
op->args[2] = op->args[3];
2246+
op->args[3] = cond;
2247+
op->opc = INDEX_op_setcond_i32;
2248+
return fold_setcond(ctx, op);
2249+
20542250
do_setcond_high:
20552251
op->args[1] = op->args[2];
20562252
op->args[2] = op->args[4];
20572253
op->args[3] = cond;
20582254
op->opc = INDEX_op_setcond_i32;
2059-
break;
2255+
return fold_setcond(ctx, op);
20602256
}
20612257

20622258
ctx->z_mask = 1;

0 commit comments

Comments
 (0)