Skip to content

Commit e5f5cff

Browse files
Artemiy VolkovJeffreyALaw
Artemiy Volkov
authored andcommitted
tree-optimization/116024 - simplify C1-X cmp C2 for wrapping signed types
Implement a match.pd transformation inverting the sign of X in C1 - X cmp C2, where C1 and C2 are integer constants and X is of a wrapping signed type, by observing that: (a) If cmp is == or !=, simply move X and C2 to opposite sides of the comparison to arrive at X cmp C1 - C2. (b) If cmp is <: - C1 - X < C2 means that C1 - X spans the values of -INF, -INF + 1, ..., C2 - 1; - Therefore, X is one of C1 - -INF, C1 - (-INF + 1), ..., C1 - C2 + 1; - Subtracting (C1 + 1), X - (C1 + 1) is one of - (-INF) - 1, - (-INF) - 2, ..., -C2; - Using the fact that - (-INF) - 1 is +INF, derive that X - (C1 + 1) spans the values +INF, +INF - 1, ..., -C2; - Thus, the original expression can be simplified to X - (C1 + 1) > -C2 - 1. (c) Similarly, C1 - X <= C2 is equivalent to X - (C1 + 1) >= -C2 - 1. (d) The >= and > cases are negations of (b) and (c), respectively. (e) In all cases, the expression -C2 - 1 can be shortened to bit_not (C2). This transformation allows to occasionally save load-immediate / subtraction instructions, e.g. the following statement: 10 - (int)f() >= 20; now compiles to addi a0,a0,-11 slti a0,a0,-20 instead of li a5,10 sub a0,a5,a0 slti t0,a0,20 xori a0,t0,1 on 32-bit RISC-V when compiled with -fwrapv. Additional examples can be found in the newly added test file. This patch has been bootstrapped and regtested on aarch64, x86_64, and i386, and additionally regtested on riscv32. gcc/ChangeLog: PR tree-optimization/116024 * match.pd: New transformation around integer comparison. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr116024-1-fwrapv.c: New test.
1 parent 65b33d4 commit e5f5cff

File tree

2 files changed

+85
-1
lines changed

2 files changed

+85
-1
lines changed

gcc/match.pd

+20-1
Original file line numberDiff line numberDiff line change
@@ -9104,7 +9104,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
91049104
(cmp (plus @1 (minus @2 @0)) @2))
91059105
(if (cmp == LT_EXPR || cmp == GE_EXPR)
91069106
(cmp (plus @1 (minus @2
9107-
(plus @0 { build_one_cst (TREE_TYPE (@1)); }))) @2)))))))
9107+
(plus @0 { build_one_cst (TREE_TYPE (@1)); }))) @2)))
9108+
/* For wrapping signed types (-fwrapv), transform like so (using < as example):
9109+
C1 - X < C2
9110+
==> C1 - X = { -INF, -INF + 1, ..., C2 - 1 }
9111+
==> X = { C1 - (-INF), C1 - (-INF + 1), ..., C1 - C2 + 1 }
9112+
==> X - (C1 + 1) = { - (-INF) - 1, - (-INF) - 2, ..., -C2 }
9113+
==> X - (C1 + 1) = { +INF, +INF - 1, ..., -C2 }
9114+
==> X - (C1 + 1) > -C2 - 1
9115+
==> X - (C1 + 1) > bit_not (C2)
9116+
9117+
Similarly,
9118+
C1 - X <= C2 ==> X - (C1 + 1) >= bit_not (C2);
9119+
C1 - X >= C2 ==> X - (C1 + 1) <= bit_not (C2);
9120+
C1 - X > C2 ==> X - (C1 + 1) < bit_not (C2). */
9121+
(if (!TYPE_UNSIGNED (TREE_TYPE (@1))
9122+
&& TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
9123+
(if (cmp == EQ_EXPR || cmp == NE_EXPR)
9124+
(cmp @1 (minus @0 @2))
9125+
(rcmp (minus @1 (plus @0 { build_one_cst (TREE_TYPE (@1)); }))
9126+
(bit_not @2))))))))
91089127

91099128
/* Canonicalizations of BIT_FIELD_REFs. */
91109129

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* PR tree-optimization/116024 */
2+
/* { dg-do compile } */
3+
/* { dg-options "-O1 -fdump-tree-forwprop1-details -fwrapv" } */
4+
5+
#include <stdint.h>
6+
7+
uint32_t f(void);
8+
9+
int32_t i2(void)
10+
{
11+
int32_t l = 10 - (int32_t)f();
12+
return l <= 20; // f() - 11 >= -21
13+
}
14+
15+
int32_t i2a(void)
16+
{
17+
int32_t l = 10 - (int32_t)f();
18+
return l < 30; // f() - 11 > -31
19+
}
20+
21+
int32_t i2b(void)
22+
{
23+
int32_t l = 200 - (int32_t)f();
24+
return l <= 100; // f() - 201 >= -101
25+
}
26+
27+
int32_t i2c(void)
28+
{
29+
int32_t l = 300 - (int32_t)f();
30+
return l < 100; // f() - 301 > -101
31+
}
32+
33+
int32_t i2d(void)
34+
{
35+
int32_t l = 1000 - (int32_t)f();
36+
return l >= 2000; // f() - 1001 <= -2001
37+
}
38+
39+
int32_t i2e(void)
40+
{
41+
int32_t l = 1000 - (int32_t)f();
42+
return l > 3000; // f() - 1001 < -3001
43+
}
44+
45+
int32_t i2f(void)
46+
{
47+
int32_t l = 20000 - (int32_t)f();
48+
return l >= 10000; // f() - 20001 <= -10001
49+
}
50+
51+
int32_t i2g(void)
52+
{
53+
int32_t l = 30000 - (int32_t)f();
54+
return l > 10000; // f() - 30001 < -10001
55+
}
56+
57+
/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 8 "forwprop1" } } */
58+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -11.*\n.*>= -21" 1 "forwprop1" } } */
59+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -11.*\n.*>= -30" 1 "forwprop1" } } */
60+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -201.*\n.*>= -101" 1 "forwprop1" } } */
61+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -301.*\n.*>= -100" 1 "forwprop1" } } */
62+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -1001.*\n.*< -2000" 1 "forwprop1" } } */
63+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -1001.*\n.*< -3001" 1 "forwprop1" } } */
64+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -20001.*\n.*< -10000" 1 "forwprop1" } } */
65+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -30001.*\n.*< -10001" 1 "forwprop1" } } */

0 commit comments

Comments
 (0)