[PATCH v2] MATCH: Fold `A CMP B ? A - B : B - A` to abs of difference [PR50856]
Eikansh Gupta <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
Recognize the absolute-difference idiom whose selector compares the operands directly (a > b ? a - b : b - a), optionally widened, as +/- abs (A - B). The same-width case is not folded under -fsanitize=signed-integer-overflow so the rewrite does not move the overflow the sanitizer reports. The transformation A </<= B ? A - B : B - A -> -abs (A - B) is only for widened operation. For same precision operands it can introduce new undefined behaviour for case a=0 and b=INT_MIN. (b-a) is defined for given values. But -abs(a-b) overflows. Transforming to abs(b-a) does not solve it either as for a=INT_MIN and b=0, (b-a) overflows. PR tree-optimization/50856 gcc/ChangeLog: * match.pd (A CMP B ? A - B : B - A -> +/- abs (A - B)): New patterns. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr50856.c: New test. * g++.target/aarch64/pr50856.C: New test. Signed-off-by: Eikansh Gupta <[email protected]> --- gcc/match.pd | 36 +++++++++++++++++++ gcc/testsuite/g++.target/aarch64/pr50856.C | 26 ++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr50856.c | 41 ++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 gcc/testsuite/g++.target/aarch64/pr50856.C create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr50856.c diff --git a/gcc/match.pd b/gcc/match.pd index a7cec25dbad..0e9e52a3387 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -7154,6 +7154,42 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (convert (negate (absu:utype @0)))) (negate (abs @0))))) ) + /* A >/>= B ? A - B : B - A -> abs (A - B) + with the operands optionally widened first. */ + (for cmp (gt ge) + (simplify + (cnd (cmp @0 @1) + (minus@4 (convert1?@2 @0) (convert2?@3 @1)) + (minus @3 @2)) + (if (ANY_INTEGRAL_TYPE_P (type) + && !TYPE_UNSIGNED (type) + && types_match (TREE_TYPE (@0), TREE_TYPE (@1)) + && (element_precision (@0) < element_precision (type) + /* The below checks are for same width operands. */ + || (types_match (TREE_TYPE (@0), type) + && TYPE_OVERFLOW_UNDEFINED (type) + /* Hoisting A - B out of the selector could move the + overflow the sanitizer reports. */ + && !sanitize_flags_p (SANITIZE_SI_OVERFLOW))) + && (!VECTOR_TYPE_P (type) + || target_supports_op_p (type, ABS_EXPR, optab_vector))) + (abs @4)))) + /* A </<= B ? A - B : B - A -> -abs (A - B). Widened operands only. + This pattern is only for widened operands as for same precision operands + there can be a new undefined behaviour for case a=0 and b=INT_MIN. */ + (for cmp (lt le) + (simplify + (cnd (cmp @0 @1) + (minus@4 (convert1?@2 @0) (convert2?@3 @1)) + (minus @3 @2)) + (if (ANY_INTEGRAL_TYPE_P (type) + && !TYPE_UNSIGNED (type) + && types_match (TREE_TYPE (@0), TREE_TYPE (@1)) + && element_precision (@0) < element_precision (type) + && (!VECTOR_TYPE_P (type) + || (target_supports_op_p (type, ABS_EXPR, optab_vector) + && target_supports_op_p (type, NEGATE_EXPR, optab_vector)))) + (negate (abs @4))))) ) /* -(type)!A -> (type)A - 1. */ diff --git a/gcc/testsuite/g++.target/aarch64/pr50856.C b/gcc/testsuite/g++.target/aarch64/pr50856.C new file mode 100644 index 00000000000..f10f16f3834 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/pr50856.C @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +/* vector a CMP b ? a - b : b - a -> abs(a - b). Folds when the + target has a vector abs. */ + +typedef short v8hi __attribute__ ((vector_size (16))); +typedef int v4si __attribute__ ((vector_size (16))); + +v8hi abd_h (v8hi a, v8hi b) +{ + return a > b ? a - b : b - a; +} + +v4si abd_s (v4si a, v4si b) +{ + return a >= b ? a - b : b - a; +} + +/* Same-width -abs must not fold. */ +v8hi nabd_h (v8hi a, v8hi b) +{ + return a < b ? a - b : b - a; +} + +/* { dg-final { scan-tree-dump-times "ABS_EXPR" 2 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr50856.c b/gcc/testsuite/gcc.dg/tree-ssa/pr50856.c new file mode 100644 index 00000000000..3c0513efbbd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr50856.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +/* a CMP b ? a - b : b - a -> +/- abs (a - b). */ + +int gt_w (unsigned char a, unsigned char b) +{ + int x = a, y = b; + return a > b ? x - y : y - x; +} + +int ge_w (unsigned char a, unsigned char b) +{ + int x = a, y = b; + return a >= b ? x - y : y - x; +} + +int lt_w (unsigned char a, unsigned char b) +{ + int x = a, y = b; + return a < b ? x - y : y - x; +} + +int le_w (unsigned char a, unsigned char b) +{ + int x = a, y = b; + return a <= b ? x - y : y - x; +} + +int gt_i (int a, int b) +{ + return a > b ? a - b : b - a; +} + +/* Same-width -abs must not fold. */ +int lt_i (int a, int b) +{ + return a < b ? a - b : b - a; +} + +/* { dg-final { scan-tree-dump-times "ABS_EXPR" 5 "optimized" } } */ -- 2.34.1