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; +}