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] EH cleanup patch


This patch improves our handling of EH cleanups.  It can significantly
reduce the number of edges in the CFG in the presence of cleanups and
as a result can significantly speed up the tree-ssa optimizers.

Bootstrapped, regression tested i686-pc-linux-gnu.

[ Note there is a follow-up patch which removes a few more edges, but
  that is blocked behind an insert_insn_on_edge bug. ]

This is largely Jason's Merrill's work.  My contribution has been mostly
just analyzing and fixing latent bugs exposed by Jason's base patch.

        * except.c (enum eh_region_type): Don't declare the enumeration
        members here.  Instead do it in except.h.
        (expand_eh_hander): Use expr_first instead of open-coding it.
        * except.h (enum eh_region_type): Define the enumeration memebers
        here.
        * tree-cfg.c (last_exec_block): Break out from make_edges.
        (could_trap_p): No longer static.
        (get_eh_region_type): New function.
        (make_try_expr_blocks): Keep the whole TRY_CATCH_EXPR or
        TRY_FINALLY_EXPR instead of just the handler part in the
        EH_STACK varray.  For a cleanup, record which cleanup higher
        in the EH_STACK it can reach.
        (make_edges): Use last_exec_block.
        (make_ctrl_stmt_edges): Thread cleanups as needed.
        (compute_reachable_eh):  Use get_eh_region_type.  Properly
        track when we can skip cleanups.  Skip cleanups when possible.
        * tree-flow.h (could_trap_p): Prototype.

Index: except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.c,v
retrieving revision 1.227.2.12
diff -c -3 -p -r1.227.2.12 except.c
*** except.c	13 May 2003 02:16:31 -0000	1.227.2.12
--- except.c	17 Jun 2003 00:07:16 -0000
*************** struct eh_region GTY(())
*** 132,148 ****
    bitmap aka;
  
    /* Each region does exactly one thing.  */
!   enum eh_region_type
!   {
!     ERT_UNKNOWN = 0,
!     ERT_CLEANUP,
!     ERT_TRY,
!     ERT_CATCH,
!     ERT_ALLOWED_EXCEPTIONS,
!     ERT_MUST_NOT_THROW,
!     ERT_THROW,
!     ERT_FIXUP
!   } type;
  
    /* Holds the action to perform based on the preceding type.  */
    union eh_region_u {
--- 132,138 ----
    bitmap aka;
  
    /* Each region does exactly one thing.  */
!   enum eh_region_type type;
  
    /* Holds the action to perform based on the preceding type.  */
    union eh_region_u {
*************** void
*** 538,546 ****
  expand_eh_handler (handler)
       tree handler;
  {
!   tree inner = handler;
!   while (TREE_CODE (inner) == COMPOUND_EXPR)
!     inner = TREE_OPERAND (inner, 0);
  
    switch (TREE_CODE (inner))
      {
--- 528,534 ----
  expand_eh_handler (handler)
       tree handler;
  {
!   tree inner = expr_first (handler);
  
    switch (TREE_CODE (inner))
      {
Index: except.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.h,v
retrieving revision 1.64.2.6
diff -c -3 -p -r1.64.2.6 except.h
*** except.h	13 May 2003 02:16:31 -0000	1.64.2.6
--- except.h	17 Jun 2003 00:07:16 -0000
*************** struct eh_status;
*** 32,37 ****
--- 32,48 ----
  /* Internal structure describing a region.  */
  struct eh_region;
  
+ enum eh_region_type {
+   ERT_UNKNOWN = 0,
+   ERT_CLEANUP,
+   ERT_TRY,
+   ERT_CATCH,
+   ERT_ALLOWED_EXCEPTIONS,
+   ERT_MUST_NOT_THROW,
+   ERT_THROW,
+   ERT_FIXUP
+ };
+ 
  /* Test: is exception handling turned on?  */
  extern int doing_eh			        PARAMS ((int));
  
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.109
diff -c -3 -p -r1.1.4.109 tree-cfg.c
*** tree-cfg.c	16 Jun 2003 18:54:00 -0000	1.1.4.109
--- tree-cfg.c	17 Jun 2003 00:07:26 -0000
*************** static void make_case_label_edges (basic
*** 100,105 ****
--- 100,106 ----
  
  /* Various helpers.  */
  static basic_block successor_block (basic_block);
+ static basic_block last_exec_block (tree *);
  static tree *first_exec_stmt (tree *);
  static basic_block switch_parent (basic_block);
  static inline bool stmt_starts_bb_p (tree, tree);
*************** static inline bool stmt_ends_bb_p (tree)
*** 107,113 ****
  static void find_contained_blocks_and_edge_targets
  		(tree *, bitmap, bitmap, tree **);
  static void compute_reachable_eh (tree);
- static int could_trap_p (tree);
  
  /* Flowgraph optimization and cleanup.  */
  static void remove_unreachable_blocks (void);
--- 108,113 ----
*************** static void replace_stmt (tree *, tree *
*** 131,136 ****
--- 131,137 ----
  static void merge_tree_blocks (basic_block, basic_block);
  static bool remap_stmts (basic_block, basic_block, tree *);
  static tree *handle_switch_split (basic_block, basic_block);
+ static enum eh_region_type get_eh_region_type (tree);
  
  /* Block iterator helpers.  */
  
*************** make_blocks (tree *first_p, tree next_bl
*** 439,445 ****
  /* Return 1 if the expr can trap, as in dereferencing an
     invalid pointer location.  */
  
! static int
  could_trap_p (tree expr)
  {
    return (TREE_CODE (expr) == INDIRECT_REF
--- 440,446 ----
  /* Return 1 if the expr can trap, as in dereferencing an
     invalid pointer location.  */
  
! int
  could_trap_p (tree expr)
  {
    return (TREE_CODE (expr) == INDIRECT_REF
*************** make_cond_expr_blocks (tree *cond_p, tre
*** 528,533 ****
--- 529,553 ----
    make_blocks (&COND_EXPR_ELSE (cond), next_block_link, cond, NULL);
  }
  
+ /* Derive an exception handling region type from STMT.  */
+ 
+ static enum eh_region_type
+ get_eh_region_type (tree stmt)
+ {
+   if (TREE_CODE (stmt) == TRY_FINALLY_EXPR)
+     return ERT_CLEANUP;
+   if (TREE_CODE (stmt) == TRY_CATCH_EXPR)
+     {
+       tree handler = TREE_OPERAND (stmt, 1);
+       if (TREE_CODE (expr_first (handler)) == CATCH_EXPR)
+ 	return ERT_TRY;
+       if (TREE_CODE (handler) == EH_FILTER_EXPR)
+ 	return ERT_ALLOWED_EXCEPTIONS;
+       return ERT_CLEANUP;
+     }
+   abort ();
+ }
+ 
  /* Create the blocks for the TRY_CATCH_EXPR or TRY_FINALLY_EXPR node
     pointed by expr_p.  */
  
*************** make_try_expr_blocks (tree *expr_p, tree
*** 552,561 ****
  
    STRIP_CONTAINERS (expr);
  
!   /* We need to keep a stack of the handler expressions of TRY_CATCH_EXPR
!      and TRY_FINALLY nodes so that we know when throwing statements should
!      end a basic block.  */
!   VARRAY_PUSH_TREE (eh_stack, TREE_OPERAND (expr, 1));
  
    /* Make blocks for the TRY block.  */
    make_blocks (&TREE_OPERAND (expr, 0), next_block_link, expr, NULL);
--- 572,580 ----
  
    STRIP_CONTAINERS (expr);
  
!   /* We need to keep a stack of the TRY_CATCH_EXPR and TRY_FINALLY nodes
!      so that we know when throwing statements should end a basic block.  */
!   VARRAY_PUSH_TREE (eh_stack, expr);
  
    /* Make blocks for the TRY block.  */
    make_blocks (&TREE_OPERAND (expr, 0), next_block_link, expr, NULL);
*************** make_try_expr_blocks (tree *expr_p, tree
*** 565,570 ****
--- 584,599 ----
  
    /* Make blocks for the handler itself.  */
    make_blocks (&TREE_OPERAND (expr, 1), next_block_link, expr, NULL);
+ 
+   /* If this is a cleanup, then record which cleanup higher in the
+      stack it can directly reach.  */
+   if (get_eh_region_type (expr) == ERT_CLEANUP
+       && VARRAY_ACTIVE_SIZE (eh_stack))
+     {
+       tree region = VARRAY_TOP_TREE (eh_stack);
+       if (get_eh_region_type (region) == ERT_CLEANUP)
+ 	stmt_ann (expr)->reachable_exception_handlers = TREE_OPERAND (region, 1);
+     }
  }
  
  /* Create the blocks for the CATCH_EXPR node pointed to by expr_p.  */
*************** make_edges (void)
*** 865,871 ****
        int bb;
        bitmap try_blocks = BITMAP_XMALLOC ();
        bitmap try_targets = BITMAP_XMALLOC ();
-       bitmap dummy_bitmap = BITMAP_XMALLOC ();
  
        /* Get bitmaps for the basic blocks within the TRY block as
  	 well as bitmap for the blocks which the TRY block can
--- 894,899 ----
*************** make_edges (void)
*** 897,913 ****
        /* We need to know the last statement in the FINALLY so that
  	 we know where to wire up the additional outgoing edges from
  	 the FINALLY block.  */
!       finally_last_p = NULL;
!       find_contained_blocks_and_edge_targets (&TREE_OPERAND (try_finally, 1),
! 		      			      dummy_bitmap,
! 					      dummy_bitmap,
! 					      &finally_last_p);
! 
!       last_bb = bb_for_stmt (*finally_last_p);
  
        /* Find edges which exited the TRY block.  For each of those
  	 edges, we want to create a new edge from the FINALLY block
! 	 to the destination of the edge out of the TRY block.  */
        if (last_bb)
  	EXECUTE_IF_AND_COMPL_IN_BITMAP (try_targets, try_blocks, 0, bb,
  	  {
--- 925,941 ----
        /* We need to know the last statement in the FINALLY so that
  	 we know where to wire up the additional outgoing edges from
  	 the FINALLY block.  */
!       last_bb = last_exec_block (&TREE_OPERAND (try_finally, 1));
  
        /* Find edges which exited the TRY block.  For each of those
  	 edges, we want to create a new edge from the FINALLY block
! 	 to the destination of the edge out of the TRY block.
! 
! 	 Note that we need to create the edges as abnormal edges until
! 	 such time as these transfers of control appear more directly
! 	 in the tree nodes.  Otherwise out of SSA may try to insert
! 	 a copy of one of these edges and we do not know how to
! 	 actually perform such as insertion.  */
        if (last_bb)
  	EXECUTE_IF_AND_COMPL_IN_BITMAP (try_targets, try_blocks, 0, bb,
  	  {
*************** make_edges (void)
*** 923,929 ****
  	      make_edge (last_bb, b, EDGE_ABNORMAL);
  	  });
  
-       BITMAP_XFREE (dummy_bitmap);
        BITMAP_XFREE (try_targets);
        BITMAP_XFREE (try_blocks);
      }
--- 951,956 ----
*************** make_ctrl_stmt_edges (basic_block bb)
*** 1087,1092 ****
--- 1114,1128 ----
      case TRY_CATCH_EXPR:
        make_edge (bb, bb_for_stmt (TREE_OPERAND (last, 0)), EDGE_FALLTHRU);
        make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
+ 
+       /* Make an edge to the next cleanup if applicable.  */
+       if (stmt_ann (last)->reachable_exception_handlers)
+ 	{
+ 	  tree handler  = stmt_ann (last)->reachable_exception_handlers;
+ 	  basic_block target_bb = last_exec_block (&TREE_OPERAND (last, 1));
+ 	  make_edge (target_bb, bb_for_stmt (handler), 0);
+ 	}
+ 
        break;
  
      case CATCH_EXPR:
*************** first_stmt (basic_block bb)
*** 2929,2934 ****
--- 2965,2985 ----
    return (!bsi_end_p (i)) ? bsi_stmt (i) : NULL_TREE;
  }
  
+ /* Return the last basic block with executable statements in it, starting
+    at ENTRY_P.  */
+ 
+ static basic_block
+ last_exec_block (entry_p)
+      tree *entry_p;
+ {
+   bitmap dummy_bitmap = BITMAP_XMALLOC ();
+   tree *last_p = NULL;
+   find_contained_blocks_and_edge_targets (entry_p, dummy_bitmap, 
dummy_bitmap,
+ 					  &last_p);
+   BITMAP_XFREE (dummy_bitmap);
+   return bb_for_stmt (*last_p);
+ }
+ 
  
  /* Return the last statement in basic block BB, stripped of any NOP
     containers.
*************** compute_reachable_eh (tree stmt)
*** 4361,4374 ****
       on a list and added to the statement's annotation.  */
    for (i = VARRAY_ACTIVE_SIZE (eh_stack) - 1; i >= 0; i--)
      {
!       tree handler = VARRAY_TREE (eh_stack, i);
!       tree tp_node;
  
!       if (TREE_CODE (handler) == CATCH_EXPR
! 	  || (TREE_CODE (handler) == COMPOUND_EXPR
! 	      && TREE_CODE (TREE_OPERAND (handler, 0)) == CATCH_EXPR))
  	{
! 	  for (si = tsi_start (&handler); !tsi_end_p (si); tsi_next (&si))
  	    {
  	      tree types;
  
--- 4412,4425 ----
       on a list and added to the statement's annotation.  */
    for (i = VARRAY_ACTIVE_SIZE (eh_stack) - 1; i >= 0; i--)
      {
!       tree region = VARRAY_TREE (eh_stack, i);
!       tree handler, tp_node;
  
!       switch (get_eh_region_type (region))
  	{
! 	case ERT_TRY:
! 	  for (si = tsi_start (&TREE_OPERAND (region, 1));
! 	       !tsi_end_p (si); tsi_next (&si))
  	    {
  	      tree types;
  
*************** compute_reachable_eh (tree stmt)
*** 4408,4419 ****
  				     reachable_handlers);
  		    }
  		}
- 
- 	      skip_cleanups = 0;
  	    }
! 	}
!       else if (TREE_CODE (handler) == EH_FILTER_EXPR)
! 	{
  	  /* This is an exception specification.  If it has
  	     no types, then it ends our search.  */
  	  if (EH_FILTER_TYPES (handler) == NULL_TREE)
--- 4459,4472 ----
  				     reachable_handlers);
  		    }
  		}
  	    }
! 
! 	  skip_cleanups = 0;
! 	  break;
! 	  
! 	case ERT_ALLOWED_EXCEPTIONS:
! 	  handler = TREE_OPERAND (region, 1);
! 
  	  /* This is an exception specification.  If it has
  	     no types, then it ends our search.  */
  	  if (EH_FILTER_TYPES (handler) == NULL_TREE)
*************** compute_reachable_eh (tree stmt)
*** 4432,4451 ****
  					  reachable_handlers);
  
  	  skip_cleanups = 0;
! 	}
!       else if (!skip_cleanups)
! 	{
  	  /* This is a cleanup and is reachable.  It does not
  	     stop our search; however, we can skip other
  	     cleanups until we run into something else.  */
  	  reachable_handlers = tree_cons (void_type_node,
  					  handler,
  					  reachable_handlers);
- #if 0
- 	  /* Actually, we can't.  At least not until we build edges from
- 	     one cleanup to the next.  */
  	  skip_cleanups = 1;
! #endif
  	}
      }
  
--- 4485,4509 ----
  					  reachable_handlers);
  
  	  skip_cleanups = 0;
! 	  break;
! 
! 	case ERT_CLEANUP:
! 	  if (skip_cleanups)
! 	    break;
! 
! 	  handler = TREE_OPERAND (region, 1);
! 
  	  /* This is a cleanup and is reachable.  It does not
  	     stop our search; however, we can skip other
  	     cleanups until we run into something else.  */
  	  reachable_handlers = tree_cons (void_type_node,
  					  handler,
  					  reachable_handlers);
  	  skip_cleanups = 1;
! 	  break;
! 
! 	default:
! 	  abort ();
  	}
      }
  
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.84
diff -c -3 -p -r1.1.4.84 tree-flow.h
*** tree-flow.h	16 Jun 2003 18:54:00 -0000	1.1.4.84
--- tree-flow.h	17 Jun 2003 00:07:28 -0000
*************** extern basic_block is_latch_block_for (b
*** 427,432 ****
--- 427,433 ----
  extern edge find_taken_edge (basic_block, tree);
  extern int call_expr_flags (tree);
  extern int remove_useless_stmts_and_vars (tree *);
+ extern int could_trap_p (tree);
  
  /* In tree-dfa.c  */
  extern void get_stmt_operands (tree);






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