re PR tree-optimization/41490 (tree-ssa-sink does not really work)
authorRichard Guenther <rguenther@suse.de>
Tue, 15 Mar 2011 11:09:09 +0000 (11:09 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Tue, 15 Mar 2011 11:09:09 +0000 (11:09 +0000)
2011-03-15  Richard Guenther  <rguenther@suse.de>

PR tree-optimization/41490
* tree-ssa-dce.c (propagate_necessity): Handle returns without
value but with VUSE.
* tree-ssa-operands.c (parse_ssa_operands): Add a VUSE on all
return statements.
* tree-ssa-sink.c (statement_sink_location): Fix store sinking.
* tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Handle virtual PHIs.
* tree-tailcall.c (find_tail_calls): Ignore returns.

* gcc.dg/tree-ssa/ssa-sink-6.c: New testcase.
* gcc.dg/tree-ssa/ssa-sink-7.c: Likewise.
* gcc.dg/tree-ssa/ssa-sink-8.c: Likewise.
* gcc.dg/tree-ssa/ssa-sink-9.c: Likewise.
* g++.dg/tree-ssa/pr33604.C: Adjust.

From-SVN: r170984

12 files changed:
gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/pr33604.C
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-9.c [new file with mode: 0644]
gcc/tree-ssa-dce.c
gcc/tree-ssa-operands.c
gcc/tree-ssa-phiopt.c
gcc/tree-ssa-sink.c
gcc/tree-tailcall.c

index 94e8260e2076639cac4b20d51dab9ac8367fcb50..3c55339f4245393766ef3911e21688913b2775b5 100644 (file)
@@ -1,3 +1,14 @@
+2011-03-15  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/41490
+       * tree-ssa-dce.c (propagate_necessity): Handle returns without
+       value but with VUSE.
+       * tree-ssa-operands.c (parse_ssa_operands): Add a VUSE on all
+       return statements.
+       * tree-ssa-sink.c (statement_sink_location): Fix store sinking.
+       * tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Handle virtual PHIs.
+       * tree-tailcall.c (find_tail_calls): Ignore returns.
+
 2011-03-15  Richard Guenther  <rguenther@suse.de>
 
        PR middle-end/48031
index 016c2a9c458b254b12f3b2e110ac5dc6b387ee5b..2db72ee2a5d50faa1ff39e39b72cc5bea6e4de15 100644 (file)
@@ -1,3 +1,12 @@
+2011-03-15  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/41490
+       * gcc.dg/tree-ssa/ssa-sink-6.c: New testcase.
+       * gcc.dg/tree-ssa/ssa-sink-7.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-sink-8.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-sink-9.c: Likewise.
+       * g++.dg/tree-ssa/pr33604.C: Adjust.
+
 2011-03-14  Jakub Jelinek  <jakub@redhat.com>
 
        PR middle-end/47917
index 7e820d3ef16fba00ab646117db124bc6b25296c3..039b3be02a4e4edb43c4117d704c3dcd1ba2cfbc 100644 (file)
@@ -42,7 +42,8 @@ int main(int argc, char *argv[])
    yielding
      D.2137.lhs.m ={v} &I;
    so that SRA can promote all locals to registers and we end up
-   referencing a single virtual operand at abort () after optimization.  */
+   referencing two virtual operands at abort () and the return
+   after optimization.  */
 
-/* { dg-final { scan-tree-dump-times ".MEM_\[0-9\]*\\\(D\\\)" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times ".MEM_\[0-9\]*\\\(D\\\)" 2 "optimized" } } */
 /* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-6.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-6.c
new file mode 100644 (file)
index 0000000..70e4812
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-sink" } */
+
+int foo(int *a, int r)
+{
+  int ret = 0;
+  *a = 1;
+  if (r == 3)
+    *a = 5;
+  else
+    ret = r + 20;
+  return ret;
+}
+
+/* *a = 1 should be sunk to the else block.  */
+
+/* { dg-final { scan-tree-dump-times "Sinking" 1 "sink" } } */
+/* { dg-final { cleanup-tree-dump "sink" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-7.c
new file mode 100644 (file)
index 0000000..ffee033
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-sink" } */
+
+int foo(int *a, int r, short *b)
+{
+  int ret = 0;
+  *a = 1;
+  if (r == 3)
+    *a = 5;
+  else
+    ret = r + 20;
+  *b = 9;
+  return ret;
+}
+
+/* *a = 1 should be sunk to the else block.  */
+
+/* { dg-final { scan-tree-dump-times "Sinking" 1 "sink" } } */
+/* { dg-final { cleanup-tree-dump "sink" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-8.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-8.c
new file mode 100644 (file)
index 0000000..4a575a7
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-sink" } */
+
+int foo(int *a, int r, short *b)
+{
+  int ret = 0;
+  *a = 1;
+  switch (r)
+    {
+      case 3:
+         *a = 5;
+         break;
+      case 4:
+      case 5:
+         *a = 9;
+         ret = r + 25;
+         break;
+      default:
+         ret = r + 20;
+    }
+  *b = 9;
+  return ret;
+}
+
+/* *a = 1 should be sunk into the default case.  */
+
+/* { dg-final { scan-tree-dump-times "Sinking" 1 "sink" } } */
+/* { dg-final { cleanup-tree-dump "sink" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-9.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-9.c
new file mode 100644 (file)
index 0000000..1a6e2b8
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-sink" } */
+
+int foo(int *a, int r, int *b)
+{
+  int ret = 0;
+  *a = 1;
+  if (r == 3)
+    {
+      *a = 5;
+      *b = 3;
+    }
+  return ret;
+}
+
+/* *a = 1 should be sunk to the else block.  */
+
+/* { dg-final { scan-tree-dump-times "Sinking" 1 "sink" } } */
+/* { dg-final { cleanup-tree-dump "sink" } } */
index a9c886f0a8fa40d0f42196960c2cd7701ff1162d..ce2d41bff31535dfc6bedb0bf3ffc83948fc265e 100644 (file)
@@ -869,7 +869,8 @@ propagate_necessity (struct edge_list *el)
            {
              tree rhs = gimple_return_retval (stmt);
              /* A return statement may perform a load.  */
-             if (TREE_CODE (rhs) != SSA_NAME
+             if (rhs
+                 && TREE_CODE (rhs) != SSA_NAME
                  && !is_gimple_min_invariant (rhs))
                {
                  if (!ref_may_be_aliased (rhs))
index d05f814917021d1be44874d6f3feeb91cb25bd39..7e2600d6e6d005bc63b0fbd13531cb4d4af0afd5 100644 (file)
@@ -1065,6 +1065,9 @@ parse_ssa_operands (gimple stmt)
       /* Add call-clobbered operands, if needed.  */
       if (code == GIMPLE_CALL)
        maybe_add_call_vops (stmt);
+
+      if (code == GIMPLE_RETURN)
+       append_vuse (gimple_vop (cfun));
     }
 }
 
index d197bdd207ac471038024adf5e2836ff7b0bd20c..e5ff6837abf8de9e3a5699f6e3ed800628f879c4 100644 (file)
@@ -311,14 +311,26 @@ tree_ssa_phiopt_worker (bool do_store_elim)
       else
        {
          gimple_seq phis = phi_nodes (bb2);
+         gimple_stmt_iterator gsi;
 
-         /* Check to make sure that there is only one PHI node.
+         /* Check to make sure that there is only one non-virtual PHI node.
             TODO: we could do it with more than one iff the other PHI nodes
             have the same elements for these two edges.  */
-         if (! gimple_seq_singleton_p (phis))
+         phi = NULL;
+         for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
+           {
+             if (!is_gimple_reg (gimple_phi_result (gsi_stmt (gsi))))
+               continue;
+             if (phi)
+               {
+                 phi = NULL;
+                 break;
+               }
+             phi = gsi_stmt (gsi);
+           }
+         if (!phi)
            continue;
 
-         phi = gsi_stmt (gsi_start (phis));
          arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
          arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
 
index 962c2955e26eada93684b8852004723553a3e87f..c3119ba5a70367acda940d0a868884cffa401a46 100644 (file)
@@ -268,7 +268,6 @@ statement_sink_location (gimple stmt, basic_block frombb,
                         gimple_stmt_iterator *togsi)
 {
   gimple use;
-  tree def;
   use_operand_p one_use = NULL_USE_OPERAND_P;
   basic_block sinkbb;
   use_operand_p use_p;
@@ -276,24 +275,17 @@ statement_sink_location (gimple stmt, basic_block frombb,
   ssa_op_iter iter;
   imm_use_iterator imm_iter;
 
-  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
-    {
-      FOR_EACH_IMM_USE_FAST (one_use, imm_iter, def)
-       {
-         if (is_gimple_debug (USE_STMT (one_use)))
-           continue;
-
-         break;
-       }
-      if (one_use != NULL_USE_OPERAND_P)
-        break;
-    }
+  /* We only can sink assignments.  */
+  if (!is_gimple_assign (stmt))
+    return false;
 
-  /* Return if there are no immediate uses of this stmt.  */
-  if (one_use == NULL_USE_OPERAND_P)
+  /* We only can sink stmts with a single definition.  */
+  def_p = single_ssa_def_operand (stmt, SSA_OP_ALL_DEFS);
+  if (def_p == NULL_DEF_OPERAND_P)
     return false;
 
-  if (gimple_code (stmt) != GIMPLE_ASSIGN)
+  /* Return if there are no immediate uses of this stmt.  */
+  if (has_zero_uses (DEF_FROM_PTR (def_p)))
     return false;
 
   /* There are a few classes of things we can't or don't move, some because we
@@ -323,20 +315,14 @@ statement_sink_location (gimple stmt, basic_block frombb,
   */
   if (stmt_ends_bb_p (stmt)
       || gimple_has_side_effects (stmt)
-      || is_hidden_global_store (stmt)
       || gimple_has_volatile_ops (stmt)
-      || gimple_vuse (stmt)
+      || (gimple_vuse (stmt) && !gimple_vdef (stmt))
       || (cfun->has_local_explicit_reg_vars
          && TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt))) == BLKmode))
     return false;
 
-  FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_ALL_DEFS)
-    {
-      tree def = DEF_FROM_PTR (def_p);
-      if (is_global_var (SSA_NAME_VAR (def))
-         || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
-       return false;
-    }
+  if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (DEF_FROM_PTR (def_p)))
+    return false;
 
   FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
     {
@@ -345,11 +331,40 @@ statement_sink_location (gimple stmt, basic_block frombb,
        return false;
     }
 
+  use = NULL;
+
+  /* If stmt is a store the one and only use needs to be the VOP
+     merging PHI node.  */
+  if (gimple_vdef (stmt))
+    {
+      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
+       {
+         gimple use_stmt = USE_STMT (use_p);
+
+         /* A killing definition is not a use.  */
+         if (gimple_assign_single_p (use_stmt)
+             && gimple_vdef (use_stmt)
+             && operand_equal_p (gimple_assign_lhs (stmt),
+                                 gimple_assign_lhs (use_stmt), 0))
+           continue;
+
+         if (gimple_code (use_stmt) != GIMPLE_PHI)
+           return false;
+
+         if (use
+             && use != use_stmt)
+           return false;
+
+         use = use_stmt;
+       }
+      if (!use)
+       return false;
+    }
   /* If all the immediate uses are not in the same place, find the nearest
      common dominator of all the immediate uses.  For PHI nodes, we have to
      find the nearest common dominator of all of the predecessor blocks, since
      that is where insertion would have to take place.  */
-  if (!all_immediate_uses_same_place (stmt))
+  else if (!all_immediate_uses_same_place (stmt))
     {
       bool debug_stmts = false;
       basic_block commondom = nearest_common_dominator_of_uses (stmt,
@@ -387,31 +402,35 @@ statement_sink_location (gimple stmt, basic_block frombb,
 
       return true;
     }
-
-  use = USE_STMT (one_use);
-  if (gimple_code (use) != GIMPLE_PHI)
+  else
     {
-      sinkbb = gimple_bb (use);
-      if (sinkbb == frombb || sinkbb->loop_depth > frombb->loop_depth
-         || sinkbb->loop_father != frombb->loop_father)
-       return false;
+      FOR_EACH_IMM_USE_FAST (one_use, imm_iter, DEF_FROM_PTR (def_p))
+       {
+         if (is_gimple_debug (USE_STMT (one_use)))
+           continue;
+         break;
+       }
+      use = USE_STMT (one_use);
 
-      /* Move the expression to a post dominator can't reduce the number of
-         executions.  */
-      if (dominated_by_p (CDI_POST_DOMINATORS, frombb, sinkbb))
-        return false;
+      if (gimple_code (use) != GIMPLE_PHI)
+       {
+         sinkbb = gimple_bb (use);
+         if (sinkbb == frombb || sinkbb->loop_depth > frombb->loop_depth
+             || sinkbb->loop_father != frombb->loop_father)
+           return false;
 
-      *togsi = gsi_for_stmt (use);
+         /* Move the expression to a post dominator can't reduce the number of
+            executions.  */
+         if (dominated_by_p (CDI_POST_DOMINATORS, frombb, sinkbb))
+           return false;
 
-      return true;
-    }
+         *togsi = gsi_for_stmt (use);
 
-  /* Note that at this point, all uses must be in the same statement, so it
-     doesn't matter which def op we choose, pick the first one.  */
-  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
-    break;
+         return true;
+       }
+    }
 
-  sinkbb = find_bb_for_arg (use, def);
+  sinkbb = find_bb_for_arg (use, DEF_FROM_PTR (def_p));
   if (!sinkbb)
     return false;
 
@@ -486,6 +505,14 @@ sink_code_in_bb (basic_block bb)
                   bb->index, (gsi_bb (togsi))->index);
        }
 
+      /* Prepare for VOP update.  */
+      if (gimple_vdef (stmt))
+       {
+         unlink_stmt_vdef (stmt);
+         gimple_set_vdef (stmt, gimple_vop (cfun));
+         mark_sym_for_renaming (gimple_vop (cfun));
+       }
+
       /* If this is the end of the basic block, we need to insert at the end
          of the basic block.  */
       if (gsi_end_p (togsi))
index 85aa82bc8555d80bb839c8adcabf7383a6852a52..c94d6ca824bcd5e171bd723b030983b2c12e15ad 100644 (file)
@@ -399,8 +399,10 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
     {
       stmt = gsi_stmt (gsi);
 
-      /* Ignore labels.  */
-      if (gimple_code (stmt) == GIMPLE_LABEL || is_gimple_debug (stmt))
+      /* Ignore labels, returns and debug stmts.  */
+      if (gimple_code (stmt) == GIMPLE_LABEL
+         || gimple_code (stmt) == GIMPLE_RETURN
+         || is_gimple_debug (stmt))
        continue;
 
       /* Check for a call.  */