From a3ebc13492ff238873f2c6a7a3e51abefec1d052 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 26 Nov 2020 16:24:07 +0100 Subject: [PATCH] match.pd: Use ranges to optimize some x * y / y to x [PR97997] For signed integers with undefined overflow we already optimize x * y / y into x, but for signed integers with -fwrapv or unsigned integers we don't. The following patch allows optimizing that into just x if value ranges prove that x * y will never overflow. It uses the global SSA_NAME_RANGE_INFO only, because like mentioned in another PR we don't currently have a way to tell the ranger from match.pd the use stmt (and we'd need in that case to tell ranger to only follow SSA_NAME_DEF_STMTs + SSA_NAME_RANGE_INFO and never go in the other direction, as following immediate uses seems forbidden in match.pd). Another possibility would be to optimize this during vrp, but on the other side the optimization itself is match.pd-ish. 2020-11-26 Jakub Jelinek PR tree-optimization/97997 * match.pd ((t * 2) / 2) -> t): Optimize even for defined overflow if ranges prove there is no overflow. * gcc.dg/tree-ssa/pr97997-1.c: New test. * gcc.dg/tree-ssa/pr97997-2.c: New test. --- gcc/match.pd | 45 ++++++++++++++++++-- gcc/testsuite/gcc.dg/tree-ssa/pr97997-1.c | 52 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr97997-2.c | 41 ++++++++++++++++++ 3 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr97997-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr97997-2.c diff --git a/gcc/match.pd b/gcc/match.pd index f8b65154a9e..b6dfc24af88 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -650,9 +650,48 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (for div (trunc_div ceil_div floor_div round_div exact_div) (simplify (div (mult:c @0 @1) @1) - (if (ANY_INTEGRAL_TYPE_P (type) - && TYPE_OVERFLOW_UNDEFINED (type)) - @0))) + (if (ANY_INTEGRAL_TYPE_P (type)) + (if (TYPE_OVERFLOW_UNDEFINED (type)) + @0 +#if GIMPLE + (if (TREE_CODE (@0) == SSA_NAME + && (TREE_CODE (@1) == SSA_NAME || TREE_CODE (@1) == INTEGER_CST)) + (with + { + bool overflowed = true; + wide_int wmin0, wmax0; + if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE) + { + /* If the multiplication can't overflow/wrap around, then + it can be optimized too. */ + wide_int wmin1, wmax1; + wi::overflow_type min_ovf, max_ovf; + if (TREE_CODE (@1) == INTEGER_CST) + { + wmin1 = wi::to_wide (@1); + wi::mul (wmin0, wmin1, TYPE_SIGN (type), &min_ovf); + wi::mul (wmax0, wmin1, TYPE_SIGN (type), &max_ovf); + if (min_ovf == wi::OVF_NONE && max_ovf == wi::OVF_NONE) + overflowed = false; + } + else if (get_range_info (@1, &wmin1, &wmax1) == VR_RANGE) + { + wi::mul (wmin0, wmin1, TYPE_SIGN (type), &min_ovf); + wi::mul (wmax0, wmax1, TYPE_SIGN (type), &max_ovf); + if (min_ovf == wi::OVF_NONE && max_ovf == wi::OVF_NONE) + { + wi::mul (wmin0, wmax1, TYPE_SIGN (type), &min_ovf); + wi::mul (wmax0, wmin1, TYPE_SIGN (type), &max_ovf); + if (min_ovf == wi::OVF_NONE && max_ovf == wi::OVF_NONE) + overflowed = false; + } + } + } + } + (if (!overflowed) + @0))) +#endif + )))) (for op (negate abs) /* Simplify cos(-x) and cos(|x|) -> cos(x). Similarly for cosh. */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr97997-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr97997-1.c new file mode 100644 index 00000000000..3c4b468b88b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr97997-1.c @@ -0,0 +1,52 @@ +/* PR tree-optimization/97997 */ +/* { dg-do compile { target { ilp32 || lp64 } } } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times "return x_\[0-9]*\\\(D\\\);" 6 "optimized" } } */ +/* { dg-final { scan-tree-dump-not " / " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " \\* " "optimized" } } */ + +unsigned short +f1 (unsigned short x) +{ + return x * 10 / 10; +} + +unsigned short +f2 (unsigned short x) +{ + int a = x; + int b = 10; + int c = 10; + return a * b / c; +} + +unsigned short +f3 (unsigned short x) +{ + return x * 10U / 10; +} + +unsigned short +f4 (unsigned short x) +{ + unsigned a = x; + unsigned b = 10; + unsigned c = 10; + return a * b / c; +} + +unsigned short +f5 (unsigned short x, unsigned short y) +{ + return (unsigned) x * y / y; +} + +unsigned int +f6 (unsigned int x, unsigned int y) +{ + if (x >= 30000) + __builtin_unreachable (); + if (y >= ~0U / 30000) + __builtin_unreachable (); + return x * y / y; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr97997-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr97997-2.c new file mode 100644 index 00000000000..a9d5075f3ab --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr97997-2.c @@ -0,0 +1,41 @@ +/* PR tree-optimization/97997 */ +/* { dg-do compile { target { ilp32 || lp64 } } } */ +/* { dg-options "-O2 -fdump-tree-optimized -fwrapv" } */ +/* { dg-final { scan-tree-dump-times "return x_\[0-9]*\\\(D\\\);" 4 "optimized" } } */ +/* { dg-final { scan-tree-dump-not " / " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " \\* " "optimized" } } */ + +unsigned short +f1 (unsigned short x) +{ + return x * 10 / 10; +} + +unsigned short +f2 (unsigned short x) +{ + int a = x; + int b = 10; + int c = 10; + return a * b / c; +} + +short +f3 (short x, short y) +{ + return x * y / y; +} + +int +f4 (int x, int y) +{ + if (x >= 30000) + __builtin_unreachable (); + if (x <= -30000) + __builtin_unreachable (); + if (y >= __INT_MAX__ / 30000) + __builtin_unreachable (); + if (y <= -__INT_MAX__ / 30000) + __builtin_unreachable (); + return x * y / y; +} -- 2.30.2