Skip to content

Commit 65b33d4

Browse files
Artemiy VolkovJeffreyALaw
Artemiy Volkov
authored andcommitted
tree-optimization/116024 - simplify C1-X cmp C2 for unsigned 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 an unsigned 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 range of 0, 1, ..., C2 - 1; - This means that X spans the range of C1 - (C2 - 1), C1 - (C2 - 2), ..., C1; - Subtracting C1 - (C2 - 1), X - (C1 - (C2 - 1)) is one of 0, 1, ..., C1 - (C1 - (C2 - 1)); - Simplifying the above, X - (C1 - C2 + 1) is one of 0, 1, ..., C2 - 1; - Summarizing, the expression C1 - X < C2 can be transformed into X - (C1 - C2 + 1) < C2. (c) Similarly, if cmp is <=: - C1 - X <= C2 means that C1 - X is one of 0, 1, ..., C2; - It follows that X is one of C1 - C2, C1 - (C2 - 1), ..., C1; - Subtracting C1 - C2, X - (C1 - C2) has range 0, 1, ..., C2; - Thus, the expression C1 - X <= C2 can be transformed into X - (C1 - C2) <= C2. (d) The >= and > cases are negations of (b) and (c), respectively. This transformation allows to occasionally save load-immediate / subtraction instructions, e.g. the following statement: 300 - (unsigned int)f() < 100; now compiles to addi a0,a0,-201 sltiu a0,a0,100 instead of li a5,300 sub a0,a5,a0 sltiu a0,a0,100 on 32-bit RISC-V. 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.c: New test.
1 parent 0883c88 commit 65b33d4

File tree

2 files changed

+87
-1
lines changed

2 files changed

+87
-1
lines changed

gcc/match.pd

+22-1
Original file line numberDiff line numberDiff line change
@@ -9083,7 +9083,28 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
90839083
TYPE_SIGN (TREE_TYPE (@0)));
90849084
constant_boolean_node (less == ovf_high, type);
90859085
})
9086-
(rcmp @1 { res; }))))))
9086+
(rcmp @1 { res; })))
9087+
/* For unsigned types, transform like so (using < as example):
9088+
C1 - X < C2
9089+
==> C1 - X = { 0, 1, ..., C2 - 1 }
9090+
==> X = { C1 - (C2 - 1), ..., C1 + 1, C1 }
9091+
==> X - (C1 - (C2 - 1)) = { 0, 1, ..., C1 - (C1 - (C2 - 1)) }
9092+
==> X - (C1 - C2 + 1) = { 0, 1, ..., C2 - 1 }
9093+
==> X - (C1 - C2 + 1) < C2.
9094+
9095+
Similarly,
9096+
C1 - X <= C2 ==> X - (C1 - C2) <= C2;
9097+
C1 - X >= C2 ==> X - (C1 - C2 + 1) >= C2;
9098+
C1 - X > C2 ==> X - (C1 - C2) > C2. */
9099+
(if (TYPE_UNSIGNED (TREE_TYPE (@1)))
9100+
(switch
9101+
(if (cmp == EQ_EXPR || cmp == NE_EXPR)
9102+
(cmp @1 (minus @0 @2)))
9103+
(if (cmp == LE_EXPR || cmp == GT_EXPR)
9104+
(cmp (plus @1 (minus @2 @0)) @2))
9105+
(if (cmp == LT_EXPR || cmp == GE_EXPR)
9106+
(cmp (plus @1 (minus @2
9107+
(plus @0 { build_one_cst (TREE_TYPE (@1)); }))) @2)))))))
90879108

90889109
/* Canonicalizations of BIT_FIELD_REFs. */
90899110

+65
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" } */
4+
5+
#include <stdint.h>
6+
7+
uint32_t f(void);
8+
9+
int32_t i2(void)
10+
{
11+
uint32_t l = 10 - (uint32_t)f();
12+
return l <= 20; // f() + 10 <= 20
13+
}
14+
15+
int32_t i2a(void)
16+
{
17+
uint32_t l = 10 - (uint32_t)f();
18+
return l < 30; // f() + 19 < 30
19+
}
20+
21+
int32_t i2b(void)
22+
{
23+
uint32_t l = 200 - (uint32_t)f();
24+
return l <= 100; // f() - 100 <= 100
25+
}
26+
27+
int32_t i2c(void)
28+
{
29+
uint32_t l = 300 - (uint32_t)f();
30+
return l < 100; // f() - 201 < 100
31+
}
32+
33+
int32_t i2d(void)
34+
{
35+
uint32_t l = 1000 - (uint32_t)f();
36+
return l >= 2000; // f() + 999 >= 2000
37+
}
38+
39+
int32_t i2e(void)
40+
{
41+
uint32_t l = 1000 - (uint32_t)f();
42+
return l > 3000; // f() + 2000 > 3000
43+
}
44+
45+
int32_t i2f(void)
46+
{
47+
uint32_t l = 20000 - (uint32_t)f();
48+
return l >= 10000; // f() - 10001 >= 10000
49+
}
50+
51+
int32_t i2g(void)
52+
{
53+
uint32_t l = 30000 - (uint32_t)f();
54+
return l > 10000; // f() - 20000 > 10000
55+
}
56+
57+
/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 8 "forwprop1" } } */
58+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 10.*\n.*<= 20" 1 "forwprop1" } } */
59+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 19.*\n.*<= 29" 1 "forwprop1" } } */
60+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294967196.*\n.*<= 100" 1 "forwprop1" } } */
61+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294967095.*\n.*<= 99" 1 "forwprop1" } } */
62+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 999.*\n.*> 1999" 1 "forwprop1" } } */
63+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 2000.*\n.*> 3000" 1 "forwprop1" } } */
64+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294957295.*\n.*> 9999" 1 "forwprop1" } } */
65+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294947296.*\n.*> 10000" 1 "forwprop1" } } */

0 commit comments

Comments
 (0)