When there is obvious UB involved in the process of re-associating
a series of IV increments to build up a CHREC, fail.  This catches
a few degenerate cases where SCEV introduces UB with its inherent
re-associating of IV increments.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

        PR tree-optimization/121370
        * tree-scalar-evolution.cc (scev_dfs::add_to_evolution_1):
        Avoid UB integer overflow in accumulating CHREC_RIGHT.

        * gcc.dg/torture/pr121370.c: New testcase.
---
 gcc/testsuite/gcc.dg/torture/pr121370.c | 25 +++++++++++++++++++++++++
 gcc/tree-scalar-evolution.cc            | 11 +++++++++++
 2 files changed, 36 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr121370.c

diff --git a/gcc/testsuite/gcc.dg/torture/pr121370.c 
b/gcc/testsuite/gcc.dg/torture/pr121370.c
new file mode 100644
index 00000000000..d40f3b216ad
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr121370.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-require-effective-target int32plus } */
+
+int a;
+int main()
+{
+  int c = -2147483647;
+  int d = -2147483647;
+  int e = 2147483647;
+  if (0)
+  f:
+    e = d + e - 2;
+g:
+  if (d - c - e > 0) {
+    a = -c;
+    if (a + d) {
+      d = 1;
+      goto g;
+    }
+    return 0;
+  }
+  if (e)
+    goto f;
+  return 0;
+}
diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc
index 413ca49cb92..3b3748aba67 100644
--- a/gcc/tree-scalar-evolution.cc
+++ b/gcc/tree-scalar-evolution.cc
@@ -670,6 +670,17 @@ scev_dfs::add_to_evolution_1 (tree chrec_before, tree 
to_add, gimple *at_stmt)
          to_add = chrec_convert (type, to_add, at_stmt);
          right = chrec_convert_rhs (type, right, at_stmt);
          right = chrec_fold_plus (chrec_type (right), right, to_add);
+         /* When we have an evolution in a non-wrapping type and
+            in the process of accumulating CHREC_RIGHT there was
+            overflow this indicates in the association that happened
+            in building the CHREC clearly involved UB.  Avoid this.
+            In building a CHREC we basically turn (a + INCR1) + INCR2
+            into a + (INCR1 + INCR2) which is not always valid.
+            Note this check only catches few invalid cases.  */
+         if ((INTEGRAL_TYPE_P (type) && ! TYPE_OVERFLOW_WRAPS (type))
+             && TREE_CODE (right) == INTEGER_CST
+             && TREE_OVERFLOW (right))
+           return chrec_dont_know;
          return build_polynomial_chrec (var, left, right);
        }
       else
-- 
2.43.0

Reply via email to