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] PATCH to tree-cfg.c to check TREE_NOTHROW


While looking at other tree-cfg.c problems, I noticed that we were ending a
block on a call to printf.  This shouldn't happen, as we know that printf
can't throw.  So I've added checks for TREE_NOTHROW in the appropriate
places.

Tested athlon-pc-linux-gnu, applied to tree-ssa.  Test in
g++.dg/opt/nothrow1.C.

2003-09-10  Jason Merrill  <jason@redhat.com>

	* tree-cfg.c (make_call_expr_edges): Break out from...
	(make_exit_edges): ...here.  Check TREE_NOTHROW.
	(is_ctrl_altering_stmt): Check TREE_NOTHROW.

*** tree-cfg.c.~1~	2003-09-10 05:49:28.000000000 +0000
--- tree-cfg.c	2003-09-10 20:23:12.000000000 +0000
*************** static inline void set_parent_stmt (tree
*** 100,105 ****
--- 100,106 ----
  static void make_edges (void);
  static void make_ctrl_stmt_edges (basic_block);
  static void make_exit_edges (basic_block);
+ static void make_call_expr_edges (basic_block, tree, tree);
  static void make_cond_expr_edges (basic_block);
  static void make_goto_expr_edges (basic_block);
  static void make_case_label_edges (basic_block);
*************** make_blocks (tree *first_p, tree next_bl
*** 508,515 ****
          {
  	  start_new_block = true;
  
- 	  /* Right now we only model exceptions which occur via calls.
- 	    This will need to be generalized in the future.  */
  	  if (TREE_CODE (stmt) == CALL_EXPR
  	      || (TREE_CODE (stmt) == MODIFY_EXPR
  		  && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
--- 509,514 ----
*************** make_ctrl_stmt_edges (basic_block bb)
*** 1167,1172 ****
--- 1166,1212 ----
      }
  }
  
+ /* A CALL_EXPR node here means that the last statement of the block
+    is a call to a non-returning function or a call that may throw.  */
+ 
+ static void
+ make_call_expr_edges (basic_block bb, tree call, tree stmt)
+ {
+   /* If this function receives a nonlocal goto, then we need to
+      make edges from this call site to all the nonlocal goto
+      handlers.  */
+   if (FUNCTION_RECEIVES_NONLOCAL_GOTO (current_function_decl))
+     make_goto_expr_edges (bb);
+ 
+   /* If this statement has reachable exception handlers, then
+      create abnormal edges to them.  */
+   if (stmt_ann (stmt)->reachable_exception_handlers
+       && !TREE_NOTHROW (call))
+     {
+       tree t;
+ 
+       for (t = stmt_ann (stmt)->reachable_exception_handlers;
+ 	   t;
+ 	   t = TREE_CHAIN (t))
+ 	make_edge (bb, bb_for_stmt (TREE_VALUE (t)), EDGE_ABNORMAL);
+     }
+ 
+   /* Some calls are known not to return.  For such calls we create
+      a fake edge.
+ 
+      We really need to revamp how we build edges so that it's not
+      such a bloody pain to avoid creating edges for this case since
+      all we do is remove these edges when we're done building the
+      CFG.  */
+   if (call_expr_flags (call) & (ECF_NORETURN | ECF_LONGJMP))
+     {
+       make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
+       return;
+     }
+ 
+   /* Don't forget the fall-thru edge.  */
+   make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
+ }
  
  /* Create exit edges for statements in block BB that alter the flow of
     control.  Statements that alter the control flow are 'goto', 'return'
*************** make_exit_edges (basic_block bb)
*** 1195,1236 ****
  	make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
        break;
  
-       /* A CALL_EXPR node here means that the last statement of the block
- 	 is a call to a non-returning function or a call that may throw.  */
      case CALL_EXPR:
!       /* If this function receives a nonlocal goto, then we need to
! 	 make edges from this call site to all the nonlocal goto
! 	 handlers.  */
!       if (FUNCTION_RECEIVES_NONLOCAL_GOTO (current_function_decl))
! 	make_goto_expr_edges (bb);
! 
!       /* If this statement has reachable exception handlers, then
! 	 create abnormal edges to them.  */
!       if (stmt_ann (last)->reachable_exception_handlers)
! 	{
! 	  tree t;
! 
! 	  for (t = stmt_ann (last)->reachable_exception_handlers;
! 	       t;
! 	       t = TREE_CHAIN (t))
! 	    make_edge (bb, bb_for_stmt (TREE_VALUE (t)), EDGE_ABNORMAL);
! 	}
! 
!       /* Some calls are known not to return.  For such calls we create
! 	 a fake edge.
! 
! 	 We really need to revamp how we build edges so that it's not
! 	 such a bloody pain to avoid creating edges for this case since
! 	 all we do is remove these edges when we're done building the
! 	 CFG.  */
!       if (call_expr_flags (last) & (ECF_NORETURN | ECF_LONGJMP))
! 	{
! 	  make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
! 	  return;
! 	}
! 
!       /* Don't forget the fall-thru edge.  */
!       make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
        break;
  
      case RETURN_EXPR:
--- 1235,1242 ----
  	make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
        break;
  
      case CALL_EXPR:
!       make_call_expr_edges (bb, last, last);
        break;
  
      case RETURN_EXPR:
*************** make_exit_edges (basic_block bb)
*** 1242,1265 ****
  	 may have an abnormal edge.  Search the RHS for this case and
  	 create any required edges.  */
        if (TREE_CODE (TREE_OPERAND (last, 1)) == CALL_EXPR)
! 	{
! 	  if (FUNCTION_RECEIVES_NONLOCAL_GOTO (current_function_decl))
! 	    make_goto_expr_edges (bb);
! 
! 	  if (stmt_ann (last)->reachable_exception_handlers)
! 	    {
! 	      tree t;
  
- 	      for (t = stmt_ann (last)->reachable_exception_handlers;
- 		   t;
- 		   t = TREE_CHAIN (t))
- 		make_edge (bb,
- 			   bb_for_stmt (TREE_VALUE (t)),
- 			   EDGE_ABNORMAL);
- 	    }
- 
-           make_edge (bb, successor_block (bb), 0);
- 	}
        if (flag_non_call_exceptions
  	  && (could_trap_p (TREE_OPERAND (last, 0))
  	      || could_trap_p (TREE_OPERAND (last, 1))))
--- 1248,1255 ----
  	 may have an abnormal edge.  Search the RHS for this case and
  	 create any required edges.  */
        if (TREE_CODE (TREE_OPERAND (last, 1)) == CALL_EXPR)
! 	make_call_expr_edges (bb, TREE_OPERAND (last, 1), last);
  
        if (flag_non_call_exceptions
  	  && (could_trap_p (TREE_OPERAND (last, 0))
  	      || could_trap_p (TREE_OPERAND (last, 1))))
*************** is_ctrl_altering_stmt (tree t)
*** 3049,3054 ****
--- 3039,3045 ----
  
    /* A CALL_EXPR also alters flow control if it may throw.  */
    if (code == CALL_EXPR
+       && !TREE_NOTHROW (t)
        && (VARRAY_ACTIVE_SIZE (eh_stack) > 0
  	  || stmt_ann (t)->reachable_exception_handlers))
      return true;
*************** is_ctrl_altering_stmt (tree t)
*** 3057,3062 ****
--- 3048,3054 ----
       an abnormal edge if the current function has nonlocal labels.  */
    if (code == MODIFY_EXPR
        && TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR
+       && !TREE_NOTHROW (TREE_OPERAND (t, 1))
        && (FUNCTION_RECEIVES_NONLOCAL_GOTO (current_function_decl)
            || VARRAY_ACTIVE_SIZE (eh_stack) > 0
  	  || stmt_ann (t)->reachable_exception_handlers))
// Test that the nothrow optimization works properly.
// { dg-do compile }
// { dg-options "-O -fdump-tree-optimized" }

extern "C" int printf (const char *, ...);

int i, j, k;

int main()
{
  try
    {
      ++i;
      printf ("foo\n");
      ++j;
    }
  catch (...)
    {
      return 42;
    }
}

// The catch block should be optimized away.
// { dg-final { scan-tree-dump-times "42" 0 "optimized" } }

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