[tree-ssa] kill more useless eh regions

Richard Henderson rth@twiddle.net
Fri Sep 19 10:56:00 GMT 2003


Doubly inlined c++ methods marked throw() have a nasty habit of 
turning out like

	try
	  {
	    <U1234>:
	  }
	catch
	  {
	    <<<eh_filter ()>>>
	      {
		__cxa_call_unexpected (<<<exception object>>>)
	      }
	  }

Since a label isn't IS_EMPTY_STMT, it wouldn't get cleaned up
with the rest of the refuse.  Looking at some of the less trivial
libstdc++ test cases, these tend to build up.  A lot.

It's pretty easy to clean this up in one pass...


r~


        * tree-cfg.c (struct rusv_data): Add may_throw, may_branch.
        (remove_useless_stmts_and_vars_1): Set them.
        (remove_useless_stmts_and_vars_goto): Likewise.
        (remove_useless_stmts_and_vars_tf): Transform to compound_expr
        if only fallthrough.
        (remove_useless_stmts_and_vars_tc): Kill region if nothrow.
        Detect catch regions that don't propagate exceptions.
        (remove_useless_stmts_and_vars): Zero entire data struct.

Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.167
diff -c -p -d -r1.1.4.167 tree-cfg.c
*** tree-cfg.c	18 Sep 2003 22:47:33 -0000	1.1.4.167
--- tree-cfg.c	19 Sep 2003 01:20:47 -0000
*************** struct rusv_data
*** 1155,1160 ****
--- 1155,1162 ----
  {
    bool repeat;
    bool remove_unused_vars;
+   bool may_throw;
+   bool may_branch;
  };
  
  static void remove_useless_stmts_and_vars_1 (tree *, struct rusv_data *);
*************** remove_useless_stmts_and_vars_cond (tree
*** 1228,1234 ****
--- 1230,1251 ----
  static void
  remove_useless_stmts_and_vars_tf (tree *stmt_p, struct rusv_data *data)
  {
+   bool save_may_branch, save_may_throw;
+   bool this_may_branch, this_may_throw;
+ 
+   /* Collect may_branch and may_throw information for the body only.  */
+   save_may_branch = data->may_branch;
+   save_may_throw = data->may_throw;
+   data->may_branch = false;
+   data->may_throw = false;
+ 
    remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 0), data);
+ 
+   this_may_branch = data->may_branch;
+   this_may_throw = data->may_throw;
+   data->may_branch |= save_may_branch;
+   data->may_throw |= save_may_throw;
+ 
    remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 1), data);
  
    /* If the body is empty, then we can emit the FINALLY block without
*************** remove_useless_stmts_and_vars_tf (tree *
*** 1246,1276 ****
        *stmt_p = TREE_OPERAND (*stmt_p, 0);
        data->repeat = true;
      }
  }
  
  static void
  remove_useless_stmts_and_vars_tc (tree *stmt_p, struct rusv_data *data)
  {
    remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 0), data);
  
!   /* If the body is empty, then we can throw away the
!      entire TRY_CATCH_EXPR.  */
!   if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 0)))
      {
!       *stmt_p = build_empty_stmt ();
        data->repeat = true;
        return;
      }
  
!   remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 1), data);
  
!   /* If the handler is empty, then we can emit the TRY block without
!      the enclosing TRY_CATCH_EXPR.  */
!   if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 1)))
      {
!       *stmt_p = TREE_OPERAND (*stmt_p, 0);
!       data->repeat = true;
      }
  }
  
  static void
--- 1263,1343 ----
        *stmt_p = TREE_OPERAND (*stmt_p, 0);
        data->repeat = true;
      }
+ 
+   /* If the body neither throws, nor branches, then we can safely string
+      the TRY and FINALLY blocks together.  We'll reassociate this in the
+      main body of remove_useless_stmts_and_vars.  */
+   else if (!this_may_branch && !this_may_throw)
+     TREE_SET_CODE (*stmt_p, COMPOUND_EXPR);
  }
  
  static void
  remove_useless_stmts_and_vars_tc (tree *stmt_p, struct rusv_data *data)
  {
+   bool save_may_throw, this_may_throw;
+   tree_stmt_iterator i;
+   tree stmt;
+ 
+   /* Collect may_throw information for the body only.  */
+   save_may_throw = data->may_throw;
+   data->may_throw = false;
+ 
    remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 0), data);
  
!   this_may_throw = data->may_throw;
!   data->may_throw = save_may_throw;
! 
!   /* If the body cannot throw, then we can drop the entire TRY_CATCH_EXPR.  */
!   if (!this_may_throw)
      {
!       *stmt_p = TREE_OPERAND (*stmt_p, 0);
        data->repeat = true;
        return;
      }
  
!   /* Process the catch clause specially.  We may be able to tell that
!      no exceptions propagate past this point.  */
  
!   this_may_throw = true;
!   i = tsi_start (&TREE_OPERAND (*stmt_p, 1));
!   stmt = tsi_stmt (i);
! 
!   switch (TREE_CODE (stmt))
      {
!     case CATCH_EXPR:
!       for (; !tsi_end_p (i); tsi_next (&i))
! 	{
! 	  stmt = tsi_stmt (i);
! 	  /* If we catch all exceptions, then the body does not
! 	     propagate exceptions past this point.  */
! 	  if (CATCH_TYPES (stmt) == NULL)
! 	    this_may_throw = false;
! 	  remove_useless_stmts_and_vars_1 (&CATCH_BODY (stmt), data);
! 	}
!       break;
! 
!     case EH_FILTER_EXPR:
!       if (EH_FILTER_MUST_NOT_THROW (stmt))
! 	this_may_throw = false;
!       else if (EH_FILTER_TYPES (stmt) == NULL)
! 	this_may_throw = false;
!       remove_useless_stmts_and_vars_1 (&EH_FILTER_FAILURE (stmt), data);
!       break;
! 
!     default:
!       /* Otherwise this is a cleanup.  */
!       remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 1), data);
! 
!       /* If the cleanup is empty, then we can emit the TRY block without
! 	 the enclosing TRY_CATCH_EXPR.  */
!       if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 1)))
! 	{
! 	  *stmt_p = TREE_OPERAND (*stmt_p, 0);
! 	  data->repeat = true;
! 	}
!       break;
      }
+   data->may_throw |= this_may_throw;
  }
  
  static void
*************** remove_useless_stmts_and_vars_goto (tree
*** 1386,1391 ****
--- 1453,1459 ----
  	{
  	  data->repeat = true;
  	  *stmt_p = build_empty_stmt ();
+ 	  return;
  	}
      }
    else
*************** remove_useless_stmts_and_vars_goto (tree
*** 1409,1417 ****
--- 1477,1488 ----
  	    {
  	      data->repeat = true;
  	      *stmt_p = build_empty_stmt ();
+ 	      return;
  	    }
  	}
      }
+ 
+   data->may_branch = true;
  }
  
  static void
*************** remove_useless_stmts_and_vars_1 (tree *f
*** 1448,1459 ****
  	case SWITCH_EXPR:
  	  remove_useless_stmts_and_vars_1 (&SWITCH_BODY (*stmt_p), data);
  	  break;
- 	case CATCH_EXPR:
- 	  remove_useless_stmts_and_vars_1 (&CATCH_BODY (*stmt_p), data);
- 	  break;
- 	case EH_FILTER_EXPR:
- 	  remove_useless_stmts_and_vars_1 (&EH_FILTER_FAILURE (*stmt_p), data);
- 	  break;
  	case TRY_FINALLY_EXPR:
  	  remove_useless_stmts_and_vars_tf (stmt_p, data);
  	  break;
--- 1519,1524 ----
*************** remove_useless_stmts_and_vars_1 (tree *f
*** 1466,1471 ****
--- 1531,1544 ----
  	case GOTO_EXPR:
  	  remove_useless_stmts_and_vars_goto (i, stmt_p, data);
  	  break;
+ 	case RETURN_EXPR:
+ 	  data->may_branch = true;
+ 	  break;
+ 	case MODIFY_EXPR:
+ 	case CALL_EXPR:
+ 	  if (tree_could_throw_p (*stmt_p))
+ 	    data->may_throw = true;
+ 	  break;
  	default:
  	  break;
  	}
*************** remove_useless_stmts_and_vars (tree *fir
*** 1484,1492 ****
    struct rusv_data data;
    do
      {
!       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);
--- 1557,1566 ----
    struct rusv_data data;
    do
      {
!       memset (&data, 0, sizeof (data));
        data.remove_unused_vars = remove_unused_vars;
        remove_unused_vars = false;
+ 
        remove_useless_stmts_and_vars_1 (first_p, &data);
      }
    while (data.repeat);



More information about the Gcc-patches mailing list