On Mon, 23 Sep 2024, Artemiy Volkov wrote: > 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.
OK. Thanks, Richard. > 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. > > Signed-off-by: Artemiy Volkov <arte...@synopsys.com> > --- > gcc/match.pd | 26 +++++++++ > gcc/testsuite/gcc.dg/pr67089-6.c | 4 +- > gcc/testsuite/gcc.dg/tree-ssa/pr116024.c | 74 ++++++++++++++++++++++++ > 3 files changed, 102 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index 940292d0d49..81be0a21462 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -8925,6 +8925,32 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > } > (cmp @0 { res; }))))))))) > > +/* Invert sign of X in comparisons of the form C1 - X CMP C2. */ > + > +(for cmp (lt le gt ge eq ne) > + rcmp (gt ge lt le eq ne) > + (simplify > + (cmp (minus INTEGER_CST@0 @1) INTEGER_CST@2) > +/* For UB-on-overflow types, simply switch sides for X and C2 > + to arrive at X RCMP C1 - C2, handling the case when the latter > + expression overflows. */ > + (if (!TREE_OVERFLOW (@0) && !TREE_OVERFLOW (@2) > + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1))) > + (with { tree res = int_const_binop (MINUS_EXPR, @0, @2); } > + (if (TREE_OVERFLOW (res)) > + (switch > + (if (cmp == NE_EXPR) > + { constant_boolean_node (true, type); }) > + (if (cmp == EQ_EXPR) > + { constant_boolean_node (false, type); }) > + { > + bool less = cmp == LE_EXPR || cmp == LT_EXPR; > + bool ovf_high = wi::lt_p (wi::to_wide (@0), 0, > + TYPE_SIGN (TREE_TYPE (@0))); > + constant_boolean_node (less == ovf_high, type); > + }) > + (rcmp @1 { res; })))))) > + > /* Canonicalizations of BIT_FIELD_REFs. */ > > (simplify > diff --git a/gcc/testsuite/gcc.dg/pr67089-6.c > b/gcc/testsuite/gcc.dg/pr67089-6.c > index b59d75b2318..80a33c3f3e2 100644 > --- a/gcc/testsuite/gcc.dg/pr67089-6.c > +++ b/gcc/testsuite/gcc.dg/pr67089-6.c > @@ -57,5 +57,5 @@ T (25, unsigned short, 2U - x, if (r > 2U) foo (0)) > T (26, unsigned char, 2U - x, if (r <= 2U) foo (0)) > > /* { dg-final { scan-tree-dump-times "ADD_OVERFLOW" 16 "widening_mul" { > target { i?86-*-* x86_64-*-* } } } } */ > -/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 11 "widening_mul" { > target { { i?86-*-* x86_64-*-* } && { ! ia32 } } } } } */ > -/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 9 "widening_mul" { > target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ > +/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 9 "widening_mul" { > target { { i?86-*-* x86_64-*-* } && { ! ia32 } } } } } */ > +/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 7 "widening_mul" { > target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024.c > b/gcc/testsuite/gcc.dg/tree-ssa/pr116024.c > new file mode 100644 > index 00000000000..0dde9abbf89 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024.c > @@ -0,0 +1,74 @@ > +/* PR tree-optimization/116024 */ > +/* { dg-do compile } */ > +/* { dg-options "-O1 -fdump-tree-forwprop1-details" } */ > + > +#include <stdint.h> > +#include <limits.h> > + > +uint32_t f(void); > + > +int32_t i1(void) > +{ > + int32_t l = 2; > + l = 10 - (int32_t)f(); > + return l <= 9; // f() > 0 > +} > + > +int32_t i1a(void) > +{ > + int32_t l = 2; > + l = 20 - (int32_t)f(); > + return l <= INT32_MIN; // return 0 > +} > + > +int32_t i1b(void) > +{ > + int32_t l = 2; > + l = 30 - (int32_t)f(); > + return l <= INT32_MIN + 31; // f() == INT32_MAX > +} > + > +int32_t i1c(void) > +{ > + int32_t l = 2; > + l = INT32_MAX - 40 - (int32_t)f(); > + return l <= -38; // f() > INT32_MAX - 3 > +} > + > +int32_t i1d(void) > +{ > + int32_t l = 2; > + l = INT32_MAX - 50 - (int32_t)f(); > + return l <= INT32_MAX - 1; // f() != -50 > +} > + > +int32_t i1e(void) > +{ > + int32_t l = 2; > + l = INT32_MAX - 60 - (int32_t)f(); > + return l != INT32_MAX - 90; // f() != 30 > +} > + > +int32_t i1f(void) > +{ > + int32_t l = 2; > + l = INT32_MIN + 70 - (int32_t)f(); > + return l <= INT32_MAX - 2; // return 0 > +} > + > +int32_t i1g(void) > +{ > + int32_t l = 2; > + l = INT32_MAX/2 + 30 - (int32_t)f(); > + return l <= INT32_MIN/2 - 30; // return 1 > +} > + > + > +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 5 > "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "return 0" 2 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "return 1" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 0" 1 > "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* == 2147483647" > 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 2147483644" 1 > "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* != 4294967246" > 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* != 30" 1 > "forwprop1" } } */ > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)