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]

Re: [tree-ssa] Block merging (updated)


Hello,

>  >> +   /* Remove labels from B and set bb_for_stmt to A for other statements. 
>  > */
>  >> +   for (bsi = bsi_start (b); !bsi_end_p (bsi);)
>  >> +     {
>  >> +       if (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR)
>  >> +       bsi_remove (&bsi);
>  >> +       else
>  >> +       {
>  >> +         set_bb_for_stmt (bsi_stmt (bsi), a);
>  >> +         bsi_next (&bsi);
>  >> +       }
>  >> +     }
>  >> 
>  >> 
>  >> This will remove user-declared labels.  IIRC some people wanted these to be
>  >> preserved, e.g. for debugging purposes.  Perhaps tree_can_merge_blocks_p
>  >> should be false if a user label heads the basic block.
>  >
>  >there is IMHO no point in this, since rtl level cfgcleanup would do the
>  >merging and removing of the label anyway.
> If the RTL cfgcleanup is removing a user label, then that code is buggy.
> 
> Please avoid removing user declared labels.

here is the patch.  Btw., why is it so crucial to preserve these labels?
Their removal would only occur during optimizing compilation, so the
fact that the debug info would be incomplete is not that serious.

If there really is some reason why not to remove them, we should also
fix other places that cause it (jump threading, OTOH, perhaps some
other).

Zdenek

Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.153.2.40
diff -c -3 -p -r1.153.2.40 basic-block.h
*** basic-block.h	3 Jan 2004 23:01:35 -0000	1.153.2.40
--- basic-block.h	13 Jan 2004 17:02:51 -0000
*************** extern void alloc_aux_for_edge (edge, in
*** 591,596 ****
--- 591,600 ----
  extern void alloc_aux_for_edges (int);
  extern void clear_aux_for_edges (void);
  extern void free_aux_for_edges (void);
+ extern void find_basic_blocks (rtx, int, FILE *);
+ extern bool cleanup_cfg (int);
+ extern bool delete_unreachable_blocks (void);
+ extern bool merge_seq_blocks (void);
  
  /* This function is always defined so it can be called from the
     debugger, and it is declared extern so we don't get warnings about
Index: cfgcleanup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgcleanup.c,v
retrieving revision 1.62.2.17
diff -c -3 -p -r1.62.2.17 cfgcleanup.c
*** cfgcleanup.c	3 Jan 2004 23:01:38 -0000	1.62.2.17
--- cfgcleanup.c	13 Jan 2004 17:02:51 -0000
*************** delete_unreachable_blocks (void)
*** 1893,1898 ****
--- 1893,1924 ----
      tidy_fallthru_edges ();
    return changed;
  }
+ 
+ /* Merges sequential blocks if possible.  */
+ 
+ bool
+ merge_seq_blocks (void)
+ {
+   basic_block bb;
+   bool changed = false;
+ 
+   for (bb = ENTRY_BLOCK_PTR->next_bb; bb != EXIT_BLOCK_PTR; )
+     {
+       if (bb->succ
+ 	  && !bb->succ->succ_next
+ 	  && can_merge_blocks_p (bb, bb->succ->dest))
+ 	{
+ 	  /* Merge the blocks and retry.  */
+ 	  merge_blocks (bb, bb->succ->dest);
+ 	  changed = true;
+ 	  continue;
+ 	}
+ 
+       bb = bb->next_bb;
+     }
+ 
+   return changed;
+ }
  
  /* Tidy the CFG by deleting unreachable code and whatnot.  */
  
Index: output.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/output.h,v
retrieving revision 1.107.2.18
diff -c -3 -p -r1.107.2.18 output.h
*** output.h	6 Oct 2003 17:36:36 -0000	1.107.2.18
--- output.h	13 Jan 2004 17:02:51 -0000
*************** extern int add_weak (tree, const char *,
*** 152,160 ****
  extern void allocate_for_life_analysis (void);
  extern int regno_uninitialized (unsigned int);
  extern int regno_clobbered_at_setjmp (int);
- extern void find_basic_blocks (rtx, int, FILE *);
- extern bool cleanup_cfg (int);
- extern bool delete_unreachable_blocks (void);
  extern void check_function_return_warnings (void);
  
  /* Functions in varasm.c.  */
--- 152,157 ----
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.250
diff -c -3 -p -r1.1.4.250 tree-cfg.c
*** tree-cfg.c	12 Jan 2004 23:39:32 -0000	1.1.4.250
--- tree-cfg.c	13 Jan 2004 17:02:51 -0000
*************** static void make_switch_expr_edges (basi
*** 95,100 ****
--- 95,101 ----
  static void make_goto_expr_edges (basic_block);
  static edge tree_redirect_edge_and_branch_1 (edge, basic_block, bool);
  static edge tree_redirect_edge_and_branch (edge, basic_block);
+ static edge tree_try_redirect_by_replacing_jump (edge, basic_block);
  
  /* Various helpers.  */
  static inline bool stmt_starts_bb_p (tree, tree);
*************** static void bsi_commit_edge_inserts_1 (e
*** 108,113 ****
--- 109,116 ----
  
  /* Flowgraph optimization and cleanup.  */
  
+ static void tree_merge_blocks (basic_block, basic_block);
+ static bool tree_can_merge_blocks_p (basic_block, basic_block);
  static void remove_bb (basic_block);
  static bool cleanup_control_flow (void);
  static edge find_taken_edge_cond_expr (basic_block, tree);
*************** cleanup_tree_cfg (void)
*** 726,733 ****
  
    timevar_push (TV_TREE_CLEANUP_CFG);
  
!   /* These three transformations can cascade, so we iterate on them until nothing
!      changes.  */
    while (something_changed)
      {
        something_changed = cleanup_control_flow ();
--- 729,736 ----
  
    timevar_push (TV_TREE_CLEANUP_CFG);
  
!   /* These three transformations can cascade, so we iterate on them until
!      nothing changes.  */
    while (something_changed)
      {
        something_changed = cleanup_control_flow ();
*************** cleanup_tree_cfg (void)
*** 735,740 ****
--- 738,747 ----
        something_changed |= remove_unreachable_blocks ();
      }
  
+   /* Merging the blocks creates no new opportunities for the other
+      optimizations, so do it here.  */
+   merge_seq_blocks ();
+ 
    compact_blocks ();
  
  #ifdef ENABLE_CHECKING
*************** cleanup_tree_cfg (void)
*** 743,748 ****
--- 750,874 ----
    timevar_pop (TV_TREE_CLEANUP_CFG);
  }
  
+ /* Checks whether we can merge block B into block A.  */
+ 
+ static bool
+ tree_can_merge_blocks_p (basic_block a, basic_block b)
+ {
+   tree last;
+   block_stmt_iterator bsi;
+ 
+   if (!a->succ
+       || a->succ->succ_next)
+     return false;
+ 
+   if (a->succ->flags & EDGE_ABNORMAL)
+     return false;
+ 
+   if (a->succ->dest != b)
+     return false;
+ 
+   if (b == EXIT_BLOCK_PTR)
+     return false;
+   
+   if (b->pred->pred_next)
+     return false;
+ 
+   /* If A ends by a statement causing exceptions or something similar, we
+      cannot merge the blocks.  */
+   last = last_stmt (a);
+   if (last
+       && stmt_ends_bb_p (last))
+     return false;
+ 
+   /* There may be no phi nodes at the start of b.  Most of these degenerate
+      phi nodes should be cleaned up by kill_redundant_phi_nodes.  */
+ 
+   if (phi_nodes (b))
+     return false;
+ 
+   /* Do not remove user labels.  */
+   for (bsi = bsi_start (b); !bsi_end_p (bsi); bsi_next (&bsi))
+     {
+       last = bsi_stmt (bsi);
+       if (TREE_CODE (last) != LABEL_EXPR)
+ 	break;
+ 
+       if (!DECL_ARTIFICIAL (LABEL_EXPR_LABEL (last)))
+ 	return false;
+     }
+ 
+   return true;
+ }
+ 
+ /* Moves basic block BB after block AFTER.  */
+ 
+ static void
+ tree_move_block_after (basic_block bb, basic_block after)
+ {
+   if (bb->prev_bb == after)
+     return;
+ 
+   unlink_block (bb);
+   link_block (bb, after);
+ }
+ 
+ /* Merges block B into block A.  */
+ 
+ static void
+ tree_merge_blocks (basic_block a, basic_block b)
+ {
+   block_stmt_iterator bsi;
+   edge e;
+   tree_stmt_iterator last;
+ 
+   if (tree_dump_file)
+     fprintf (tree_dump_file, "Merging blocks %d and %d\n", a->index, b->index);
+ 
+   /* Ensure that b follows a.  */
+   tree_move_block_after (b, a);
+ 
+   if (!(a->succ->flags & EDGE_FALLTHRU))
+     abort ();
+ 
+   if (last_stmt (a)
+       && stmt_ends_bb_p (last_stmt (a)))
+     abort ();
+ 
+   /* Remove labels from B and set bb_for_stmt to A for other statements.  */
+   for (bsi = bsi_start (b); !bsi_end_p (bsi);)
+     {
+       if (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR)
+ 	bsi_remove (&bsi);
+       else
+ 	{
+ 	  set_bb_for_stmt (bsi_stmt (bsi), a);
+ 	  bsi_next (&bsi);
+ 	}
+     }
+ 
+   remove_edge (a->succ);
+ 
+   /* Merge the chains.  */
+   last = tsi_last (a->stmt_list);
+   tsi_link_after (&last, b->stmt_list, TSI_NEW_STMT);
+   b->stmt_list = alloc_stmt_list ();
+ 
+   /* Redirect the edges.  */
+   a->succ = b->succ;
+   b->succ = NULL;
+   for (e = a->succ; e; e = e->succ_next)
+     e->src = a;
+ 
+   /* Update dominance information.  */
+   if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
+     redirect_immediate_dominators (CDI_DOMINATORS, b, a);
+ 
+   /* Remove B.  */
+   delete_basic_block (b);
+ }
+ 
+ 
  /* Walk the function tree removing unnecessary statements.
  
       * Empty statement nodes are removed
*************** remove_bb (basic_block bb)
*** 1473,1478 ****
--- 1599,1607 ----
  
    remove_phi_nodes_and_edges_for_unreachable_block (bb);
  
+   if (dom_computed[CDI_DOMINATORS])
+     delete_from_dominance_info (CDI_DOMINATORS, bb);
+     
    /* Remove the basic block from the array.  */
    expunge_block (bb);
  }
*************** struct cfg_hooks tree_cfg_hooks = {
*** 3958,3967 ****
    NULL,				/* create_basic_block  */
    tree_redirect_edge_and_branch,/* redirect_edge_and_branch  */
    tree_redirect_edge_and_branch_force,/* redirect_edge_and_branch_force  */
!   NULL,				/* delete_basic_block  */
    tree_split_block,		/* split_block  */
!   NULL,				/* can_merge_blocks_p  */
!   NULL,				/* merge_blocks  */
    tree_split_edge,		/* cfgh_split_edge  */
    tree_make_forwarder_block,	/* cfgh_make_forward_block  */
    tree_loop_optimizer_init,     /* cfgh_loop_optimizer_init  */
--- 4087,4096 ----
    NULL,				/* create_basic_block  */
    tree_redirect_edge_and_branch,/* redirect_edge_and_branch  */
    tree_redirect_edge_and_branch_force,/* redirect_edge_and_branch_force  */
!   remove_bb,			/* delete_basic_block  */
    tree_split_block,		/* split_block  */
!   tree_can_merge_blocks_p,	/* can_merge_blocks_p  */
!   tree_merge_blocks,		/* merge_blocks  */
    tree_split_edge,		/* cfgh_split_edge  */
    tree_make_forwarder_block,	/* cfgh_make_forward_block  */
    tree_loop_optimizer_init,     /* cfgh_loop_optimizer_init  */


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