https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127103

--- Comment #3 from Drea Pinski <pinskia at gcc dot gnu.org> ---
The two patterns which are needed here are:
```
/* x + uMax(x, 1) -> uMax(x+x, 1)
   if x+x is known not to wrap/overflow.  */
(simplify
 (plus:c @0 (max:s@2 @0 integer_onep@1))
 (if (TYPE_UNSIGNED (type))
  (with { int_range_max vr0; }
   (if (gimple_match_range_of_expr (vr0, @0, @2)
        && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr0))
    (max (plus @0 @0) @1)))))

/* minmax (a, b) + c -> minmax (a + c, b + c)
   if a+c or b+c simplifies and a+c/b+c don't overlfow */
(for minmax (min max)
 (simplify
  (plus:c @0 (minmax:cs@3 @1 @2))
  (with { int_range_max vr0, vr1, vr2; }
   (if (gimple_match_range_of_expr (vr0, @0)
        && gimple_match_range_of_expr (vr1, @1, @3)
        && gimple_match_range_of_expr (vr2, @2, @3)
        && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr1)
        && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr2))
    (minmax (plus @0 @1) (plus! @0 @2))))))
```

The first one is like the LLVM patch linked.

The second one is to transform:
  __room_33 = 2147483647 - _32;
...
_35 = MIN_EXPR <__room_33, _34>;
  # RANGE [irange] long unsigned int [1, 4294967292]
  _36 = _32 + _35;

Into:
_t = _34 + _32 ;
_36 = MIN<2147483647, _t>

Note the ! is needed there as there is an opposite pattern too:
/* minmax (a + c, b + c) -> minmax (a, b) + c */
(for minmax (min max)
 (simplify
  (minmax:c (plus:cs @0 @2) (plus:s @1 @2))
   (if (INTEGRAL_TYPE_P (type)
        && TYPE_OVERFLOW_UNDEFINED (type)
        && !TYPE_OVERFLOW_SANITIZED (type))
    (plus (minmax @0 @1) @2))))

Which currently is only supported for signed (though could be expanded for
unsigned using overflow_free_p).

With the second pattern, we get the same IR as LLVM which is what allows for
the first pattern.

Reply via email to