The following fixes a jump-threading bug when threading through a backedge
(thus it's only applicable to GCC 5).  The issue is that when we see
a backedge walking the SSA value chain might end up picking up values
from a previous iteration.

The fix is to add backedge_seen to yet another function and avoid
walking the SSA value chain in that case.

Bootstrapped and tested on x86_64-unknown-linux-gnu - ok for the branch?

(I was sitting on this patch for some months because I only had a
proprietary testcase)

Thanks,
Richard.

2016-12-09  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/78731
        * tree-ssa-threadedge.c (simplify_control_stmt_condition):
        If we've seen a backedge to not walk the SSA value chain.
        (thread_around_empty_blocks): Pass down whether we've seen
        a backedge to simplify_control_stmt_condition.
        (thread_through_normal_block): Likewise.

        * gcc.dg/torture/pr78731.c: New testcase.

Index: gcc/tree-ssa-threadedge.c
===================================================================
--- gcc/tree-ssa-threadedge.c   (revision 237797)
+++ gcc/tree-ssa-threadedge.c   (working copy)
@@ -574,7 +574,8 @@ simplify_control_stmt_condition (edge e,
                                 gimple stmt,
                                 gcond *dummy_cond,
                                 tree (*simplify) (gimple, gimple),
-                                bool handle_dominating_asserts)
+                                bool handle_dominating_asserts,
+                                bool backedge_seen)
 {
   tree cond, cached_lhs;
   enum gimple_code code = gimple_code (stmt);
@@ -593,7 +594,7 @@ simplify_control_stmt_condition (edge e,
       /* Get the current value of both operands.  */
       if (TREE_CODE (op0) == SSA_NAME)
        {
-         for (int i = 0; i < 2; i++)
+         for (int i = 0; i < (backedge_seen ? 1 : 2); i++)
            {
              if (TREE_CODE (op0) == SSA_NAME
                  && SSA_NAME_VALUE (op0))
@@ -605,7 +606,7 @@ simplify_control_stmt_condition (edge e,
 
       if (TREE_CODE (op1) == SSA_NAME)
        {
-         for (int i = 0; i < 2; i++)
+         for (int i = 0; i < (backedge_seen ? 1 : 2); i++)
            {
              if (TREE_CODE (op1) == SSA_NAME
                  && SSA_NAME_VALUE (op1))
@@ -689,7 +690,7 @@ simplify_control_stmt_condition (edge e,
         a loop invariant SSA_NAME used in the condition.  */
       if (cached_lhs)
        {
-         for (int i = 0; i < 2; i++)
+         for (int i = 0; i < (backedge_seen ? 1 : 2); i++)
            {
              if (TREE_CODE (cached_lhs) == SSA_NAME
                  && SSA_NAME_VALUE (cached_lhs))
@@ -940,7 +941,8 @@ thread_around_empty_blocks (edge taken_e
 
   /* Extract and simplify the condition.  */
   cond = simplify_control_stmt_condition (taken_edge, stmt, dummy_cond,
-                                         simplify, handle_dominating_asserts);
+                                         simplify, handle_dominating_asserts,
+                                         *backedge_seen_p);
 
   /* If the condition can be statically computed and we have not already
      visited the destination edge, then add the taken edge to our thread
@@ -1326,7 +1328,8 @@ thread_through_normal_block (edge e,
 
       /* Extract and simplify the condition.  */
       cond = simplify_control_stmt_condition (e, stmt, dummy_cond, simplify,
-                                             handle_dominating_asserts);
+                                             handle_dominating_asserts,
+                                             *backedge_seen_p);
 
       if (!cond)
        return 0;
Index: gcc/testsuite/gcc.dg/torture/pr78731.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr78731.c      (revision 0)
+++ gcc/testsuite/gcc.dg/torture/pr78731.c      (working copy)
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define GENERAL 1
+#define BRACKETS 2
+#define QUOTES 3
+
+void __attribute__((noinline,noclone))
+foo(char *qb, char* into)
+{
+  int state = QUOTES;
+  int save_state = BRACKETS;
+
+  while (qb)
+    {
+      switch (state)
+       {
+       case BRACKETS:
+         exit(0);
+       case GENERAL:
+         abort ();
+       case QUOTES:
+         state = save_state;
+         save_state = GENERAL;
+         break;
+       default: ;
+       }
+      printf("State %d btw GENERAL %d\n", state, GENERAL);
+    }
+  abort ();
+}
+
+int main()
+{
+  char *b = "123";
+  char out[4];
+  foo(b, out);
+  return 0;
+}

Reply via email to