> 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


Attachment: 0001-match.pd-drop-a-clamp-whose-bounds-cross.patch
Description: 0001-match.pd-drop-a-clamp-whose-bounds-cross.patch

Reply via email to