Expressions of the form "X + CST < Y + CST" where: * CST is an unsigned integer constant with only the MSB set, and * X and Y's types have integer conversion ranks <= CST's
can be simplified to "(signed) X < (signed) Y". This is because, assuming a 32-bit signed numbers, (unsigned) INT_MIN + 0x80000000 is 0, and (unsigned) INT_MAX + 0x80000000 is UINT_MAX. i.e. the result increases monotonically with signed input. This means: ((signed) X < (signed) Y) iff (X + 0x80000000 < Y + 0x80000000) gcc/ * match.pd (X + C < Y + C -> (signed) X < (signed) Y, if C is 0x80000000): New simplification. gcc/testsuite/ * gcc.dg/pr94899.c: New test. --- gcc/match.pd | 13 +++++++++ gcc/testsuite/gcc.dg/pr94899.c | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/pr94899.c --- v1: https://gcc.gnu.org/pipermail/gcc-patches/2022-February/589557.html Notes on v2, based on Richard's review comments: 1. I removed matching on "convert", and therefore also replaced the removal of convert upon simplification with an explicit cast to signed. I originally thought this simplification only applies to signed operands that have been cast to unsigned, but thinking about it, it became clear that they do not necessarily have to be signed originally. The simplification is now a bit more general. 2. Removed checks for operands' types as it seems to be unnecessary. I hope this is correct. 3. Added unsigned types and mismatched sizes of operands to the test. These are now simplified.
diff --git a/gcc/match.pd b/gcc/match.pd index b942cb2930a..fabb06c6808 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1975,6 +1975,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))) (op @0 @1)))) + +/* As a special case, X + C < Y + C is the same as (signed) X < (signed) Y + when C is an unsigned integer constant with only the MSB set, and X and + Y have types of equal or lower integer conversion rank than C's. */ +(for op (lt le ge gt) + (simplify + (op (plus:c INTEGER_CST@0 @1) (plus:c INTEGER_CST@0 @2)) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && TYPE_UNSIGNED (TREE_TYPE (@0)) + && wi::only_sign_bit_p (wi::to_wide (@0))) + (with { tree stype = signed_type_for (TREE_TYPE (@0)); } + (op (convert:stype @1) (convert:stype @2)))))) + /* For equality and subtraction, this is also true with wrapping overflow. */ (for op (eq ne minus) (simplify diff --git a/gcc/testsuite/gcc.dg/pr94899.c b/gcc/testsuite/gcc.dg/pr94899.c new file mode 100644 index 00000000000..f47120988b7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr94899.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +typedef __INT16_TYPE__ int16_t; +typedef __INT32_TYPE__ int32_t; +typedef __UINT16_TYPE__ uint16_t; +typedef __UINT32_TYPE__ uint32_t; + +#define MAGIC 0x80000000 + +int +f_i16_i16 (int16_t x, int16_t y) +{ + return x + MAGIC < y + MAGIC; +} + +int +f_i16_i32 (int16_t x, int32_t y) +{ + return x + MAGIC < y + MAGIC; +} + +int +f_i32_i32 (int32_t x, int32_t y) +{ + return x + MAGIC < y + MAGIC; +} + +int +f_u32_i32 (uint32_t x, int32_t y) +{ + return x + MAGIC < y + MAGIC; +} + +int +f_u32_u32 (uint32_t x, uint32_t y) +{ + return x + MAGIC < y + MAGIC; +} + +int +f_i32_i32_sub (int32_t x, int32_t y) +{ + return x - MAGIC < y - MAGIC; +} + +/* The constants above should have been optimized away. */ +/* { dg-final { scan-tree-dump-times "2147483648" 0 "optimized"} } */ -- 2.34.1