https://gcc.gnu.org/g:c59bee6acb24a0d580f4c98a14e879452096220e
commit r17-3190-gc59bee6acb24a0d580f4c98a14e879452096220e Author: Tudor-Stefan Magirescu <[email protected]> Date: Mon Aug 10 18:11:45 2026 +0200 tree-optimization: Simplify ((X CMP1 Y) - (X CMP2 Y)) REL 0 Add a new match.pd pattern to fold sign-of-difference expressions into a single comparison. The pattern matches differences of two comparisons of the same operands, where the comparison pair is one of {gt,lt} or {ge,le}. The pattern cannot be merged into the generic (X - Y) CMP 0 rule above it, which is restricted to eq/ne. Extending that rule to lt/le/gt/ge would defeat ABS_EXPR synthesis in fold_cond_expr_with_comparison for expressions of the form (X - Y) < 0 ? (Y - X) : (X - Y). Matching the full comparison structure avoids this regression. Bootstrapped and tested on x86_64-linux-gnu. gcc/ChangeLog: * match.pd (((X CMP1 Y) - (X CMP2 Y)) REL 0): New pattern. gcc/testsuite/ChangeLog: * gcc.c-torture/execute/subcmp-1.c: New test. * gcc.dg/tree-ssa/subcmp-1.c: New test. Signed-off-by: Tudor-Stefan Magirescu <[email protected]> Diff: --- gcc/match.pd | 15 +++ gcc/testsuite/gcc.c-torture/execute/subcmp-1.c | 55 +++++++++++ gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c | 131 +++++++++++++++++++++++++ 3 files changed, 201 insertions(+) diff --git a/gcc/match.pd b/gcc/match.pd index 0ba97b32cb13..50e731770228 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -7599,6 +7599,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (single_use (@2)) (cmp @0 @1))))) +/* Fold ((X CMP1 Y) - (X CMP2 Y)) REL 0 into a single comparison of X and Y, + e.g., ((X > Y) - (X < Y)) < 0 to X < Y. This cannot be merged into the + generic X - Y CMP 0 rule above as it would prevent ABS_EXPR synthesis in + fold_cond_expr_with_comparison. */ +(for rel (lt le gt ge) + (for cmp1 (gt ge) + cmp2 (lt le) + (simplify + (rel (minus@2 (convert? (cmp1:c @0 @1)) + (convert? (cmp2:c @0 @1))) integer_zerop) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && !TYPE_UNSIGNED (TREE_TYPE (@2)) + && TYPE_PRECISION (TREE_TYPE (@2)) > 1) + (rel @0 @1))))) + /* Simplify (x < 0) ^ (y < 0) to (x ^ y) < 0 and (x >= 0) ^ (y >= 0) to (x ^ y) < 0. */ (for cmp (lt ge) diff --git a/gcc/testsuite/gcc.c-torture/execute/subcmp-1.c b/gcc/testsuite/gcc.c-torture/execute/subcmp-1.c new file mode 100644 index 000000000000..4682246c3552 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/subcmp-1.c @@ -0,0 +1,55 @@ +#define func(vol, op1, op2, op3) \ +_Bool op1##_##op2##_##op3##_##vol (int a, int b) \ +{ \ + vol _Bool x = op_##op1(a, b); \ + vol _Bool y = op_##op2(a, b); \ + return op_##op3(x - y, 0); \ +} + +#define op_lt(a, b) ((a) < (b)) +#define op_le(a, b) ((a) <= (b)) +#define op_gt(a, b) ((a) > (b)) +#define op_ge(a, b) ((a) >= (b)) + +#define funcs(a) \ + a(gt,lt,lt) \ + a(gt,lt,le) \ + a(gt,lt,gt) \ + a(gt,lt,ge) \ + \ + a(ge,le,lt) \ + a(ge,le,le) \ + a(ge,le,gt) \ + a(ge,le,ge) \ + \ + a(lt,gt,lt) \ + a(lt,gt,le) \ + a(lt,gt,gt) \ + a(lt,gt,ge) \ + \ + a(le,ge,lt) \ + a(le,ge,le) \ + a(le,ge,gt) \ + a(le,ge,ge) \ + +#define funcs1(a,b,c) \ +func(,a,b,c) \ +func(volatile,a,b,c) + +funcs(funcs1) + +#define test(op1,op2,op3) \ +do { \ + if (op1##_##op2##_##op3##_(x,y) \ + != op1##_##op2##_##op3##_volatile(x,y)) \ + __builtin_abort(); \ +} while(0); + +int main() +{ + for(int x = -10; x < 10; x++) + for(int y = -10; y < 10; y++) + { + funcs(test) + } +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c b/gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c new file mode 100644 index 000000000000..489cf4c1f406 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c @@ -0,0 +1,131 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +_Bool subgtlt_lt(int a00, int b00) +{ + _Bool x00 = a00 > b00; + _Bool y00 = a00 < b00; + return x00 - y00 < 0; +} +/* { dg-final { scan-tree-dump "a00_\[0-9\]+.D. < b00_\[0-9\]+.D.|b00_\[0-9\]+.D. > a00_\[0-9\]+.D." "optimized" } } */ + +_Bool subgtlt_le(int a01, int b01) +{ + _Bool x01 = a01 > b01; + _Bool y01 = a01 < b01; + return x01 - y01 <= 0; +} +/* { dg-final { scan-tree-dump "a01_\[0-9\]+.D. <= b01_\[0-9\]+.D.|b01_\[0-9\]+.D. >= a01_\[0-9\]+.D." "optimized" } } */ + +_Bool subgtlt_gt(int a02, int b02) +{ + _Bool x02 = a02 > b02; + _Bool y02 = a02 < b02; + return x02 - y02 > 0; +} +/* { dg-final { scan-tree-dump "a02_\[0-9\]+.D. > b02_\[0-9\]+.D.|b02_\[0-9\]+.D. < a02_\[0-9\]+.D." "optimized" } } */ + +_Bool subgtlt_ge(int a03, int b03) +{ + _Bool x03 = a03 > b03; + _Bool y03 = a03 < b03; + return x03 - y03 >= 0; +} +/* { dg-final { scan-tree-dump "a03_\[0-9\]+.D. >= b03_\[0-9\]+.D.|b03_\[0-9\]+.D. <= a03_\[0-9\]+.D." "optimized" } } */ + +_Bool subgele_lt(int a04, int b04) +{ + _Bool x04 = a04 >= b04; + _Bool y04 = a04 <= b04; + return x04 - y04 < 0; +} +/* { dg-final { scan-tree-dump "a04_\[0-9\]+.D. < b04_\[0-9\]+.D.|b04_\[0-9\]+.D. > a04_\[0-9\]+.D." "optimized" } } */ + +_Bool subgele_le(int a05, int b05) +{ + _Bool x05 = a05 >= b05; + _Bool y05 = a05 <= b05; + return x05 - y05 <= 0; +} +/* { dg-final { scan-tree-dump "a05_\[0-9\]+.D. <= b05_\[0-9\]+.D.|b05_\[0-9\]+.D. >= a05_\[0-9\]+.D." "optimized" } } */ + +_Bool subgele_gt(int a06, int b06) +{ + _Bool x06 = a06 >= b06; + _Bool y06 = a06 <= b06; + return x06 - y06 > 0; +} +/* { dg-final { scan-tree-dump "a06_\[0-9\]+.D. > b06_\[0-9\]+.D.|b06_\[0-9\]+.D. < a06_\[0-9\]+.D." "optimized" } } */ + +_Bool subgele_ge(int a07, int b07) +{ + _Bool x07 = a07 >= b07; + _Bool y07 = a07 <= b07; + return x07 - y07 >= 0; +} +/* { dg-final { scan-tree-dump "a07_\[0-9\]+.D. >= b07_\[0-9\]+.D.|b07_\[0-9\]+.D. <= a07_\[0-9\]+.D." "optimized" } } */ + +_Bool subltgt_lt(int a08, int b08) +{ + _Bool x08 = a08 < b08; + _Bool y08 = a08 > b08; + return x08 - y08 < 0; +} +/* { dg-final { scan-tree-dump "a08_\[0-9\]+.D. > b08_\[0-9\]+.D.|b08_\[0-9\]+.D. < a08_\[0-9\]+.D." "optimized" } } */ + +_Bool subltgt_le(int a09, int b09) +{ + _Bool x09 = a09 < b09; + _Bool y09 = a09 > b09; + return x09 - y09 <= 0; +} +/* { dg-final { scan-tree-dump "a09_\[0-9\]+.D. >= b09_\[0-9\]+.D.|b09_\[0-9\]+.D. <= a09_\[0-9\]+.D." "optimized" } } */ + +_Bool subltgt_gt(int a10, int b10) +{ + _Bool x10 = a10 < b10; + _Bool y10 = a10 > b10; + return x10 - y10 > 0; +} +/* { dg-final { scan-tree-dump "a10_\[0-9\]+.D. < b10_\[0-9\]+.D.|b10_\[0-9\]+.D. > a10_\[0-9\]+.D." "optimized" } } */ + +_Bool subltgt_ge(int a11, int b11) +{ + _Bool x11 = a11 < b11; + _Bool y11 = a11 > b11; + return x11 - y11 >= 0; +} +/* { dg-final { scan-tree-dump "a11_\[0-9\]+.D. <= b11_\[0-9\]+.D.|b11_\[0-9\]+.D. >= a11_\[0-9\]+.D." "optimized" } } */ + +_Bool sublege_lt(int a12, int b12) +{ + _Bool x12 = a12 <= b12; + _Bool y12 = a12 >= b12; + return x12 - y12 < 0; +} +/* { dg-final { scan-tree-dump "a12_\[0-9\]+.D. > b12_\[0-9\]+.D.|b12_\[0-9\]+.D. < a12_\[0-9\]+.D." "optimized" } } */ + +_Bool sublege_le(int a13, int b13) +{ + _Bool x13 = a13 <= b13; + _Bool y13 = a13 >= b13; + return x13 - y13 <= 0; +} +/* { dg-final { scan-tree-dump "a13_\[0-9\]+.D. >= b13_\[0-9\]+.D.|b13_\[0-9\]+.D. <= a13_\[0-9\]+.D." "optimized" } } */ + +_Bool sublege_gt(int a14, int b14) +{ + _Bool x14 = a14 <= b14; + _Bool y14 = a14 >= b14; + return x14 - y14 > 0; +} +/* { dg-final { scan-tree-dump "a14_\[0-9\]+.D. < b14_\[0-9\]+.D.|b14_\[0-9\]+.D. > a14_\[0-9\]+.D." "optimized" } } */ + +_Bool sublege_ge(int a15, int b15) +{ + _Bool x15 = a15 <= b15; + _Bool y15 = a15 >= b15; + return x15 - y15 >= 0; +} +/* { dg-final { scan-tree-dump "a15_\[0-9\]+.D. <= b15_\[0-9\]+.D.|b15_\[0-9\]+.D. >= a15_\[0-9\]+.D." "optimized" } } */ +/* { dg-final { scan-tree-dump-not "_\[0-9\]+ - _\[0-9\]+" "optimized" } } */
