This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR41490


This fixes store-sinking (finally, broken since alias-improvements
merge).  To work reliably this adds an unconditional VUSE to all
return statements.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

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.

Index: gcc/tree-ssa-dce.c
===================================================================
*** gcc/tree-ssa-dce.c.orig	2011-03-09 17:57:48.000000000 +0100
--- gcc/tree-ssa-dce.c	2011-03-09 18:03:30.000000000 +0100
*************** propagate_necessity (struct edge_list *e
*** 869,875 ****
  	    {
  	      tree rhs = gimple_return_retval (stmt);
  	      /* A return statement may perform a load.  */
! 	      if (TREE_CODE (rhs) != SSA_NAME
  		  && !is_gimple_min_invariant (rhs))
  		{
  		  if (!ref_may_be_aliased (rhs))
--- 869,876 ----
  	    {
  	      tree rhs = gimple_return_retval (stmt);
  	      /* A return statement may perform a load.  */
! 	      if (rhs
! 		  && TREE_CODE (rhs) != SSA_NAME
  		  && !is_gimple_min_invariant (rhs))
  		{
  		  if (!ref_may_be_aliased (rhs))
Index: gcc/tree-ssa-operands.c
===================================================================
*** gcc/tree-ssa-operands.c.orig	2011-03-09 17:57:48.000000000 +0100
--- gcc/tree-ssa-operands.c	2011-03-09 18:03:30.000000000 +0100
*************** parse_ssa_operands (gimple stmt)
*** 1065,1070 ****
--- 1065,1073 ----
        /* 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: gcc/tree-ssa-sink.c
===================================================================
*** gcc/tree-ssa-sink.c.orig	2011-03-09 17:57:48.000000000 +0100
--- gcc/tree-ssa-sink.c	2011-03-09 18:03:30.000000000 +0100
*************** statement_sink_location (gimple stmt, ba
*** 268,274 ****
  			 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;
--- 268,273 ----
*************** statement_sink_location (gimple stmt, ba
*** 276,299 ****
    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;
!     }
  
!   /* Return if there are no immediate uses of this stmt.  */
!   if (one_use == NULL_USE_OPERAND_P)
      return false;
  
!   if (gimple_code (stmt) != GIMPLE_ASSIGN)
      return false;
  
    /* There are a few classes of things we can't or don't move, some because we
--- 275,291 ----
    ssa_op_iter iter;
    imm_use_iterator imm_iter;
  
!   /* We only can sink assignments.  */
!   if (!is_gimple_assign (stmt))
!     return false;
  
!   /* 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;
  
!   /* 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
*************** statement_sink_location (gimple stmt, ba
*** 323,342 ****
    */
    if (stmt_ends_bb_p (stmt)
        || gimple_has_side_effects (stmt)
-       || is_hidden_global_store (stmt)
        || gimple_has_volatile_ops (stmt)
!       || gimple_vuse (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;
!     }
  
    FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
      {
--- 315,328 ----
    */
    if (stmt_ends_bb_p (stmt)
        || gimple_has_side_effects (stmt)
        || gimple_has_volatile_ops (stmt)
!       || (gimple_vuse (stmt) && !gimple_vdef (stmt))
        || (cfun->has_local_explicit_reg_vars
  	  && TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt))) == BLKmode))
      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)
      {
*************** statement_sink_location (gimple stmt, ba
*** 345,355 ****
  	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))
      {
        bool debug_stmts = false;
        basic_block commondom = nearest_common_dominator_of_uses (stmt,
--- 331,370 ----
  	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.  */
!   else if (!all_immediate_uses_same_place (stmt))
      {
        bool debug_stmts = false;
        basic_block commondom = nearest_common_dominator_of_uses (stmt,
*************** statement_sink_location (gimple stmt, ba
*** 387,417 ****
  
        return true;
      }
! 
!   use = USE_STMT (one_use);
!   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;
  
!       /* 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;
  
!       *togsi = gsi_for_stmt (use);
  
!       return true;
      }
  
!   /* 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;
! 
!   sinkbb = find_bb_for_arg (use, def);
    if (!sinkbb)
      return false;
  
--- 402,436 ----
  
        return true;
      }
!   else
      {
!       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);
  
!       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;
! 
! 	  /* 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;
  
! 	  *togsi = gsi_for_stmt (use);
  
! 	  return true;
! 	}
      }
  
!   sinkbb = find_bb_for_arg (use, DEF_FROM_PTR (def_p));
    if (!sinkbb)
      return false;
  
*************** sink_code_in_bb (basic_block bb)
*** 486,491 ****
--- 505,518 ----
  		   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: gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-6.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-6.c	2011-03-09 18:03:30.000000000 +0100
***************
*** 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" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-7.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-7.c	2011-03-09 18:03:30.000000000 +0100
***************
*** 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" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-8.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-8.c	2011-03-09 18:03:30.000000000 +0100
***************
*** 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" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-9.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-9.c	2011-03-09 18:03:30.000000000 +0100
***************
*** 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: gcc/testsuite/g++.dg/tree-ssa/pr33604.C
===================================================================
*** gcc/testsuite/g++.dg/tree-ssa/pr33604.C.orig	2010-07-01 10:55:04.000000000 +0200
--- gcc/testsuite/g++.dg/tree-ssa/pr33604.C	2011-03-10 12:32:41.000000000 +0100
*************** int main(int argc, char *argv[])
*** 42,48 ****
     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.  */
  
! /* { dg-final { scan-tree-dump-times ".MEM_\[0-9\]*\\\(D\\\)" 1 "optimized" } } */
  /* { dg-final { cleanup-tree-dump "optimized" } } */
--- 42,49 ----
     yielding
       D.2137.lhs.m ={v} &I;
     so that SRA can promote all locals to registers and we end up
!    referencing two virtual operands at abort () and the return
!    after optimization.  */
  
! /* { dg-final { scan-tree-dump-times ".MEM_\[0-9\]*\\\(D\\\)" 2 "optimized" } } */
  /* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/tree-ssa-phiopt.c
===================================================================
*** gcc/tree-ssa-phiopt.c.orig	2010-11-03 16:54:55.000000000 +0100
--- gcc/tree-ssa-phiopt.c	2011-03-10 13:08:09.000000000 +0100
*************** tree_ssa_phiopt_worker (bool do_store_el
*** 311,324 ****
        else
  	{
  	  gimple_seq phis = phi_nodes (bb2);
  
! 	  /* Check to make sure that there is only one 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))
  	    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);
  
--- 311,336 ----
        else
  	{
  	  gimple_seq phis = phi_nodes (bb2);
+ 	  gimple_stmt_iterator gsi;
  
! 	  /* 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.  */
! 	  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;
  
  	  arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
  	  arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
  
Index: gcc/tree-tailcall.c
===================================================================
*** gcc/tree-tailcall.c.orig	2011-02-16 11:18:16.000000000 +0100
--- gcc/tree-tailcall.c	2011-03-10 12:30:52.000000000 +0100
*************** find_tail_calls (basic_block bb, struct
*** 399,406 ****
      {
        stmt = gsi_stmt (gsi);
  
!       /* Ignore labels.  */
!       if (gimple_code (stmt) == GIMPLE_LABEL || is_gimple_debug (stmt))
  	continue;
  
        /* Check for a call.  */
--- 399,408 ----
      {
        stmt = gsi_stmt (gsi);
  
!       /* 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.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]