> On 6 Aug 2026, at 06:33, Jeffrey Law <[email protected]> wrote: > > > > On 8/4/2026 3:54 AM, [email protected] wrote: >> From: Kyrylo Tkachov <[email protected]> >> >> MIN (MAX (X, Y + CST), Y) is Y for a positive CST: the inner select is at >> least Y + CST, which is strictly above Y where the type cannot wrap, so the >> outer select always takes Y. The dual holds for MAX over MIN with a >> negative offset. Both leave the whole nest dead. >> >> int f (int x, int y) >> { >> int a = x > y + 7 ? x : y + 7; >> return a < y ? a : y; >> } >> >> aarch64 -O2 before: >> >> add w2, w1, 7 >> cmp w2, w0 >> csel w0, w2, w0, ge >> cmp w0, w1 >> csel w0, w0, w1, le >> >> after: >> >> mov w0, w1 >> >> The shape arises after inlining, when a clamp helper is instantiated with a >> lower bound that the caller has already pushed above the upper one. The >> existing min/max-with-offset rules only cover the case where the two selects >> name the same operand, so the nest survived. >> >> Bootstrapped and tested on aarch64-none-linux-gnu. >> Ok for trunk? >> Thanks, >> Kyrill >> >> gcc/ChangeLog: >> >> * match.pd (MIN (MAX (X, Y + CST), Y)): New simplification. >> (MAX (MIN (X, Y + CST), Y)): Likewise. >> >> gcc/testsuite/ChangeLog: >> >> * gcc.dg/tree-ssa/minmax-offset-absorb-1.c: New test. > Generally OK. Just one testcase question. > >> + >> +/* Must not fold: the offset has the wrong sign for the outer select. */ >> +int keep2 (int x, int y) >> +{ >> + int a = x > y - 7 ? x : y - 7; >> + return a < y ? a : y; >> +} > So very happy to see both positive and negative tests. This one probably > isn't testing what you think since it appears the MAX_EXPR is never > discovered. We discover the MIN_EXPR, but the MAX is still in if-then form. > So not really sure the scans are testing this in the way you want. Not sure > if you want to adjust that or not. For reference the IL looks like this: > > _1 = y_3(D) + -6; > if (_1 > x_4(D)) > goto <bb 4>; [50.00%] > else > goto <bb 3>; [50.00%] > ;; succ: 4 [50.0% (guessed)] count:536870912 (estimated locally, > freq 0.5000) (TRUE_VALUE,EXECUTABLE) > ;; 3 [50.0% (guessed)] count:536870912 (estimated locally, > freq 0.5000) (FALSE_VALUE,EXECUTABLE) > > ;; basic block 3, loop depth 0, count 536870912 (estimated locally, freq > 0.5000), maybe hot > ;; prev block 2, next block 4, flags: (NEW, REACHABLE, VISITED) > ;; pred: 2 [50.0% (guessed)] count:536870912 (estimated locally, > freq 0.5000) (FALSE_VALUE,EXECUTABLE) > _8 = MIN_EXPR <y_3(D), x_4(D)>; > goto <bb 5>; [100.00%] > ;; succ: 5 [always] count:536870912 (estimated locally, freq > 0.5000) (FALLTHRU,EXECUTABLE) > > ;; basic block 4, loop depth 0, count 536870912 (estimated locally, freq > 0.5000), maybe hot > ;; prev block 3, next block 5, flags: (NEW, REACHABLE, VISITED) > ;; pred: 2 [50.0% (guessed)] count:536870912 (estimated locally, > freq 0.5000) (TRUE_VALUE,EXECUTABLE) > a_5 = y_3(D) + -7; > ;; succ: 5 [always] count:536870912 (estimated locally, freq > 0.5000) (FALLTHRU,EXECUTABLE) > > ;; basic block 5, loop depth 0, count 1073741824 (estimated locally, freq > 1.0000), maybe hot > ;; prev block 4, next block 1, flags: (NEW, REACHABLE, VISITED) > ;; pred: 4 [always] count:536870912 (estimated locally, freq > 0.5000) (FALLTHRU,EXECUTABLE) > ;; 3 [always] count:536870912 (estimated locally, freq > 0.5000) (FALLTHRU,EXECUTABLE) > # prephitmp_9 = PHI <a_5(4), _8(3)> > return prephitmp_9; > >
Thanks for catching this. Here’s an updated set of tests with the patch. Kyrill > > Jeff
0001-match.pd-drop-a-clamp-whose-bounds-cross.patch
Description: 0001-match.pd-drop-a-clamp-whose-bounds-cross.patch
