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

Reply via email to