]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
backport: re PR tree-optimization/47286 (Invalid code when using register ... asm)
authorRichard Guenther <rguenther@suse.de>
Mon, 17 Jan 2011 11:31:10 +0000 (11:31 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 17 Jan 2011 11:31:10 +0000 (11:31 +0000)
2011-01-17  Richard Guenther  <rguenther@suse.de>

        Backport from mainline
PR tree-optimization/47286
* tree-ssa-structalias.c (new_var_info): Register variables
are global.

* gcc.dg/tree-ssa/pr47286.c: New testcase.

        PR tree-optimization/44592
* tree-ssa-ccp.c (gimplify_and_update_call_from_tree): Copy
from trunk.

* gfortran.dg/pr44592.f90: New testcase.

From-SVN: r168894

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr47286.c [new file with mode: 0644]
gcc/testsuite/gfortran.dg/pr44592.f90 [new file with mode: 0644]
gcc/tree-ssa-ccp.c
gcc/tree-ssa-structalias.c

index 86e15db5cd91000f7271756502f3ab586aebabfc..3d4c6eb7b99b8c1a841f659ff13044203e7130f4 100644 (file)
@@ -1,3 +1,14 @@
+2011-01-17  Richard Guenther  <rguenther@suse.de>
+
+       Backport from mainline
+       PR tree-optimization/47286
+       * tree-ssa-structalias.c (new_var_info): Register variables
+       are global.
+
+       PR tree-optimization/44592
+       * tree-ssa-ccp.c (gimplify_and_update_call_from_tree): Copy
+       from trunk.
+
 2011-01-16  Jakub Jelinek  <jakub@redhat.com>
 
        Backport from mainline
index 3e9e0a06b81fea107e65737b1b299218d33ca7fa..ad808a8735a6857e42b41b94d6c966c1ee39f555 100644 (file)
@@ -1,3 +1,12 @@
+2011-01-17  Richard Guenther  <rguenther@suse.de>
+
+       Backport from mainline
+       PR tree-optimization/47286
+       * gcc.dg/tree-ssa/pr47286.c: New testcase.
+
+       PR tree-optimization/44592
+       * gfortran.dg/pr44592.f90: New testcase.
+
 2011-01-16  Jakub Jelinek  <jakub@redhat.com>
 
        Backport from mainline
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr47286.c b/gcc/testsuite/gcc.dg/tree-ssa/pr47286.c
new file mode 100644 (file)
index 0000000..b03c59b
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! { i?86-*-* x86_64-*-* } } { "*" } { "" } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+struct thread_info { int preempt_count; };
+static inline struct thread_info *current_thread_info(void)
+{
+  register struct thread_info *sp asm("esp");
+  return sp;
+}
+void testcase(void)
+{
+  current_thread_info()->preempt_count += 1;
+}
+
+/* We have to make sure that alias analysis treats sp as pointing
+   to globals and thus the store not optimized away.  */
+
+/* { dg-final { scan-tree-dump "->preempt_count =" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gfortran.dg/pr44592.f90 b/gcc/testsuite/gfortran.dg/pr44592.f90
new file mode 100644 (file)
index 0000000..8b043ba
--- /dev/null
@@ -0,0 +1,20 @@
+! { dg-do run }
+! { dg-options "-O3" }
+! From forall_12.f90
+! Fails with loop reversal at -O3
+!
+  character(len=1) :: b(4) = (/"1","2","3","4"/), c(4)
+  c = b
+  i = 1
+  ! This statement must be here for the abort below
+  b(1:3)(i:i) = b(2:4)(i:i)
+
+  b = c
+  b(4:2:-1)(i:i) = b(3:1:-1)(i:i)
+
+  ! This fails.  If the condition is printed, the result is F F F F
+  if (any (b .ne. (/"1","1","2","3"/))) i = 2
+  print *, b
+  print *, b .ne. (/"1","1","2","3"/)
+  if (i == 2) call abort
+end
index 2056da82d8e4e40a6e28a29336e2cfcb4c09bb79..b570548d55aab628abfa1d6bd872a76db72f8670 100644 (file)
@@ -3355,7 +3355,9 @@ optimize_stdarg_builtin (gimple call)
    is replaced.  If the call is expected to produces a result, then it
    is replaced by an assignment of the new RHS to the result variable.
    If the result is to be ignored, then the call is replaced by a
-   GIMPLE_NOP.  */
+   GIMPLE_NOP.  A proper VDEF chain is retained by making the first
+   VUSE and the last VDEF of the whole sequence be the same as the replaced
+   statement and using new SSA names for stores in between.  */
 
 static void
 gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
@@ -3366,17 +3368,36 @@ gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
   gimple_stmt_iterator i;
   gimple_seq stmts = gimple_seq_alloc();
   struct gimplify_ctx gctx;
+  gimple last = NULL;
+  gimple laststore = NULL;
+  tree reaching_vuse;
 
   stmt = gsi_stmt (*si_p);
 
   gcc_assert (is_gimple_call (stmt));
 
   lhs = gimple_call_lhs (stmt);
+  reaching_vuse = gimple_vuse (stmt);
 
   push_gimplify_context (&gctx);
 
   if (lhs == NULL_TREE)
-    gimplify_and_add (expr, &stmts);
+    {
+      gimplify_and_add (expr, &stmts);
+      /* We can end up with folding a memcpy of an empty class assignment
+        which gets optimized away by C++ gimplification.  */
+      if (gimple_seq_empty_p (stmts))
+       {
+         pop_gimplify_context (NULL);
+         if (gimple_in_ssa_p (cfun))
+           {
+             unlink_stmt_vdef (stmt);
+             release_defs (stmt);
+           }
+         gsi_remove (si_p, true);
+         return;
+       }
+    }
   else
     tmp = get_initialized_tmp_var (expr, &stmts, NULL);
 
@@ -3387,26 +3408,95 @@ gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
 
   /* The replacement can expose previously unreferenced variables.  */
   for (i = gsi_start (stmts); !gsi_end_p (i); gsi_next (&i))
-  {
-    new_stmt = gsi_stmt (i);
-    find_new_referenced_vars (new_stmt);
-    gsi_insert_before (si_p, new_stmt, GSI_NEW_STMT);
-    mark_symbols_for_renaming (new_stmt);
-    gsi_next (si_p);
-  }
+    {
+      if (last)
+       {
+         gsi_insert_before (si_p, last, GSI_NEW_STMT);
+         gsi_next (si_p);
+       }
+      new_stmt = gsi_stmt (i);
+      if (gimple_in_ssa_p (cfun))
+       {
+         find_new_referenced_vars (new_stmt);
+         mark_symbols_for_renaming (new_stmt);
+       }
+      /* If the new statement has a VUSE, update it with exact SSA name we
+         know will reach this one.  */
+      if (gimple_vuse (new_stmt))
+       {
+         /* If we've also seen a previous store create a new VDEF for
+            the latter one, and make that the new reaching VUSE.  */
+         if (laststore)
+           {
+             reaching_vuse = make_ssa_name (gimple_vop (cfun), laststore);
+             gimple_set_vdef (laststore, reaching_vuse);
+             update_stmt (laststore);
+             laststore = NULL;
+           }
+         gimple_set_vuse (new_stmt, reaching_vuse);
+         gimple_set_modified (new_stmt, true);
+       }
+      if (gimple_assign_single_p (new_stmt)
+         && !is_gimple_reg (gimple_assign_lhs (new_stmt)))
+       {
+         laststore = new_stmt;
+       }
+      last = new_stmt;
+    }
 
   if (lhs == NULL_TREE)
     {
-      new_stmt = gimple_build_nop ();
-      unlink_stmt_vdef (stmt);
-      release_defs (stmt);
+      /* If we replace a call without LHS that has a VDEF and our new
+         sequence ends with a store we must make that store have the same
+        vdef in order not to break the sequencing.  This can happen
+        for instance when folding memcpy calls into assignments.  */
+      if (gimple_vdef (stmt) && laststore)
+       {
+         gimple_set_vdef (laststore, gimple_vdef (stmt));
+         if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME)
+           SSA_NAME_DEF_STMT (gimple_vdef (stmt)) = laststore;
+         update_stmt (laststore);
+       }
+      else if (gimple_in_ssa_p (cfun))
+       {
+         unlink_stmt_vdef (stmt);
+         release_defs (stmt);
+       }
+      new_stmt = last;
     }
   else
     {
+      if (last)
+       {
+         gsi_insert_before (si_p, last, GSI_NEW_STMT);
+         gsi_next (si_p);
+       }
+      if (laststore && is_gimple_reg (lhs))
+       {
+         gimple_set_vdef (laststore, gimple_vdef (stmt));
+         update_stmt (laststore);
+         if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME)
+           SSA_NAME_DEF_STMT (gimple_vdef (stmt)) = laststore;
+         laststore = NULL;
+       }
+      else if (laststore)
+       {
+         reaching_vuse = make_ssa_name (gimple_vop (cfun), laststore);
+         gimple_set_vdef (laststore, reaching_vuse);
+         update_stmt (laststore);
+         laststore = NULL;
+       }
       new_stmt = gimple_build_assign (lhs, tmp);
-      gimple_set_vuse (new_stmt, gimple_vuse (stmt));
-      gimple_set_vdef (new_stmt, gimple_vdef (stmt));
-      move_ssa_defining_stmt_for_defs (new_stmt, stmt);
+      if (!is_gimple_reg (tmp))
+       gimple_set_vuse (new_stmt, reaching_vuse);
+      if (!is_gimple_reg (lhs))
+       {
+         gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+         if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME)
+           SSA_NAME_DEF_STMT (gimple_vdef (stmt)) = new_stmt;
+       }
+      else if (reaching_vuse == gimple_vuse (stmt))
+       unlink_stmt_vdef (stmt);
     }
 
   gimple_set_location (new_stmt, gimple_location (stmt));
index aa3b7018f47a680ea9aef51efd3e610a42fb237e..314705ccbfd13d7a9134bbd9def796423b42b92d 100644 (file)
@@ -369,7 +369,11 @@ new_var_info (tree t, const char *name)
   ret->may_have_pointers = true;
   ret->is_global_var = (t == NULL_TREE);
   if (t && DECL_P (t))
-    ret->is_global_var = is_global_var (t);
+    ret->is_global_var = (is_global_var (t)
+                         /* We have to treat even local register variables
+                            as escape points.  */
+                         || (TREE_CODE (t) == VAR_DECL
+                             && DECL_HARD_REGISTER (t)));
   ret->solution = BITMAP_ALLOC (&pta_obstack);
   ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
   ret->next = NULL;