Currently exact division is treated the same as trucate division but
we can do better. For an example `[1, +INF] ex/ 4` is computed to
`[0, +INF/4]`. This is ok range but we can do better. Since `1 ex/ 4` is
undefined, we can treat it as never happening. By checking the mod and
incrementing (or decrementing) by 1 the result if the mod is non zero.
This means we are doing round away from 0.
The main reason why this is helpful with C++ code we have checks like:
```
if (a == b) __builtin_unreachable ();
ptrdiff t = a - b;
```
So we want the range of t not include 0.
Bootstrapped and tested on x86_64-linux-gnu.
PR tree-optimization/125863
gcc/ChangeLog:
* range-op.cc (operator_div::wi_op_overflows): Improve
handling of exact division.
gcc/testsuite/ChangeLog:
* g++.dg/opt/pr125863-1.C: New test.
* gcc.dg/tree-ssa/vrp-exact-div-1.c: New test.
Signed-off-by: Andrew Pinski <[email protected]>
---
gcc/range-op.cc | 17 +++++++++++++++-
gcc/testsuite/g++.dg/opt/pr125863-1.C | 15 ++++++++++++++
.../gcc.dg/tree-ssa/vrp-exact-div-1.c | 20 +++++++++++++++++++
3 files changed, 51 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/opt/pr125863-1.C
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-exact-div-1.c
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 94edfdc9870..5b60e4cce0c 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2546,10 +2546,25 @@ operator_div::wi_op_overflows (wide_int &res, tree type,
switch (m_code)
{
- case EXACT_DIV_EXPR:
case TRUNC_DIV_EXPR:
res = wi::div_trunc (w0, w1, sign, &overflow);
break;
+ case EXACT_DIV_EXPR:
+ {
+ wide_int mod = wi::mod_trunc (w0, w1, sign);
+ res = wi::div_trunc (w0, w1, sign, &overflow);
+ // For exact divide if we have some say `1 ex/ 4`, it is undefined
+ // behavior so we to not include 0 here so increment the result by 1,
+ // but only if not w0 is not the max
+ if (wi::gt_p (mod, 0, sign)
+ && w0 != wi::max_value (w1.get_precision (), sign))
+ res = wi::add (res, 1);
+ // Likewise for `-1 ex/ 4` needs not to include 0.
+ if (wi::lt_p (mod, 0, sign)
+ && w0 != wi::min_value (w1.get_precision (), sign))
+ res = wi::sub (res, 1);
+ break;
+ }
case FLOOR_DIV_EXPR:
res = wi::div_floor (w0, w1, sign, &overflow);
break;
diff --git a/gcc/testsuite/g++.dg/opt/pr125863-1.C
b/gcc/testsuite/g++.dg/opt/pr125863-1.C
new file mode 100644
index 00000000000..50210c97d63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr125863-1.C
@@ -0,0 +1,15 @@
+// PR tree-optimization/125863
+// { dg-do compile }
+// { dg-options "-O3 -Warray-bounds" }
+// { dg-skip-if "requires hosted libstdc++ for vector" { ! hostedlib } }
+
+// There should be no Warray-bounds warnings here.
+
+#include <vector>
+
+void foo(std::vector<int> &vec)
+{
+ if (vec.empty())
+ __builtin_unreachable();
+ vec.resize(1);
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-exact-div-1.c
b/gcc/testsuite/gcc.dg/tree-ssa/vrp-exact-div-1.c
new file mode 100644
index 00000000000..59089a6c18e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-exact-div-1.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-forwprop -fdump-tree-evrp" } */
+/* PR tree-optimization/125863 */
+
+long f(int *a, int *b)
+{
+ if (a == b) return 0;
+ long t = a - b;
+ if (t == 0) __builtin_trap();
+ return t;
+}
+
+/* VPR/ranger should be able to figure out the range of t does not include 0.
+ That is:
+ _1 = a_3(D) - b_4(D);
+ t_5 = _1 /[ex] 4;
+ where the range of _1 excludes 0 because of the `a==b` check.
+ Note forwprop is disabled because it would convert `t_5 == 0` into `a == b`.
*/
+/* { dg-final { scan-tree-dump-not "__builtin_trap " "evrp" } } */
+/* { dg-final { scan-tree-dump "Folding predicate t_. == 0 to 0" "evrp" } } */
--
2.43.0