This adds a pattern to optimize `minmax (a, b) + c` into `minmax (a + c, b +
c)` when
`a + c` and `b + c` are known not to overflow and either `a + c` or `b + c`
simplifies.
This shows up in std::vector::push_back :
```
# RANGE [irange] const size_type [0, 2147483647] MASK 0x7fffffff VALUE 0x0
__room_33 = 2147483647 - _32;
...
# RANGE [irange] long unsigned int [1, 2147483646] MASK 0x7fffffff VALUE 0x0
_35 = MIN_EXPR <__room_33, _34>;
# RANGE [irange] long unsigned int [1, 4294967292]
_36 = _32 + _35;
```
_32 has a range of `[0, 2147483647]`, _34 has a range of `[1, 2147483646]`.
This is transformed into:
_t = _32 + _34;
_36 = MIN_EXPR<_t, 2147483647>
This then allows to remove a condition that was never could be executed too.
This is currently limited to unsigned types as overflow_free_p does not tell
me if we are going to introduce new undefined overflow; it will return true for
all TYPE_OVERFLOW_UNDEFINED types. I filed PR 127356 to add a modified version
of overflow_free_p. But since the types in push_back is unsigned this is enough
for now.
Bootstrapped and tested on x86_64-linux-gnu.
PR tree-optimization/127103
gcc/ChangeLog:
* match.pd (`minmax (a, b) + c`): New pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/minmax-plus-1.c: New test.
Signed-off-by: Andrea Pinski <[email protected]>
---
gcc/match.pd | 15 +++++++
gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c | 39 +++++++++++++++++++
2 files changed, 54 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c
diff --git a/gcc/match.pd b/gcc/match.pd
index d6ece84e186..81734b73a7d 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -532,6 +532,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(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 (TYPE_UNSIGNED (type)
+ && 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))))))
+
#endif
/* X * 1, X / 1 -> X. */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c
b/gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c
new file mode 100644
index 00000000000..75067fdb962
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+/* minmax (a, b) + c -> minmax (a + c, b + c) */
+/* PR tree-optimization/127103 */
+
+__attribute__((always_inline))
+static inline unsigned
+min(unsigned a, unsigned b)
+{
+ if (a > b)
+ return b;
+ return a;
+}
+__attribute__((always_inline))
+static inline unsigned
+max(unsigned a, unsigned b)
+{
+ if (a < b)
+ return b;
+ return a;
+}
+
+unsigned f(unsigned a, unsigned t1)
+{
+ if (a > __INT_MAX__)
+ return 0;
+ unsigned t = __INT_MAX__ - a;
+ return a + min(t, a);
+}
+
+unsigned f1(unsigned a, unsigned t1)
+{
+ if (a > __INT_MAX__)
+ return 0;
+ unsigned t = __INT_MAX__ - a;
+ return a + max(t, a);
+}
+
+/* { dg-final { scan-tree-dump-times "gimple_assign <mult_expr, _\[0-9\],
a_\[0-9\].D., 2" 2 "optimized" } } */
--
2.43.0