So this is an implementation of an idea I had a few years back and prototyped last spring to fix pr92539.

pr92539 is a false positive Warray-bounds warning triggered by loop unrolling. The warning is in code that will never execute, but none of the optimizers clean things up well enough or early enough in the pipeline to avoid the warning.

To optimize away the code we can take advantage of the fact that we're comparing a value to a bogus pointer. So for example an EQ comparison against &"aa" + 3 is always false and a NE comparison against that would always be true.

I've implemented this in vr-values. It's not my preferred location, but we need to handle this scenario before the array-bounds warnings which are currently placed immediately after vrp1. So vr-values it was...

This could perhaps also be done in match.pd; there's a reasonable chance it's implementable there and would trigger early enough in the pipeline to avoid the false positive. I can certainly explore that if folks think that's a better solution to this long standing issue.

Bootstrapped and regression tested on x86_64 and run through the crosses in my tester.

Anyway, thoughts?

Jeff

        PR tree-optimization/92539

gcc/
        * vr-values.cc (simplify_using_ranges::fold_cond_with_ops): Optimize
        away EQ/NE test against a bogus pointer.


gcc/testsuite/
        g++.dg/torture/pr92539.C: New test.



diff --git a/gcc/testsuite/g++.dg/torture/pr92539.C 
b/gcc/testsuite/g++.dg/torture/pr92539.C
new file mode 100644
index 00000000000..36af174620b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr92539.C
@@ -0,0 +1,51 @@
+// { dg-do compile }
+// { dg-additional-options "-Wall" }
+
+static bool
+ischar(int ch)
+{
+    return (0 == (ch & ~0xff) || ~0 == (ch | 0xff)) != 0;
+}
+
+static bool eat(char const*& first, char const* last)
+{
+    if (first != last && ischar(*first)) {
+        ++first;
+        return true;
+    }
+    return false;
+}
+
+static bool eat_two(char const*& first, char const* last)
+{
+    auto save = first;
+    if (eat(first, last) && eat(first, last))
+        return true;
+    first = save;
+    return false;
+}
+
+static bool foo(char const*& first, char const* last)
+{
+    auto local_iterator = first;
+    int i = 0;
+    for (; i < 3; ++i)
+        if (!eat_two(local_iterator, last))
+            return false;
+    first = local_iterator;
+    return true;
+}
+
+static bool test(char const* in, bool full_match = true)
+{
+    auto last = in;
+    while (*last)
+        ++last;
+    return foo(in, last) && (!full_match || (in == last));
+}
+
+int main()
+{
+    return test("aa");
+}
+
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index cf273a3fc62..f03c44505d5 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -325,6 +325,35 @@ simplify_using_ranges::fold_cond_with_ops (enum tree_code 
code,
       if (res == range_false ())
        return boolean_false_node;
     }
+
+  /* If we're comparing pointers and one of the pointers is
+     not a valid pointer (say &MEM <const char> [(void *)"aa" + 4B)
+     return true for EQ and false for NE.  */
+  tree type = TREE_TYPE (op0);
+  if ((code == EQ_EXPR || code == NE_EXPR)
+      && POINTER_TYPE_P (type)
+      && TREE_CODE (op1) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (op1, 0)) == MEM_REF)
+    {
+      tree mem_ref = TREE_OPERAND (op1, 0);
+      if (TREE_CODE (TREE_OPERAND (mem_ref, 0)) == ADDR_EXPR)
+       {
+         tree addr_expr = TREE_OPERAND (mem_ref, 0);
+         if (TREE_CODE (TREE_OPERAND (addr_expr, 0)) == STRING_CST)
+           {
+             tree string = TREE_OPERAND (addr_expr, 0);
+
+             if (TREE_CODE (TREE_OPERAND (mem_ref, 1)) == INTEGER_CST)
+               {
+                 HOST_WIDE_INT len = TREE_STRING_LENGTH (string);
+                 HOST_WIDE_INT offset = tree_to_uhwi (TREE_OPERAND (mem_ref, 
1));
+                 if (offset > len)
+                   return code == EQ_EXPR ? boolean_false_node : 
boolean_true_node;
+               }
+           }
+       }
+    }
+
   return NULL;
 }
 

Reply via email to