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]

[tree-ssa] remove more useless gotos


Handles the case of

	{
	  {
	    ...
	    goto label;
	  }
	};
	label:

which you see a lot when inlining functions that return values.

Also adds a dump for remove_useless_stmts_and_vars, which makes
it easier for me to see what happens with eh lowering (which is
immediately afterward).


r~


        * tree-cfg.c (struct rusv_data): New.
        (remove_useless_stmts_and_vars_1): Rename from 
        remove_useless_stmts_and_vars.  Use rusv_data.  Handle goto-next
        via remembering the last goto seen, and zapping it when appropriate.
        (remove_useless_stmts_and_vars): New.  Loop until done.
        * tree-flow.h (remove_useless_stmts_and_vars): Update decl.
        * tree-optimize.c (optimize_function_tree): Don't cache fnbody.
        Dump data after remove_useless_stmts_and_vars.
        * tree-ssa.c (rewrite_out_of_ssa): Kill loop around 
        remove_useless_stmts_and_vars.
        * tree-dump.c (dump_files): Add .useless. 
        * tree.h (enum tree_dump_index): Add TDI_useless.

Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.163
diff -c -p -d -r1.1.4.163 tree-cfg.c
*** tree-cfg.c	13 Sep 2003 16:58:45 -0000	1.1.4.163
--- tree-cfg.c	17 Sep 2003 21:54:27 -0000
*************** cleanup_tree_cfg (void)
*** 1461,1471 ****
     BIND_EXPR, or TRY block, we will need to repeat this optimization pass
     to ensure we eliminate all the useless code.  */
  
! int
! remove_useless_stmts_and_vars (tree *first_p, int remove_unused_vars)
  {
    tree_stmt_iterator i;
-   int repeat = 0;
  
    for (i = tsi_start (first_p); !tsi_end_p (i); tsi_next (&i))
      {
--- 1461,1477 ----
     BIND_EXPR, or TRY block, we will need to repeat this optimization pass
     to ensure we eliminate all the useless code.  */
  
! struct rusv_data
! {
!   tree *last_goto;
!   bool repeat;
!   bool remove_unused_vars;
! };
! 
! static void
! remove_useless_stmts_and_vars_1 (tree *first_p, struct rusv_data *data)
  {
    tree_stmt_iterator i;
  
    for (i = tsi_start (first_p); !tsi_end_p (i); tsi_next (&i))
      {
*************** remove_useless_stmts_and_vars (tree *fir
*** 1488,1500 ****
        /* Dive into control structures.  */
        stmt_p = tsi_stmt_ptr (i);
        code = TREE_CODE (*stmt_p);
        if (code == COND_EXPR)
  	{
  	  tree then_clause, else_clause, cond;
! 	  repeat |= remove_useless_stmts_and_vars (&COND_EXPR_THEN (*stmt_p),
! 						   remove_unused_vars);
! 	  repeat |= remove_useless_stmts_and_vars (&COND_EXPR_ELSE (*stmt_p),
! 						   remove_unused_vars);
  
  	  then_clause = COND_EXPR_THEN (*stmt_p);
  	  else_clause = COND_EXPR_ELSE (*stmt_p);
--- 1494,1514 ----
        /* Dive into control structures.  */
        stmt_p = tsi_stmt_ptr (i);
        code = TREE_CODE (*stmt_p);
+ 
+       /* Zap last goto handling if we see anything that can generate code.  */
+       if (code != CASE_LABEL_EXPR && code != LABEL_EXPR && code != BIND_EXPR)
+ 	data->last_goto = NULL;
+ 
        if (code == COND_EXPR)
  	{
  	  tree then_clause, else_clause, cond;
! 	  remove_useless_stmts_and_vars_1 (&COND_EXPR_THEN (*stmt_p), data);
! 
! 	  if (!IS_EMPTY_STMT (COND_EXPR_ELSE (*stmt_p)))
! 	    {
! 	      data->last_goto = NULL;
! 	      remove_useless_stmts_and_vars_1 (&COND_EXPR_ELSE (*stmt_p), data);
! 	    }
  
  	  then_clause = COND_EXPR_THEN (*stmt_p);
  	  else_clause = COND_EXPR_ELSE (*stmt_p);
*************** remove_useless_stmts_and_vars (tree *fir
*** 1510,1529 ****
  	  if (integer_nonzerop (cond) && IS_EMPTY_STMT (else_clause))
  	    {
  	      *stmt_p = then_clause;
! 	       repeat = 1;
  	    }
  	  else if (integer_zerop (cond) && IS_EMPTY_STMT (then_clause))
  	    {
  	      *stmt_p = else_clause;
! 	       repeat = 1;
  	    }
  	  else if (TREE_CODE (then_clause) == GOTO_EXPR
! 	      && TREE_CODE (else_clause) == GOTO_EXPR
! 	      && (GOTO_DESTINATION (then_clause)
! 		  == GOTO_DESTINATION (else_clause)))
  	    {
  	      *stmt_p = then_clause;
! 	      repeat = 1;
  	    }
  	  /* If the THEN/ELSE clause merely assigns a value to
  	     a variable/parameter which is already known to contain
--- 1524,1543 ----
  	  if (integer_nonzerop (cond) && IS_EMPTY_STMT (else_clause))
  	    {
  	      *stmt_p = then_clause;
! 	       data->repeat = true;
  	    }
  	  else if (integer_zerop (cond) && IS_EMPTY_STMT (then_clause))
  	    {
  	      *stmt_p = else_clause;
! 	       data->repeat = true;
  	    }
  	  else if (TREE_CODE (then_clause) == GOTO_EXPR
! 		   && TREE_CODE (else_clause) == GOTO_EXPR
! 		   && (GOTO_DESTINATION (then_clause)
! 		       == GOTO_DESTINATION (else_clause)))
  	    {
  	      *stmt_p = then_clause;
! 	      data->repeat = true;
  	    }
  	  /* If the THEN/ELSE clause merely assigns a value to
  	     a variable/parameter which is already known to contain
*************** remove_useless_stmts_and_vars (tree *fir
*** 1554,1573 ****
  	    }
  	}
        else if (code == SWITCH_EXPR)
! 	repeat |= remove_useless_stmts_and_vars (&SWITCH_BODY (*stmt_p),
! 						 remove_unused_vars);
        else if (code == CATCH_EXPR)
! 	repeat |= remove_useless_stmts_and_vars (&CATCH_BODY (*stmt_p),
! 						 remove_unused_vars);
        else if (code == EH_FILTER_EXPR)
! 	repeat |= remove_useless_stmts_and_vars (&EH_FILTER_FAILURE (*stmt_p),
! 						 remove_unused_vars);
        else if (code == TRY_CATCH_EXPR || code == TRY_FINALLY_EXPR)
  	{
! 	  repeat |= remove_useless_stmts_and_vars (&TREE_OPERAND (*stmt_p, 0),
! 						   remove_unused_vars);
! 	  repeat |= remove_useless_stmts_and_vars (&TREE_OPERAND (*stmt_p, 1),
! 						   remove_unused_vars);
  
  	  /* If the handler of a TRY_CATCH or TRY_FINALLY is empty, then
  	     we can emit the TRY block without the enclosing TRY_CATCH_EXPR
--- 1568,1590 ----
  	    }
  	}
        else if (code == SWITCH_EXPR)
! 	remove_useless_stmts_and_vars_1 (&SWITCH_BODY (*stmt_p), data);
        else if (code == CATCH_EXPR)
! 	{
! 	  remove_useless_stmts_and_vars_1 (&CATCH_BODY (*stmt_p), data);
! 	  data->last_goto = NULL;
! 	}
        else if (code == EH_FILTER_EXPR)
! 	{
! 	  remove_useless_stmts_and_vars_1 (&EH_FILTER_FAILURE (*stmt_p), data);
! 	  data->last_goto = NULL;
! 	}
        else if (code == TRY_CATCH_EXPR || code == TRY_FINALLY_EXPR)
  	{
! 	  remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 0), data);
! 	  data->last_goto = NULL;
! 	  remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 1), data);
! 	  data->last_goto = NULL;
  
  	  /* If the handler of a TRY_CATCH or TRY_FINALLY is empty, then
  	     we can emit the TRY block without the enclosing TRY_CATCH_EXPR
*************** remove_useless_stmts_and_vars (tree *fir
*** 1575,1581 ****
  	  if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 1)))
  	    {
  	      *stmt_p = TREE_OPERAND (*stmt_p, 0);
! 	      repeat = 1;
  	    }
  
  	  /* If the body of a TRY_FINALLY is empty, then we can emit
--- 1592,1598 ----
  	  if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 1)))
  	    {
  	      *stmt_p = TREE_OPERAND (*stmt_p, 0);
! 	      data->repeat = true;
  	    }
  
  	  /* If the body of a TRY_FINALLY is empty, then we can emit
*************** remove_useless_stmts_and_vars (tree *fir
*** 1585,1591 ****
  		   && IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 0)))
  	    {
  	      *stmt_p = TREE_OPERAND (*stmt_p, 1);
! 	      repeat = 1;
  	    }
  
  	  /* If the body of a TRY_CATCH_EXPR is empty, then we can
--- 1602,1608 ----
  		   && IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 0)))
  	    {
  	      *stmt_p = TREE_OPERAND (*stmt_p, 1);
! 	      data->repeat = true;
  	    }
  
  	  /* If the body of a TRY_CATCH_EXPR is empty, then we can
*************** remove_useless_stmts_and_vars (tree *fir
*** 1594,1608 ****
  		   && IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 0)))
  	    {
  	      *stmt_p = build_empty_stmt ();
! 	      repeat = 1;
  	    }
  	}
        else if (code == BIND_EXPR)
  	{
  	  tree block;
  	  /* First remove anything underneath the BIND_EXPR.  */
! 	  repeat |= remove_useless_stmts_and_vars (&BIND_EXPR_BODY (*stmt_p),
! 						   remove_unused_vars);
  
  	  /* If the BIND_EXPR has no variables, then we can pull everything
  	     up one level and remove the BIND_EXPR, unless this is the
--- 1611,1625 ----
  		   && IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 0)))
  	    {
  	      *stmt_p = build_empty_stmt ();
! 	      data->repeat = true;
  	    }
  	}
        else if (code == BIND_EXPR)
  	{
  	  tree block;
+ 
  	  /* First remove anything underneath the BIND_EXPR.  */
! 	  remove_useless_stmts_and_vars_1 (&BIND_EXPR_BODY (*stmt_p), data);
  
  	  /* If the BIND_EXPR has no variables, then we can pull everything
  	     up one level and remove the BIND_EXPR, unless this is the
*************** remove_useless_stmts_and_vars (tree *fir
*** 1620,1628 ****
  		      != FUNCTION_DECL)))
  	    {
  	      *stmt_p = BIND_EXPR_BODY (*stmt_p);
! 	      repeat = 1;
  	    }
! 	  else if (remove_unused_vars)
  	    {
  	      /* If we were unable to completely eliminate the BIND_EXPR,
  		 go ahead and prune out any unused variables.  We do not
--- 1637,1645 ----
  		      != FUNCTION_DECL)))
  	    {
  	      *stmt_p = BIND_EXPR_BODY (*stmt_p);
! 	      data->repeat = true;
  	    }
! 	  else if (data->remove_unused_vars)
  	    {
  	      /* If we were unable to completely eliminate the BIND_EXPR,
  		 go ahead and prune out any unused variables.  We do not
*************** remove_useless_stmts_and_vars (tree *fir
*** 1684,1738 ****
  			  != FUNCTION_DECL)))
  		{
  		  *stmt_p = BIND_EXPR_BODY (*stmt_p);
! 		  repeat = 1;
  		}
  	    }
  	}
        else if (code == GOTO_EXPR)
  	{
! 	  tree_stmt_iterator tsi = i;
! 
! 	  /* Step past the GOTO_EXPR statement.  */
! 	  tsi_next (&tsi);
! 	  if (! tsi_end_p (tsi))
! 	    {
! 	      /* If we are not at the end of this tree, then see if
! 		 we are at the target label.  If so, then this jump
! 		 is not needed.  */
! 	      tree label;
! 
! 	      label = tsi_stmt (tsi);
! 	      if (TREE_CODE (label) == LABEL_EXPR
! 		  && LABEL_EXPR_LABEL (label) == GOTO_DESTINATION (*stmt_p))
! 		{
! 		  repeat = 1;
! 		  *stmt_p = build_empty_stmt ();
! 		}
! 	    }
! 	  else
  	    {
! 	      /* We are at the end of this tree, we may still have
! 		 an unnecessary GOTO_EXPR if NEXT_BLOCK_LINK
! 		 points to the target label.  */
! 	      tree next_block_link = NEXT_BLOCK_LINK (*stmt_p);
! 
! 	      if (next_block_link)
! 		{
! 		  tree next_stmt;
! 
! 		  /* Get the statement at NEXT_BLOCK_LINK and see if it
! 		     is our target label.  */
! 		  next_stmt = tsi_stmt (tsi_start (&next_block_link));
! 		  if (next_stmt
! 		      && TREE_CODE (next_stmt) == LABEL_EXPR
! 		      && (LABEL_EXPR_LABEL (next_stmt)
! 			  == GOTO_DESTINATION (*stmt_p)))
! 		    {
! 		      repeat = 1;
! 		      *stmt_p = build_empty_stmt ();
! 		    }
! 		}
! 
  	    }
  	}
  
--- 1701,1723 ----
  			  != FUNCTION_DECL)))
  		{
  		  *stmt_p = BIND_EXPR_BODY (*stmt_p);
! 		  data->repeat = true;
  		}
  	    }
  	}
        else if (code == GOTO_EXPR)
  	{
! 	  data->last_goto = stmt_p;
! 	}
!       else if (code == LABEL_EXPR)
! 	{
! 	  if (data->last_goto
! 	      && (GOTO_DESTINATION (*data->last_goto)
! 		  == LABEL_EXPR_LABEL (*stmt_p)))
  	    {
! 	      *data->last_goto = build_empty_stmt ();
! 	      data->last_goto = NULL;
!               data->repeat = true;
  	    }
  	}
  
*************** remove_useless_stmts_and_vars (tree *fir
*** 1740,1748 ****
  	 re-rationalize COMPOUND_EXPRs.  */
        if (TREE_CODE (*container_p) == COMPOUND_EXPR
  	  && TREE_CODE (TREE_OPERAND (*container_p, 0)) == COMPOUND_EXPR)
! 	*container_p = rationalize_compound_expr (*container_p);
      }
!   return repeat;
  }
  
  /* Delete all unreachable basic blocks.  Return true if any unreachable
--- 1725,1754 ----
  	 re-rationalize COMPOUND_EXPRs.  */
        if (TREE_CODE (*container_p) == COMPOUND_EXPR
  	  && TREE_CODE (TREE_OPERAND (*container_p, 0)) == COMPOUND_EXPR)
! 	{
! 	  *container_p = rationalize_compound_expr (*container_p);
! 	  /* Re-rationalization invalidates internal pointers.  */
! 	  data->repeat |= !!data->last_goto;
! 	  data->last_goto = NULL;
! 	}
      }
! }
! 
! void
! remove_useless_stmts_and_vars (tree *first_p, bool remove_unused_vars)
! {
!   struct rusv_data data;
! 
!   do
!     {
!       data.last_goto = NULL;
!       data.repeat = false;
!       data.remove_unused_vars = remove_unused_vars;
!       remove_unused_vars = false;
! 
!       remove_useless_stmts_and_vars_1 (first_p, &data);
!     }
!   while (data.repeat);
  }
  
  /* Delete all unreachable basic blocks.  Return true if any unreachable
Index: tree-dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dump.c,v
retrieving revision 1.6.2.37
diff -c -p -d -r1.6.2.37 tree-dump.c
*** tree-dump.c	11 Sep 2003 22:02:13 -0000	1.6.2.37
--- tree-dump.c	17 Sep 2003 21:54:27 -0000
*************** static struct dump_file_info dump_files[
*** 651,656 ****
--- 651,657 ----
    {".generic", "tree-generic", 0, 0},
    {".inlined", "tree-inlined", 0, 0},
    {".gimple", "tree-gimple", 0, 0},
+   {".useless", "tree-useless", 0, 0},
    {".cfg", "tree-cfg", 0, 0},
    {".dot", "tree-dot", 0, 0},
    {".pta", "tree-pta", 0, 0},
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.115
diff -c -p -d -r1.1.4.115 tree-flow.h
*** tree-flow.h	16 Sep 2003 03:08:08 -0000	1.1.4.115
--- tree-flow.h	17 Sep 2003 21:54:27 -0000
*************** extern tree last_stmt (basic_block);
*** 429,435 ****
  extern tree *last_stmt_ptr (basic_block);
  extern edge find_taken_edge (basic_block, tree);
  extern int call_expr_flags (tree);
! extern int remove_useless_stmts_and_vars (tree *, int);
  extern int could_trap_p (tree);
  extern basic_block tree_split_edge (edge);
  extern void bsi_move_before (block_stmt_iterator, block_stmt_iterator);
--- 429,435 ----
  extern tree *last_stmt_ptr (basic_block);
  extern edge find_taken_edge (basic_block, tree);
  extern int call_expr_flags (tree);
! extern void remove_useless_stmts_and_vars (tree *, bool);
  extern int could_trap_p (tree);
  extern basic_block tree_split_edge (edge);
  extern void bsi_move_before (block_stmt_iterator, block_stmt_iterator);
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.46
diff -c -p -d -r1.1.4.46 tree-optimize.c
*** tree-optimize.c	12 Sep 2003 16:15:52 -0000	1.1.4.46
--- tree-optimize.c	17 Sep 2003 21:54:27 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 54,75 ****
  void
  optimize_function_tree (tree fndecl)
  {
-   tree fnbody;
- 
    /* Don't bother doing anything if the program has errors.  */
    if (errorcount || sorrycount)
      return;
  
-   fnbody = DECL_SAVED_TREE (fndecl);
- 
    /* Build the flowgraph.  */
    init_flow ();
  
    /* Run a pass over the statements deleting any obviously useless
       statements before we build the CFG.  */
!   remove_useless_stmts_and_vars (&DECL_SAVED_TREE (fndecl), 0);
  
!   build_tree_cfg (fnbody);
  
    /* Begin analysis and optimization passes.  */
    if (n_basic_blocks > 0 && ! (errorcount || sorrycount))
--- 54,80 ----
  void
  optimize_function_tree (tree fndecl)
  {
    /* Don't bother doing anything if the program has errors.  */
    if (errorcount || sorrycount)
      return;
  
    /* Build the flowgraph.  */
    init_flow ();
  
    /* Run a pass over the statements deleting any obviously useless
       statements before we build the CFG.  */
!   remove_useless_stmts_and_vars (&DECL_SAVED_TREE (fndecl), false);
!   {
!     int flags;
!     FILE *file = dump_begin (TDI_useless, &flags);
!     if (file)
!       {
! 	dump_function_to_file (current_function_decl, file, flags);
! 	dump_end (TDI_useless, file);
!       }
!   }
  
!   build_tree_cfg (DECL_SAVED_TREE (fndecl));
  
    /* Begin analysis and optimization passes.  */
    if (n_basic_blocks > 0 && ! (errorcount || sorrycount))
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.125
diff -c -p -d -r1.1.4.125 tree-ssa.c
*** tree-ssa.c	13 Sep 2003 02:08:59 -0000	1.1.4.125
--- tree-ssa.c	17 Sep 2003 21:54:27 -0000
*************** rewrite_out_of_ssa (tree fndecl)
*** 1638,1644 ****
    var_map map;
    tree phi, next;
    elim_graph g;
-   int repeat, first_iteration;
    tree_live_info_p liveinfo;
  
    timevar_push (TV_TREE_SSA_TO_NORMAL);
--- 1638,1643 ----
*************** rewrite_out_of_ssa (tree fndecl)
*** 1763,1777 ****
  
    /* Do some cleanups which reduce the amount of data the
       tree->rtl expanders deal with.  */
!   first_iteration = 1;
!   do
!     {
!       repeat = remove_useless_stmts_and_vars (&DECL_SAVED_TREE (fndecl),
! 					      first_iteration);
!       first_iteration = 0;
!     }
!   while (repeat);
!   
    /* Flush out flow graph and SSA data.  */
    delete_tree_ssa (fndecl);
    delete_tree_cfg ();
--- 1762,1769 ----
  
    /* Do some cleanups which reduce the amount of data the
       tree->rtl expanders deal with.  */
!   remove_useless_stmts_and_vars (&DECL_SAVED_TREE (fndecl), true);
! 
    /* Flush out flow graph and SSA data.  */
    delete_tree_ssa (fndecl);
    delete_tree_cfg ();
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.97
diff -c -p -d -r1.342.2.97 tree.h
*** tree.h	11 Sep 2003 22:02:12 -0000	1.342.2.97
--- tree.h	17 Sep 2003 21:54:28 -0000
*************** enum tree_dump_index
*** 3435,3440 ****
--- 3435,3441 ----
    TDI_inlined,			/* dump each function after inlining
  				   within it.  */
    TDI_gimple,			/* dump each function after gimplifying it.  */
+   TDI_useless,			/* dump after cleaning useless bits.  */
    TDI_cfg,			/* dump the flowgraph for each function.  */
    TDI_dot,			/* create a dot graph file for each 
  				   function's flowgraph.  */


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