Skip to content

Commit 0883c88

Browse files
Artemiy VolkovJeffreyALaw
Artemiy Volkov
authored andcommitted
tree-optimization/116024 - simplify C1-X cmp C2 for UB-on-overflow types
Implement a match.pd pattern for C1 - X cmp C2, where C1 and C2 are integer constants and X is of a UB-on-overflow type. The pattern is simplified to X rcmp C1 - C2 by moving X and C2 to the other side of the comparison (with opposite signs). If C1 - C2 happens to overflow, replace the whole expression with either a constant 0 or a constant 1 node, depending on the comparison operator and the sign of the overflow. This transformation allows to occasionally save load-immediate / subtraction instructions, e.g. the following statement: 10 - (int) x <= 9; now compiles to sgt a0,a0,zero instead of li a5,10 sub a0,a5,a0 slti a0,a0,10 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. Existing tests were adjusted where necessary. gcc/ChangeLog: PR tree-optimization/116024 * match.pd: New transformation around integer comparison. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr116024.c: New test. * gcc.dg/pr67089-6.c: Adjust.
1 parent 2990f58 commit 0883c88

File tree

3 files changed

+94
-2
lines changed

3 files changed

+94
-2
lines changed

gcc/match.pd

+26
Original file line numberDiff line numberDiff line change
@@ -9059,6 +9059,32 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
90599059
}
90609060
(cmp @0 { res; })))))))))
90619061

9062+
/* Invert sign of X in comparisons of the form C1 - X CMP C2. */
9063+
9064+
(for cmp (lt le gt ge eq ne)
9065+
rcmp (gt ge lt le eq ne)
9066+
(simplify
9067+
(cmp (minus INTEGER_CST@0 @1) INTEGER_CST@2)
9068+
/* For UB-on-overflow types, simply switch sides for X and C2
9069+
to arrive at X RCMP C1 - C2, handling the case when the latter
9070+
expression overflows. */
9071+
(if (!TREE_OVERFLOW (@0) && !TREE_OVERFLOW (@2)
9072+
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1)))
9073+
(with { tree res = int_const_binop (MINUS_EXPR, @0, @2); }
9074+
(if (TREE_OVERFLOW (res))
9075+
(switch
9076+
(if (cmp == NE_EXPR)
9077+
{ constant_boolean_node (true, type); })
9078+
(if (cmp == EQ_EXPR)
9079+
{ constant_boolean_node (false, type); })
9080+
{
9081+
bool less = cmp == LE_EXPR || cmp == LT_EXPR;
9082+
bool ovf_high = wi::lt_p (wi::to_wide (@0), 0,
9083+
TYPE_SIGN (TREE_TYPE (@0)));
9084+
constant_boolean_node (less == ovf_high, type);
9085+
})
9086+
(rcmp @1 { res; }))))))
9087+
90629088
/* Canonicalizations of BIT_FIELD_REFs. */
90639089

90649090
(simplify

gcc/testsuite/gcc.dg/pr67089-6.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@ T (25, unsigned short, 2U - x, if (r > 2U) foo (0))
5757
T (26, unsigned char, 2U - x, if (r <= 2U) foo (0))
5858

5959
/* { dg-final { scan-tree-dump-times "ADD_OVERFLOW" 16 "widening_mul" { target { i?86-*-* x86_64-*-* } } } } */
60-
/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 11 "widening_mul" { target { { i?86-*-* x86_64-*-* } && { ! ia32 } } } } } */
61-
/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 9 "widening_mul" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */
60+
/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 9 "widening_mul" { target { { i?86-*-* x86_64-*-* } && { ! ia32 } } } } } */
61+
/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 7 "widening_mul" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/* PR tree-optimization/116024 */
2+
/* { dg-do compile } */
3+
/* { dg-options "-O1 -fdump-tree-forwprop1-details" } */
4+
5+
#include <stdint.h>
6+
#include <limits.h>
7+
8+
uint32_t f(void);
9+
10+
int32_t i1(void)
11+
{
12+
int32_t l = 10 - (int32_t)f();
13+
return l <= 9; // f() > 0
14+
}
15+
16+
int32_t i1a(void)
17+
{
18+
int32_t l = 20 - (int32_t)f();
19+
return l <= INT32_MIN; // return 0
20+
}
21+
22+
int32_t i1b(void)
23+
{
24+
int32_t l = 30 - (int32_t)f();
25+
return l <= INT32_MIN + 31; // f() == INT32_MAX
26+
}
27+
28+
int32_t i1c(void)
29+
{
30+
int32_t l = INT32_MAX - 40 - (int32_t)f();
31+
return l <= -38; // f() > INT32_MAX - 3
32+
}
33+
34+
int32_t i1d(void)
35+
{
36+
int32_t l = INT32_MAX - 50 - (int32_t)f();
37+
return l <= INT32_MAX - 1; // f() != -50
38+
}
39+
40+
int32_t i1e(void)
41+
{
42+
int32_t l = INT32_MAX - 60 - (int32_t)f();
43+
return l != INT32_MAX - 90; // f() != 30
44+
}
45+
46+
int32_t i1f(void)
47+
{
48+
int32_t l = INT32_MIN + 70 - (int32_t)f();
49+
return l <= INT32_MAX - 2; // return 0
50+
}
51+
52+
int32_t i1g(void)
53+
{
54+
int32_t l = INT32_MAX/2 + 30 - (int32_t)f();
55+
return l <= INT32_MIN/2 - 30; // return 1
56+
}
57+
58+
59+
/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 5 "forwprop1" } } */
60+
/* { dg-final { scan-tree-dump-times "return 0" 2 "forwprop1" } } */
61+
/* { dg-final { scan-tree-dump-times "return 1" 1 "forwprop1" } } */
62+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 0" 1 "forwprop1" } } */
63+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* == 2147483647" 1 "forwprop1" } } */
64+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 2147483644" 1 "forwprop1" } } */
65+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* != 4294967246" 1 "forwprop1" } } */
66+
/* { dg-final { scan-tree-dump-times "gimple_simplified to.* != 30" 1 "forwprop1" } } */

0 commit comments

Comments
 (0)