On Mon, Aug 10, 2026 at 9:14 AM Tudor-Stefan Magirescu <[email protected]> wrote: > > 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.
Pushed: https://gcc.gnu.org/pipermail/gcc-cvs/2026-August/459699.html . Thanks again for the patch and hope to see more in the future. > > 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]> > --- > Thanks for the review! I agree with the suggestions and implemented them as > described below. > > Changes in v2: > - Combined the four simplification rules into a single one using loops and > the `:c` flag. > - Removed the `single_use` guard from the simplification rule. > > gcc/match.pd | 15 ++ > .../gcc.c-torture/execute/subcmp-1.c | 55 ++++++++ > gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c | 131 ++++++++++++++++++ > 3 files changed, 201 insertions(+) > create mode 100644 gcc/testsuite/gcc.c-torture/execute/subcmp-1.c > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index cf03333fdc6..7f7d5ae713e 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -7314,6 +7314,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 00000000000..4682246c355 > --- /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 00000000000..489cf4c1f40 > --- /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" } } */ > -- > 2.43.0 >
