Message ID | 20240821162547.25246-1-artemiy@synopsys.com |
---|---|
State | New |
Headers | show |
Series | [v2] tree-optimization/116024 - match.pd: add 4 int-compare simplifications | expand |
On Wed, 21 Aug 2024, Artemiy Volkov wrote: > Hi, > > sending a v2 of > https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659851.html after > changing variable types in all new testcases from standard to fixed-width. > > Could anyone please assist with reviewing and/or pushing to trunk/14 since I > don't have commit access? > > Many thanks, > Artemiy > > ---------- 8< ------------ > > This patch implements match.pd patterns for the following transformations: > > (1) (UB-on-overflow types) C1 - X cmp C2 -> X cmp C1 - C2 > > (2) (unsigned types) C1 - X cmp C2 -> > (a) X cmp C1 - C2, when cmp is !=, == > (b) X - (C1 - C2) cmp C2, when cmp is <=, > > (c) X - (C1 - C2 + 1) cmp C2, when cmp is <, >=, > > (3) (signed wrapping types) C1 - X cmp C2 > (a) X cmp C1 - C2, when cmp is !=, == > (b) X - (C1 + 1) rcmp -(C2 + 1), otherwise > > (4) (all wrapping types) X + C1 cmp C2 -> > (a) X cmp C2 - C1, when cmp is !=, == > (b) X cmp -C1, when cmp is <=, > and C2 - C1 == max > (c) X cmp -C1, when cmp is <, >= and C2 - C1 == min It would be easier to review if separating those, it wasn't all clear what of (1) .. (4) corresponds to which hunk below. > Included along are testcases for all the aforementioned changes. 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 transformations around integer comparison. > > gcc/testsuite/ChangeLog: > > * gcc.dg/tree-ssa/pr116024.c: New test. > * gcc.dg/tree-ssa/pr116024-1.c: Ditto. > * gcc.dg/tree-ssa/pr116024-1-fwrapv.c: Ditto. > * gcc.dg/tree-ssa/pr116024-2.c: Ditto. > * gcc.dg/tree-ssa/pr116024-2-fwrapv.c: Ditto. > * gcc.dg/pr67089-6.c: Adjust. > * gcc.target/aarch64/gtu_to_ltu_cmp_1.c: Ditto. > > Signed-off-by: Artemiy Volkov <artemiy@synopsys.com> > --- > gcc/match.pd | 75 ++++++++++++++++++- > gcc/testsuite/gcc.dg/pr67089-6.c | 4 +- > .../gcc.dg/tree-ssa/pr116024-1-fwrapv.c | 74 ++++++++++++++++++ > gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c | 74 ++++++++++++++++++ > .../gcc.dg/tree-ssa/pr116024-2-fwrapv.c | 38 ++++++++++ > gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c | 39 ++++++++++ > gcc/testsuite/gcc.dg/tree-ssa/pr116024.c | 74 ++++++++++++++++++ > .../gcc.target/aarch64/gtu_to_ltu_cmp_1.c | 2 +- > 8 files changed, 376 insertions(+), 4 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-1-fwrapv.c > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index 65a3aae2243..bf3ccef7437 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -8800,6 +8800,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > (cmp @0 { TREE_OVERFLOW (res) > ? drop_tree_overflow (res) : res; })))))))) > (for cmp (lt le gt ge) > + rcmp (gt ge lt le) > (for op (plus minus) > rop (minus plus) > (simplify > @@ -8827,7 +8828,79 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > "X cmp C2 -+ C1"), > WARN_STRICT_OVERFLOW_COMPARISON); > } > - (cmp @0 { res; }))))))))) > + (cmp @0 { res; }))))) > +/* For wrapping types, simplify X + C1 CMP C2 to X CMP -C1 when possible. */ it's more like X +- C1 CMP C2 to X CMP' C2 -+ C1 when C2 -+ C1 == +-INF? I have to think hard whether this requires an unsigned type (naturally TYPE_OVERFLOW_WRAPS) or if it also works for signed types (with -fwrapv). Can you explain? > + (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))) > + (with > + { > + wide_int max = wi::max_value (TREE_TYPE (@0)); > + wide_int min = wi::min_value (TREE_TYPE (@0)); > + > + wide_int c2 = rop == PLUS_EXPR > + ? wi::add (wi::to_wide (@2), wi::to_wide (@1)) > + : wi::sub (wi::to_wide (@2), wi::to_wide (@1)); > + } > + (if (((cmp == LE_EXPR || cmp == GT_EXPR) && wi::eq_p (c2, max)) > + || ((cmp == LT_EXPR || cmp == GE_EXPR) && wi::eq_p (c2, min))) > + (with > + { > + wide_int c1 = rop == PLUS_EXPR > + ? wi::add (min, wi::to_wide (@1)) > + : wi::sub (min, wi::to_wide (@1)); > + tree c1_cst = build_uniform_cst (TREE_TYPE (@0), > + wide_int_to_tree (TREE_TYPE (@0), c1)); > + } > + (rcmp @0 { c1_cst; }))))))))) > + > +/* 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) > + (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)) > + (with > + { > + fold_overflow_warning (("assuming signed overflow does not occur " > + "when simplifying conditional to constant"), > + WARN_STRICT_OVERFLOW_CONDITIONAL); > + } > + (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); > + })) > + (with > + { > + fold_overflow_warning (("assuming signed overflow does not occur " > + "when changing C1 - X cmp C2 to " > + "X cmp C1 - C2"), > + WARN_STRICT_OVERFLOW_COMPARISON); please don't add more fold_overflow_warning > + } > + (rcmp @1 { res; })))) > + (if (TYPE_UNSIGNED (TREE_TYPE (@1))) > + (switch > + (if (cmp == EQ_EXPR || cmp == NE_EXPR) > + (cmp @1 (minus @0 @2))) > + (if (cmp == LE_EXPR || cmp == GT_EXPR) > + (cmp (plus @1 (minus @2 @0)) @2)) Why's that an improvement? > + (if (cmp == LT_EXPR || cmp == GE_EXPR) > + (cmp (plus @1 (minus @2 > + (plus @0 { build_int_cst (TREE_TYPE (@1), 1); }))) @2))) Likewise? Can you add comments describing the transform before the respective transforms? > + (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1))) > + (if (cmp == EQ_EXPR || cmp == NE_EXPR) > + (cmp @1 (minus @0 @2)) > + (rcmp (minus @1 (plus @0 { build_int_cst (TREE_TYPE (@1), 1); })) > + (negate @2)))))))) why is the latter valid for all compares but the TYPE_UNSIGNED case is not? I suppose this is for signed compares but without undefined overflow? More comments would clearly help so that people later understand what the different cases are. > > /* Canonicalizations of BIT_FIELD_REFs. */ > > 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-1-fwrapv.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1-fwrapv.c > new file mode 100644 > index 00000000000..1fe8c821bec > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1-fwrapv.c > @@ -0,0 +1,74 @@ > +/* PR tree-optimization/116024 */ > +/* { dg-do compile } */ > +/* { dg-options "-O1 -fdump-tree-forwprop1-details -fwrapv" } */ > + > +#include <stdint.h> > +#include <limits.h> > + > +uint32_t f(void); > + > +int32_t i2(void) > +{ > + int32_t l = 2; > + l = 10 - (int32_t)f(); > + return l <= 20; // f() + 10 + INT_MIN <= 20 > +} > + > +int32_t i2a(void) > +{ > + int32_t l = 2; > + l = 10 - (int32_t)f(); > + return l < 30; // f() + 19 + INT_MIN <= 29 > +} > + > +int32_t i2b(void) > +{ > + int32_t l = 2; > + l = 200 - (int32_t)f(); > + return l <= 100; // f() - 100 + INT_MIN <= 100 > +} > + > +int32_t i2c(void) > +{ > + int32_t l = 2; > + l = 300 - (int32_t)f(); > + return l < 100; // f() - 201 + INT_MIN <= 99 > +} > + > +int32_t i2d(void) > +{ > + int32_t l = 2; > + l = 1000 - (int32_t)f(); > + return l >= 2000; // f() + 999 + INT_MIN > 1999 > +} > + > +int32_t i2e(void) > +{ > + int32_t l = 2; > + l = 1000 - (int32_t)f(); > + return l > 3000; // f() + 2000 + INT_MIN > 3000 > +} > + > +int32_t i2f(void) > +{ > + int32_t l = 2; > + l = 20000 - (int32_t)f(); > + return l >= 10000; // f() - 10001 + INT_MIN > 9999 > +} > + > +int32_t i2g(void) > +{ > + int32_t l = 2; > + l = 30000 - (int32_t)f(); > + return l > 10000; // f() - 20000 + INT_MIN > 10000 > +} > + > +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 8 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -11.*\n.*>= -20" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -11.*\n.*>= -29" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -201.*\n.*>= -100" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -301.*\n.*>= -99" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -1001.*\n.*< -1999" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -1001.*\n.*< -3000" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -20001.*\n.*< -9999" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -30001.*\n.*< -10000" 1 "forwprop1" } } */ > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c > new file mode 100644 > index 00000000000..ecafb41fa09 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.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 i2(void) > +{ > + uint32_t l = 2; > + l = 10 - (uint32_t)f(); > + return l <= 20; // f() + 10 <= 20 > +} > + > +int32_t i2a(void) > +{ > + uint32_t l = 2; > + l = 10 - (uint32_t)f(); > + return l < 30; // f() + 19 <= 29 > +} > + > +int32_t i2b(void) > +{ > + uint32_t l = 2; > + l = 200 - (uint32_t)f(); > + return l <= 100; // f() - 100 <= 100 > +} > + > +int32_t i2c(void) > +{ > + uint32_t l = 2; > + l = 300 - (uint32_t)f(); > + return l < 100; // f() - 201 <= 99 > +} > + > +int32_t i2d(void) > +{ > + uint32_t l = 2; > + l = 1000 - (uint32_t)f(); > + return l >= 2000; // f() + 999 > 1999 > +} > + > +int32_t i2e(void) > +{ > + uint32_t l = 2; > + l = 1000 - (uint32_t)f(); > + return l > 3000; // f() + 2000 > 3000 > +} > + > +int32_t i2f(void) > +{ > + uint32_t l = 2; > + l = 20000 - (uint32_t)f(); > + return l >= 10000; // f() - 10001 > 9999 > +} > + > +int32_t i2g(void) > +{ > + uint32_t l = 2; > + l = 30000 - (uint32_t)f(); > + return l > 10000; // f() - 20000 > 10000 > +} > + > +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 8 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 10.*\n.*<= 20" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 19.*\n.*<= 29" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294967196.*\n.*<= 100" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294967095.*\n.*<= 99" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 999.*\n.*> 1999" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 2000.*\n.*> 3000" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294957295.*\n.*> 9999" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294947296.*\n.*> 10000" 1 "forwprop1" } } */ > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c > new file mode 100644 > index 00000000000..ff8f097e647 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c > @@ -0,0 +1,38 @@ > +/* PR tree-optimization/116024 */ > +/* { dg-do compile } */ > +/* { dg-options "-O1 -fdump-tree-forwprop1-details -fwrapv" } */ > + > +#include <stdint.h> > +#include <limits.h> > + > +uint32_t f(void); > + > +int32_t i3(void) > +{ > + int32_t l = -10 + (int32_t)f(); > + return l <= INT_MAX - 10; // f() > INT_MIN + 9 > +} > + > +int32_t i3a(void) > +{ > + int32_t l = -21 + (int32_t)f(); > + return l < INT_MAX - 20; // f() > INT_MIN + 20 > +} > + > +int32_t i3b(void) > +{ > + int32_t l = 30 + (int32_t)f(); > + return l >= INT_MIN + 30; // f() <= INT_MAX - 30 > +} > + > +int32_t i3c(void) > +{ > + int32_t l = 40 + (int32_t)f(); > + return l > INT_MIN + 39; // f() <= INT_MAX - 39 > +} > + > +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*? \\+" 4 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* >= -2147483638" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* >= -2147483627" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 2147483618" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 2147483608" 1 "forwprop1" } } */ > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c > new file mode 100644 > index 00000000000..f7269765fcb > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c > @@ -0,0 +1,39 @@ > +/* 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 i3(void) > +{ > + uint32_t l = 2; > + l = UINT_MAX - 9 + (uint32_t)f(); > + return l <= UINT_MAX - 10; // f() > 9 > +} > + > +int32_t i3a(void) > +{ > + uint32_t l = UINT_MAX - 20 + (uint32_t)f(); > + return l < UINT_MAX - 20; // f() > 20 > +} > + > +int32_t i3b(void) > +{ > + uint32_t l = 30 + (uint32_t)f(); > + return l >= 30; // f() < -30u > +} > + > +int32_t i3c(void) > +{ > + uint32_t l = 40 + (uint32_t)f(); > + return l > 39; // f() < -39u > +} > + > +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*? \\+" 4 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 9" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 20" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 4294967265" 1 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 4294967255" 1 "forwprop1" } } */ > 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..22b08057b2b > --- /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 <= INT_MIN; // return 0 > +} > + > +int32_t i1b(void) > +{ > + int32_t l = 2; > + l = 30 - (int32_t)f(); > + return l <= INT_MIN + 31; // f() == INT_MAX > +} > + > +int32_t i1c(void) > +{ > + int32_t l = 2; > + l = INT_MAX - 40 - (int32_t)f(); > + return l <= -38; // f() > INT_MAX - 3 > +} > + > +int32_t i1d(void) > +{ > + int32_t l = 2; > + l = INT_MAX - 50 - (int32_t)f(); > + return l <= INT_MAX - 1; // f() != -50 > +} > + > +int32_t i1e(void) > +{ > + int32_t l = 2; > + l = INT_MAX - 60 - (int32_t)f(); > + return l != INT_MAX - 90; // f() != 30 > +} > + > +int32_t i1f(void) > +{ > + int32_t l = 2; > + l = INT_MIN + 70 - (int32_t)f(); > + return l <= INT_MAX - 2; // return 0 > +} > + > +int32_t i1g(void) > +{ > + int32_t l = 2; > + l = INT_MAX/2 + 30 - (int32_t)f(); > + return l <= INT_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" } } */ > diff --git a/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c b/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c > index 81c536c90af..bfcec6719de 100644 > --- a/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c > +++ b/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c > @@ -10,4 +10,4 @@ f1 (int x, int t) > return t; > } > > -/* { dg-final { scan-assembler-times "cmn\\tw\[0-9\]+, #2" 1 } } */ > +/* { dg-final { scan-assembler-times "cmn\\tw\[0-9\]+, #3" 1 } } */ >
On 8/22/2024 3:15 PM, Richard Biener wrote: > On Wed, 21 Aug 2024, Artemiy Volkov wrote: > >> Hi, >> >> sending a v2 of >> https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659851.html after >> changing variable types in all new testcases from standard to fixed-width. >> >> Could anyone please assist with reviewing and/or pushing to trunk/14 since I >> don't have commit access? >> >> Many thanks, >> Artemiy >> >> ---------- 8< ------------ >> >> This patch implements match.pd patterns for the following transformations: >> >> (1) (UB-on-overflow types) C1 - X cmp C2 -> X cmp C1 - C2 >> >> (2) (unsigned types) C1 - X cmp C2 -> >> (a) X cmp C1 - C2, when cmp is !=, == >> (b) X - (C1 - C2) cmp C2, when cmp is <=, > >> (c) X - (C1 - C2 + 1) cmp C2, when cmp is <, >=, >> >> (3) (signed wrapping types) C1 - X cmp C2 >> (a) X cmp C1 - C2, when cmp is !=, == >> (b) X - (C1 + 1) rcmp -(C2 + 1), otherwise >> >> (4) (all wrapping types) X + C1 cmp C2 -> >> (a) X cmp C2 - C1, when cmp is !=, == >> (b) X cmp -C1, when cmp is <=, > and C2 - C1 == max >> (c) X cmp -C1, when cmp is <, >= and C2 - C1 == min > > It would be easier to review if separating those, it wasn't all > clear what of (1) .. (4) corresponds to which hunk below. OK, I will split this patch into 4 in v3. > >> Included along are testcases for all the aforementioned changes. 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 transformations around integer comparison. >> >> gcc/testsuite/ChangeLog: >> >> * gcc.dg/tree-ssa/pr116024.c: New test. >> * gcc.dg/tree-ssa/pr116024-1.c: Ditto. >> * gcc.dg/tree-ssa/pr116024-1-fwrapv.c: Ditto. >> * gcc.dg/tree-ssa/pr116024-2.c: Ditto. >> * gcc.dg/tree-ssa/pr116024-2-fwrapv.c: Ditto. >> * gcc.dg/pr67089-6.c: Adjust. >> * gcc.target/aarch64/gtu_to_ltu_cmp_1.c: Ditto. >> >> Signed-off-by: Artemiy Volkov <artemiy@synopsys.com> >> --- >> gcc/match.pd | 75 ++++++++++++++++++- >> gcc/testsuite/gcc.dg/pr67089-6.c | 4 +- >> .../gcc.dg/tree-ssa/pr116024-1-fwrapv.c | 74 ++++++++++++++++++ >> gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c | 74 ++++++++++++++++++ >> .../gcc.dg/tree-ssa/pr116024-2-fwrapv.c | 38 ++++++++++ >> gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c | 39 ++++++++++ >> gcc/testsuite/gcc.dg/tree-ssa/pr116024.c | 74 ++++++++++++++++++ >> .../gcc.target/aarch64/gtu_to_ltu_cmp_1.c | 2 +- >> 8 files changed, 376 insertions(+), 4 deletions(-) >> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-1-fwrapv.c >> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c >> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c >> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c >> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024.c >> >> diff --git a/gcc/match.pd b/gcc/match.pd >> index 65a3aae2243..bf3ccef7437 100644 >> --- a/gcc/match.pd >> +++ b/gcc/match.pd >> @@ -8800,6 +8800,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) >> (cmp @0 { TREE_OVERFLOW (res) >> ? drop_tree_overflow (res) : res; })))))))) >> (for cmp (lt le gt ge) >> + rcmp (gt ge lt le) >> (for op (plus minus) >> rop (minus plus) >> (simplify >> @@ -8827,7 +8828,79 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) >> "X cmp C2 -+ C1"), >> WARN_STRICT_OVERFLOW_COMPARISON); >> } >> - (cmp @0 { res; }))))))))) >> + (cmp @0 { res; }))))) >> +/* For wrapping types, simplify X + C1 CMP C2 to X CMP -C1 when possible. */ > > it's more like X +- C1 CMP C2 to X CMP' C2 -+ C1 when C2 -+ C1 == +-INF? > > I have to think hard whether this requires an unsigned type > (naturally TYPE_OVERFLOW_WRAPS) or if it also works for signed > types (with -fwrapv). > > Can you explain? If CMP is <= and C2 -+ C1 == +INF, we can add -+C1 to both sides of the comparison (and use the fact that -INF <= X+-C1) to obtain (-INF-+C1 <=) X <= C2-+C1. The right part always holds, so we are left with -INF-+C1 <= X. (> is the negation of this, so -INF-+C1 > X). Similarly, for >= (and <), using the fact that X+-C1 <= +INF, we can eliminate C2 and simplify to X <= +INF-+C1. > >> + (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))) >> + (with >> + { >> + wide_int max = wi::max_value (TREE_TYPE (@0)); >> + wide_int min = wi::min_value (TREE_TYPE (@0)); >> + >> + wide_int c2 = rop == PLUS_EXPR >> + ? wi::add (wi::to_wide (@2), wi::to_wide (@1)) >> + : wi::sub (wi::to_wide (@2), wi::to_wide (@1)); >> + } >> + (if (((cmp == LE_EXPR || cmp == GT_EXPR) && wi::eq_p (c2, max)) >> + || ((cmp == LT_EXPR || cmp == GE_EXPR) && wi::eq_p (c2, min))) >> + (with >> + { >> + wide_int c1 = rop == PLUS_EXPR >> + ? wi::add (min, wi::to_wide (@1)) >> + : wi::sub (min, wi::to_wide (@1)); BTW, in accordance with the above, this should clearly be wi::{add,sub} (c2, wi::to_wide (@1)). This error did not cause any of the newly added tests to fail only because something had replaced < to <= and >= to > prior to the forwprop1 pass. I will correct this in v3. >> + tree c1_cst = build_uniform_cst (TREE_TYPE (@0), >> + wide_int_to_tree (TREE_TYPE (@0), c1)); >> + } >> + (rcmp @0 { c1_cst; }))))))))) >> + >> +/* 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) >> + (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)) >> + (with >> + { >> + fold_overflow_warning (("assuming signed overflow does not occur " >> + "when simplifying conditional to constant"), >> + WARN_STRICT_OVERFLOW_CONDITIONAL); >> + } >> + (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); >> + })) >> + (with >> + { >> + fold_overflow_warning (("assuming signed overflow does not occur " >> + "when changing C1 - X cmp C2 to " >> + "X cmp C1 - C2"), >> + WARN_STRICT_OVERFLOW_COMPARISON); > > please don't add more fold_overflow_warning OK, I will remove both warnings. > >> + } >> + (rcmp @1 { res; })))) >> + (if (TYPE_UNSIGNED (TREE_TYPE (@1))) >> + (switch >> + (if (cmp == EQ_EXPR || cmp == NE_EXPR) >> + (cmp @1 (minus @0 @2))) >> + (if (cmp == LE_EXPR || cmp == GT_EXPR) >> + (cmp (plus @1 (minus @2 @0)) @2)) > > Why's that an improvement? > >> + (if (cmp == LT_EXPR || cmp == GE_EXPR) >> + (cmp (plus @1 (minus @2 >> + (plus @0 { build_int_cst (TREE_TYPE (@1), 1); }))) @2))) > > Likewise? Can you add comments describing the transform before the > respective transforms? The rest of the cases (including these two above) are an improvement because the variable (@1) now appears with a plus instead of a minus sign, potentially saving sub instructions in generated code. E.g., currently on 32-bit RISC-V the expression "10 - (unsigned int) f() < 30" is computed using 3 instructions: li a5,10 sub a0,a5,a0 sltiu a0,a0,30 With my patch applied, it becomes 2: addi a0,a0,19 sltiu a0,a0,30 This was the motivating example in PR116024. > >> + (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1))) >> + (if (cmp == EQ_EXPR || cmp == NE_EXPR) >> + (cmp @1 (minus @0 @2)) >> + (rcmp (minus @1 (plus @0 { build_int_cst (TREE_TYPE (@1), 1); })) >> + (negate @2)))))))) > > why is the latter valid for all compares but the TYPE_UNSIGNED case is > not? I suppose this is for signed compares but without undefined > overflow? > > More comments would clearly help so that people later understand what > the different cases are. Yes, this is for !TYPE_UNSIGNED () && TYPE_OVERFLOW_WRAPS (), thus for signed integers under -fwrapv. The primary reason the approaches for unsigned and wrapping signed integers are different is that for the latter I can just negate C2 and invert the comparison, and for unsigned types it's easier to replace C1 - X CMP C2 with X + (C2 - C1) CMP C2 (with additional adjustments in both cases). I will make sure to add more comments describing all of this to match.pd in v3. Thanks for taking a look, Artemiy > >> >> /* Canonicalizations of BIT_FIELD_REFs. */ >> >> 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-1-fwrapv.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1-fwrapv.c >> new file mode 100644 >> index 00000000000..1fe8c821bec >> --- /dev/null >> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1-fwrapv.c >> @@ -0,0 +1,74 @@ >> +/* PR tree-optimization/116024 */ >> +/* { dg-do compile } */ >> +/* { dg-options "-O1 -fdump-tree-forwprop1-details -fwrapv" } */ >> + >> +#include <stdint.h> >> +#include <limits.h> >> + >> +uint32_t f(void); >> + >> +int32_t i2(void) >> +{ >> + int32_t l = 2; >> + l = 10 - (int32_t)f(); >> + return l <= 20; // f() + 10 + INT_MIN <= 20 >> +} >> + >> +int32_t i2a(void) >> +{ >> + int32_t l = 2; >> + l = 10 - (int32_t)f(); >> + return l < 30; // f() + 19 + INT_MIN <= 29 >> +} >> + >> +int32_t i2b(void) >> +{ >> + int32_t l = 2; >> + l = 200 - (int32_t)f(); >> + return l <= 100; // f() - 100 + INT_MIN <= 100 >> +} >> + >> +int32_t i2c(void) >> +{ >> + int32_t l = 2; >> + l = 300 - (int32_t)f(); >> + return l < 100; // f() - 201 + INT_MIN <= 99 >> +} >> + >> +int32_t i2d(void) >> +{ >> + int32_t l = 2; >> + l = 1000 - (int32_t)f(); >> + return l >= 2000; // f() + 999 + INT_MIN > 1999 >> +} >> + >> +int32_t i2e(void) >> +{ >> + int32_t l = 2; >> + l = 1000 - (int32_t)f(); >> + return l > 3000; // f() + 2000 + INT_MIN > 3000 >> +} >> + >> +int32_t i2f(void) >> +{ >> + int32_t l = 2; >> + l = 20000 - (int32_t)f(); >> + return l >= 10000; // f() - 10001 + INT_MIN > 9999 >> +} >> + >> +int32_t i2g(void) >> +{ >> + int32_t l = 2; >> + l = 30000 - (int32_t)f(); >> + return l > 10000; // f() - 20000 + INT_MIN > 10000 >> +} >> + >> +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 8 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -11.*\n.*>= -20" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -11.*\n.*>= -29" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -201.*\n.*>= -100" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -301.*\n.*>= -99" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -1001.*\n.*< -1999" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -1001.*\n.*< -3000" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -20001.*\n.*< -9999" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -30001.*\n.*< -10000" 1 "forwprop1" } } */ >> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c >> new file mode 100644 >> index 00000000000..ecafb41fa09 >> --- /dev/null >> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.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 i2(void) >> +{ >> + uint32_t l = 2; >> + l = 10 - (uint32_t)f(); >> + return l <= 20; // f() + 10 <= 20 >> +} >> + >> +int32_t i2a(void) >> +{ >> + uint32_t l = 2; >> + l = 10 - (uint32_t)f(); >> + return l < 30; // f() + 19 <= 29 >> +} >> + >> +int32_t i2b(void) >> +{ >> + uint32_t l = 2; >> + l = 200 - (uint32_t)f(); >> + return l <= 100; // f() - 100 <= 100 >> +} >> + >> +int32_t i2c(void) >> +{ >> + uint32_t l = 2; >> + l = 300 - (uint32_t)f(); >> + return l < 100; // f() - 201 <= 99 >> +} >> + >> +int32_t i2d(void) >> +{ >> + uint32_t l = 2; >> + l = 1000 - (uint32_t)f(); >> + return l >= 2000; // f() + 999 > 1999 >> +} >> + >> +int32_t i2e(void) >> +{ >> + uint32_t l = 2; >> + l = 1000 - (uint32_t)f(); >> + return l > 3000; // f() + 2000 > 3000 >> +} >> + >> +int32_t i2f(void) >> +{ >> + uint32_t l = 2; >> + l = 20000 - (uint32_t)f(); >> + return l >= 10000; // f() - 10001 > 9999 >> +} >> + >> +int32_t i2g(void) >> +{ >> + uint32_t l = 2; >> + l = 30000 - (uint32_t)f(); >> + return l > 10000; // f() - 20000 > 10000 >> +} >> + >> +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 8 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 10.*\n.*<= 20" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 19.*\n.*<= 29" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294967196.*\n.*<= 100" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294967095.*\n.*<= 99" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 999.*\n.*> 1999" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 2000.*\n.*> 3000" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294957295.*\n.*> 9999" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294947296.*\n.*> 10000" 1 "forwprop1" } } */ >> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c >> new file mode 100644 >> index 00000000000..ff8f097e647 >> --- /dev/null >> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c >> @@ -0,0 +1,38 @@ >> +/* PR tree-optimization/116024 */ >> +/* { dg-do compile } */ >> +/* { dg-options "-O1 -fdump-tree-forwprop1-details -fwrapv" } */ >> + >> +#include <stdint.h> >> +#include <limits.h> >> + >> +uint32_t f(void); >> + >> +int32_t i3(void) >> +{ >> + int32_t l = -10 + (int32_t)f(); >> + return l <= INT_MAX - 10; // f() > INT_MIN + 9 >> +} >> + >> +int32_t i3a(void) >> +{ >> + int32_t l = -21 + (int32_t)f(); >> + return l < INT_MAX - 20; // f() > INT_MIN + 20 >> +} >> + >> +int32_t i3b(void) >> +{ >> + int32_t l = 30 + (int32_t)f(); >> + return l >= INT_MIN + 30; // f() <= INT_MAX - 30 >> +} >> + >> +int32_t i3c(void) >> +{ >> + int32_t l = 40 + (int32_t)f(); >> + return l > INT_MIN + 39; // f() <= INT_MAX - 39 >> +} >> + >> +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*? \\+" 4 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* >= -2147483638" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* >= -2147483627" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 2147483618" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 2147483608" 1 "forwprop1" } } */ >> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c >> new file mode 100644 >> index 00000000000..f7269765fcb >> --- /dev/null >> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c >> @@ -0,0 +1,39 @@ >> +/* 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 i3(void) >> +{ >> + uint32_t l = 2; >> + l = UINT_MAX - 9 + (uint32_t)f(); >> + return l <= UINT_MAX - 10; // f() > 9 >> +} >> + >> +int32_t i3a(void) >> +{ >> + uint32_t l = UINT_MAX - 20 + (uint32_t)f(); >> + return l < UINT_MAX - 20; // f() > 20 >> +} >> + >> +int32_t i3b(void) >> +{ >> + uint32_t l = 30 + (uint32_t)f(); >> + return l >= 30; // f() < -30u >> +} >> + >> +int32_t i3c(void) >> +{ >> + uint32_t l = 40 + (uint32_t)f(); >> + return l > 39; // f() < -39u >> +} >> + >> +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*? \\+" 4 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 9" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 20" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 4294967265" 1 "forwprop1" } } */ >> +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 4294967255" 1 "forwprop1" } } */ >> 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..22b08057b2b >> --- /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 <= INT_MIN; // return 0 >> +} >> + >> +int32_t i1b(void) >> +{ >> + int32_t l = 2; >> + l = 30 - (int32_t)f(); >> + return l <= INT_MIN + 31; // f() == INT_MAX >> +} >> + >> +int32_t i1c(void) >> +{ >> + int32_t l = 2; >> + l = INT_MAX - 40 - (int32_t)f(); >> + return l <= -38; // f() > INT_MAX - 3 >> +} >> + >> +int32_t i1d(void) >> +{ >> + int32_t l = 2; >> + l = INT_MAX - 50 - (int32_t)f(); >> + return l <= INT_MAX - 1; // f() != -50 >> +} >> + >> +int32_t i1e(void) >> +{ >> + int32_t l = 2; >> + l = INT_MAX - 60 - (int32_t)f(); >> + return l != INT_MAX - 90; // f() != 30 >> +} >> + >> +int32_t i1f(void) >> +{ >> + int32_t l = 2; >> + l = INT_MIN + 70 - (int32_t)f(); >> + return l <= INT_MAX - 2; // return 0 >> +} >> + >> +int32_t i1g(void) >> +{ >> + int32_t l = 2; >> + l = INT_MAX/2 + 30 - (int32_t)f(); >> + return l <= INT_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" } } */ >> diff --git a/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c b/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c >> index 81c536c90af..bfcec6719de 100644 >> --- a/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c >> +++ b/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c >> @@ -10,4 +10,4 @@ f1 (int x, int t) >> return t; >> } >> >> -/* { dg-final { scan-assembler-times "cmn\\tw\[0-9\]+, #2" 1 } } */ >> +/* { dg-final { scan-assembler-times "cmn\\tw\[0-9\]+, #3" 1 } } */ >> >
diff --git a/gcc/match.pd b/gcc/match.pd index 65a3aae2243..bf3ccef7437 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -8800,6 +8800,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (cmp @0 { TREE_OVERFLOW (res) ? drop_tree_overflow (res) : res; })))))))) (for cmp (lt le gt ge) + rcmp (gt ge lt le) (for op (plus minus) rop (minus plus) (simplify @@ -8827,7 +8828,79 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) "X cmp C2 -+ C1"), WARN_STRICT_OVERFLOW_COMPARISON); } - (cmp @0 { res; }))))))))) + (cmp @0 { res; }))))) +/* For wrapping types, simplify X + C1 CMP C2 to X CMP -C1 when possible. */ + (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))) + (with + { + wide_int max = wi::max_value (TREE_TYPE (@0)); + wide_int min = wi::min_value (TREE_TYPE (@0)); + + wide_int c2 = rop == PLUS_EXPR + ? wi::add (wi::to_wide (@2), wi::to_wide (@1)) + : wi::sub (wi::to_wide (@2), wi::to_wide (@1)); + } + (if (((cmp == LE_EXPR || cmp == GT_EXPR) && wi::eq_p (c2, max)) + || ((cmp == LT_EXPR || cmp == GE_EXPR) && wi::eq_p (c2, min))) + (with + { + wide_int c1 = rop == PLUS_EXPR + ? wi::add (min, wi::to_wide (@1)) + : wi::sub (min, wi::to_wide (@1)); + tree c1_cst = build_uniform_cst (TREE_TYPE (@0), + wide_int_to_tree (TREE_TYPE (@0), c1)); + } + (rcmp @0 { c1_cst; }))))))))) + +/* 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) + (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)) + (with + { + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying conditional to constant"), + WARN_STRICT_OVERFLOW_CONDITIONAL); + } + (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); + })) + (with + { + fold_overflow_warning (("assuming signed overflow does not occur " + "when changing C1 - X cmp C2 to " + "X cmp C1 - C2"), + WARN_STRICT_OVERFLOW_COMPARISON); + } + (rcmp @1 { res; })))) + (if (TYPE_UNSIGNED (TREE_TYPE (@1))) + (switch + (if (cmp == EQ_EXPR || cmp == NE_EXPR) + (cmp @1 (minus @0 @2))) + (if (cmp == LE_EXPR || cmp == GT_EXPR) + (cmp (plus @1 (minus @2 @0)) @2)) + (if (cmp == LT_EXPR || cmp == GE_EXPR) + (cmp (plus @1 (minus @2 + (plus @0 { build_int_cst (TREE_TYPE (@1), 1); }))) @2))) + (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1))) + (if (cmp == EQ_EXPR || cmp == NE_EXPR) + (cmp @1 (minus @0 @2)) + (rcmp (minus @1 (plus @0 { build_int_cst (TREE_TYPE (@1), 1); })) + (negate @2)))))))) /* Canonicalizations of BIT_FIELD_REFs. */ 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-1-fwrapv.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1-fwrapv.c new file mode 100644 index 00000000000..1fe8c821bec --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1-fwrapv.c @@ -0,0 +1,74 @@ +/* PR tree-optimization/116024 */ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-forwprop1-details -fwrapv" } */ + +#include <stdint.h> +#include <limits.h> + +uint32_t f(void); + +int32_t i2(void) +{ + int32_t l = 2; + l = 10 - (int32_t)f(); + return l <= 20; // f() + 10 + INT_MIN <= 20 +} + +int32_t i2a(void) +{ + int32_t l = 2; + l = 10 - (int32_t)f(); + return l < 30; // f() + 19 + INT_MIN <= 29 +} + +int32_t i2b(void) +{ + int32_t l = 2; + l = 200 - (int32_t)f(); + return l <= 100; // f() - 100 + INT_MIN <= 100 +} + +int32_t i2c(void) +{ + int32_t l = 2; + l = 300 - (int32_t)f(); + return l < 100; // f() - 201 + INT_MIN <= 99 +} + +int32_t i2d(void) +{ + int32_t l = 2; + l = 1000 - (int32_t)f(); + return l >= 2000; // f() + 999 + INT_MIN > 1999 +} + +int32_t i2e(void) +{ + int32_t l = 2; + l = 1000 - (int32_t)f(); + return l > 3000; // f() + 2000 + INT_MIN > 3000 +} + +int32_t i2f(void) +{ + int32_t l = 2; + l = 20000 - (int32_t)f(); + return l >= 10000; // f() - 10001 + INT_MIN > 9999 +} + +int32_t i2g(void) +{ + int32_t l = 2; + l = 30000 - (int32_t)f(); + return l > 10000; // f() - 20000 + INT_MIN > 10000 +} + +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 8 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -11.*\n.*>= -20" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -11.*\n.*>= -29" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -201.*\n.*>= -100" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -301.*\n.*>= -99" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -1001.*\n.*< -1999" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -1001.*\n.*< -3000" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -20001.*\n.*< -9999" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ -30001.*\n.*< -10000" 1 "forwprop1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c new file mode 100644 index 00000000000..ecafb41fa09 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.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 i2(void) +{ + uint32_t l = 2; + l = 10 - (uint32_t)f(); + return l <= 20; // f() + 10 <= 20 +} + +int32_t i2a(void) +{ + uint32_t l = 2; + l = 10 - (uint32_t)f(); + return l < 30; // f() + 19 <= 29 +} + +int32_t i2b(void) +{ + uint32_t l = 2; + l = 200 - (uint32_t)f(); + return l <= 100; // f() - 100 <= 100 +} + +int32_t i2c(void) +{ + uint32_t l = 2; + l = 300 - (uint32_t)f(); + return l < 100; // f() - 201 <= 99 +} + +int32_t i2d(void) +{ + uint32_t l = 2; + l = 1000 - (uint32_t)f(); + return l >= 2000; // f() + 999 > 1999 +} + +int32_t i2e(void) +{ + uint32_t l = 2; + l = 1000 - (uint32_t)f(); + return l > 3000; // f() + 2000 > 3000 +} + +int32_t i2f(void) +{ + uint32_t l = 2; + l = 20000 - (uint32_t)f(); + return l >= 10000; // f() - 10001 > 9999 +} + +int32_t i2g(void) +{ + uint32_t l = 2; + l = 30000 - (uint32_t)f(); + return l > 10000; // f() - 20000 > 10000 +} + +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*?- _" 8 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 10.*\n.*<= 20" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 19.*\n.*<= 29" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294967196.*\n.*<= 100" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294967095.*\n.*<= 99" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 999.*\n.*> 1999" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 2000.*\n.*> 3000" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294957295.*\n.*> 9999" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* \\+ 4294947296.*\n.*> 10000" 1 "forwprop1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c new file mode 100644 index 00000000000..ff8f097e647 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c @@ -0,0 +1,38 @@ +/* PR tree-optimization/116024 */ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-forwprop1-details -fwrapv" } */ + +#include <stdint.h> +#include <limits.h> + +uint32_t f(void); + +int32_t i3(void) +{ + int32_t l = -10 + (int32_t)f(); + return l <= INT_MAX - 10; // f() > INT_MIN + 9 +} + +int32_t i3a(void) +{ + int32_t l = -21 + (int32_t)f(); + return l < INT_MAX - 20; // f() > INT_MIN + 20 +} + +int32_t i3b(void) +{ + int32_t l = 30 + (int32_t)f(); + return l >= INT_MIN + 30; // f() <= INT_MAX - 30 +} + +int32_t i3c(void) +{ + int32_t l = 40 + (int32_t)f(); + return l > INT_MIN + 39; // f() <= INT_MAX - 39 +} + +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*? \\+" 4 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* >= -2147483638" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* >= -2147483627" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 2147483618" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 2147483608" 1 "forwprop1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c new file mode 100644 index 00000000000..f7269765fcb --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c @@ -0,0 +1,39 @@ +/* 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 i3(void) +{ + uint32_t l = 2; + l = UINT_MAX - 9 + (uint32_t)f(); + return l <= UINT_MAX - 10; // f() > 9 +} + +int32_t i3a(void) +{ + uint32_t l = UINT_MAX - 20 + (uint32_t)f(); + return l < UINT_MAX - 20; // f() > 20 +} + +int32_t i3b(void) +{ + uint32_t l = 30 + (uint32_t)f(); + return l >= 30; // f() < -30u +} + +int32_t i3c(void) +{ + uint32_t l = 40 + (uint32_t)f(); + return l > 39; // f() < -39u +} + +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*? \\+" 4 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 9" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 20" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 4294967265" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 4294967255" 1 "forwprop1" } } */ 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..22b08057b2b --- /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 <= INT_MIN; // return 0 +} + +int32_t i1b(void) +{ + int32_t l = 2; + l = 30 - (int32_t)f(); + return l <= INT_MIN + 31; // f() == INT_MAX +} + +int32_t i1c(void) +{ + int32_t l = 2; + l = INT_MAX - 40 - (int32_t)f(); + return l <= -38; // f() > INT_MAX - 3 +} + +int32_t i1d(void) +{ + int32_t l = 2; + l = INT_MAX - 50 - (int32_t)f(); + return l <= INT_MAX - 1; // f() != -50 +} + +int32_t i1e(void) +{ + int32_t l = 2; + l = INT_MAX - 60 - (int32_t)f(); + return l != INT_MAX - 90; // f() != 30 +} + +int32_t i1f(void) +{ + int32_t l = 2; + l = INT_MIN + 70 - (int32_t)f(); + return l <= INT_MAX - 2; // return 0 +} + +int32_t i1g(void) +{ + int32_t l = 2; + l = INT_MAX/2 + 30 - (int32_t)f(); + return l <= INT_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" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c b/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c index 81c536c90af..bfcec6719de 100644 --- a/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c +++ b/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c @@ -10,4 +10,4 @@ f1 (int x, int t) return t; } -/* { dg-final { scan-assembler-times "cmn\\tw\[0-9\]+, #2" 1 } } */ +/* { dg-final { scan-assembler-times "cmn\\tw\[0-9\]+, #3" 1 } } */
Hi, sending a v2 of https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659851.html after changing variable types in all new testcases from standard to fixed-width. Could anyone please assist with reviewing and/or pushing to trunk/14 since I don't have commit access? Many thanks, Artemiy ---------- 8< ------------ This patch implements match.pd patterns for the following transformations: (1) (UB-on-overflow types) C1 - X cmp C2 -> X cmp C1 - C2 (2) (unsigned types) C1 - X cmp C2 -> (a) X cmp C1 - C2, when cmp is !=, == (b) X - (C1 - C2) cmp C2, when cmp is <=, > (c) X - (C1 - C2 + 1) cmp C2, when cmp is <, >=, (3) (signed wrapping types) C1 - X cmp C2 (a) X cmp C1 - C2, when cmp is !=, == (b) X - (C1 + 1) rcmp -(C2 + 1), otherwise (4) (all wrapping types) X + C1 cmp C2 -> (a) X cmp C2 - C1, when cmp is !=, == (b) X cmp -C1, when cmp is <=, > and C2 - C1 == max (c) X cmp -C1, when cmp is <, >= and C2 - C1 == min Included along are testcases for all the aforementioned changes. 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 transformations around integer comparison. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr116024.c: New test. * gcc.dg/tree-ssa/pr116024-1.c: Ditto. * gcc.dg/tree-ssa/pr116024-1-fwrapv.c: Ditto. * gcc.dg/tree-ssa/pr116024-2.c: Ditto. * gcc.dg/tree-ssa/pr116024-2-fwrapv.c: Ditto. * gcc.dg/pr67089-6.c: Adjust. * gcc.target/aarch64/gtu_to_ltu_cmp_1.c: Ditto. Signed-off-by: Artemiy Volkov <artemiy@synopsys.com> --- gcc/match.pd | 75 ++++++++++++++++++- gcc/testsuite/gcc.dg/pr67089-6.c | 4 +- .../gcc.dg/tree-ssa/pr116024-1-fwrapv.c | 74 ++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c | 74 ++++++++++++++++++ .../gcc.dg/tree-ssa/pr116024-2-fwrapv.c | 38 ++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c | 39 ++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr116024.c | 74 ++++++++++++++++++ .../gcc.target/aarch64/gtu_to_ltu_cmp_1.c | 2 +- 8 files changed, 376 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-1-fwrapv.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr116024.c