diff gcc/tree-eh.c @ 63:b7f97abdc517 gcc-4.6-20100522

update gcc from gcc-4.5.0 to gcc-4.6
author ryoma <e075725@ie.u-ryukyu.ac.jp>
date Mon, 24 May 2010 12:47:05 +0900
parents 77e2b8dfacca
children f6334be47118
line wrap: on
line diff
--- a/gcc/tree-eh.c	Fri Feb 12 23:41:23 2010 +0900
+++ b/gcc/tree-eh.c	Mon May 24 12:47:05 2010 +0900
@@ -1,5 +1,5 @@
 /* Exception handling semantics and decomposition for trees.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -23,11 +23,10 @@
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "rtl.h"
-#include "tm_p.h"
 #include "flags.h"
 #include "function.h"
 #include "except.h"
+#include "pointer-set.h"
 #include "tree-flow.h"
 #include "tree-dump.h"
 #include "tree-inline.h"
@@ -563,6 +562,7 @@
   if (tf->goto_queue_active == 0)
     return;
   replace_goto_queue_stmt_list (tf->top_p_seq, tf);
+  replace_goto_queue_stmt_list (eh_seq, tf);
 }
 
 /* Add a new record to the goto queue contained in TF. NEW_STMT is the
@@ -643,7 +643,6 @@
      labels. */
   new_stmt = stmt;
   record_in_goto_queue (tf, new_stmt, index, true);
-
 }
 
 /* For any GIMPLE_GOTO or GIMPLE_RETURN, decide whether it leaves a try_finally
@@ -1518,6 +1517,20 @@
     return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3;
 }
 
+/* REG is the enclosing region for a possible cleanup region, or the region
+   itself.  Returns TRUE if such a region would be unreachable.
+
+   Cleanup regions within a must-not-throw region aren't actually reachable
+   even if there are throwing stmts within them, because the personality
+   routine will call terminate before unwinding.  */
+
+static bool
+cleanup_is_dead_in (eh_region reg)
+{
+  while (reg && reg->type == ERT_CLEANUP)
+    reg = reg->outer;
+  return (reg && reg->type == ERT_MUST_NOT_THROW);
+}
 
 /* A subroutine of lower_eh_constructs_1.  Lower a GIMPLE_TRY_FINALLY nodes
    to a sequence of labels and blocks, plus the exception region trees
@@ -1530,6 +1543,7 @@
   struct leh_tf_state this_tf;
   struct leh_state this_state;
   int ndests;
+  gimple_seq old_eh_seq;
 
   /* Process the try block.  */
 
@@ -1537,22 +1551,30 @@
   this_tf.try_finally_expr = tp;
   this_tf.top_p = tp;
   this_tf.outer = state;
-  if (using_eh_for_cleanups_p)
-    this_tf.region = gen_eh_region_cleanup (state->cur_region);
+  if (using_eh_for_cleanups_p && !cleanup_is_dead_in (state->cur_region))
+    {
+      this_tf.region = gen_eh_region_cleanup (state->cur_region);
+      this_state.cur_region = this_tf.region;
+    }
   else
-    this_tf.region = NULL;
-
-  this_state.cur_region = this_tf.region;
+    {
+      this_tf.region = NULL;
+      this_state.cur_region = state->cur_region;
+    }
+
   this_state.ehp_region = state->ehp_region;
   this_state.tf = &this_tf;
 
+  old_eh_seq = eh_seq;
+  eh_seq = NULL;
+
   lower_eh_constructs_1 (&this_state, gimple_try_eval(tp));
 
   /* Determine if the try block is escaped through the bottom.  */
   this_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp));
 
   /* Determine if any exceptions are possible within the try block.  */
-  if (using_eh_for_cleanups_p)
+  if (this_tf.region)
     this_tf.may_throw = eh_region_may_contain_throw (this_tf.region);
   if (this_tf.may_throw)
     honor_protect_cleanup_actions (state, &this_state, &this_tf);
@@ -1601,6 +1623,20 @@
   if (this_tf.goto_queue_map)
     pointer_map_destroy (this_tf.goto_queue_map);
 
+  /* If there was an old (aka outer) eh_seq, append the current eh_seq.
+     If there was no old eh_seq, then the append is trivially already done.  */
+  if (old_eh_seq)
+    {
+      if (eh_seq == NULL)
+	eh_seq = old_eh_seq;
+      else
+	{
+	  gimple_seq new_eh_seq = eh_seq;
+	  eh_seq = old_eh_seq;
+	  gimple_seq_add_seq(&eh_seq, new_eh_seq);
+	}
+    }
+
   return this_tf.top_p_seq;
 }
 
@@ -1762,8 +1798,9 @@
   eh_region this_region = NULL;
   struct leh_tf_state fake_tf;
   gimple_seq result;
-
-  if (flag_exceptions)
+  bool cleanup_dead = cleanup_is_dead_in (state->cur_region);
+
+  if (flag_exceptions && !cleanup_dead)
     {
       this_region = gen_eh_region_cleanup (state->cur_region);
       this_state.cur_region = this_region;
@@ -1771,7 +1808,7 @@
 
   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
 
-  if (!eh_region_may_contain_throw (this_region))
+  if (cleanup_dead || !eh_region_may_contain_throw (this_region))
     return gimple_try_eval (tp);
 
   /* Build enough of a try-finally state so that we can reuse
@@ -3038,9 +3075,10 @@
 };
 
 
-/* At the end of inlining, we can lower EH_DISPATCH.  */
-
-static void
+/* At the end of inlining, we can lower EH_DISPATCH.  Return true when 
+   we have found some duplicate labels and removed some edges.  */
+
+static bool
 lower_eh_dispatch (basic_block src, gimple stmt)
 {
   gimple_stmt_iterator gsi;
@@ -3048,6 +3086,7 @@
   eh_region r;
   tree filter, fn;
   gimple x;
+  bool redirected = false;
 
   region_nr = gimple_eh_dispatch_region (stmt);
   r = get_eh_region_from_number (region_nr);
@@ -3063,6 +3102,7 @@
 	eh_catch c;
 	edge_iterator ei;
 	edge e;
+	struct pointer_set_t *seen_values = pointer_set_create ();
 
 	/* Collect the labels for a switch.  Zero the post_landing_pad
 	   field becase we'll no longer have anything keeping these labels
@@ -3071,6 +3111,7 @@
 	for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
 	  {
 	    tree tp_node, flt_node, lab = c->label;
+	    bool have_label = false;
 
 	    c->label = NULL;
 	    tp_node = c->type_list;
@@ -3083,14 +3124,29 @@
 	      }
 	    do
 	      {
-		tree t = build3 (CASE_LABEL_EXPR, void_type_node,
-				 TREE_VALUE (flt_node), NULL, lab);
-		VEC_safe_push (tree, heap, labels, t);
+		/* Filter out duplicate labels that arise when this handler 
+		   is shadowed by an earlier one.  When no labels are 
+		   attached to the handler anymore, we remove 
+		   the corresponding edge and then we delete unreachable 
+		   blocks at the end of this pass.  */
+		if (! pointer_set_contains (seen_values, TREE_VALUE (flt_node)))
+		  {
+		    tree t = build3 (CASE_LABEL_EXPR, void_type_node,
+				     TREE_VALUE (flt_node), NULL, lab);
+		    VEC_safe_push (tree, heap, labels, t);
+		    pointer_set_insert (seen_values, TREE_VALUE (flt_node));
+		    have_label = true;
+		  }
 
 		tp_node = TREE_CHAIN (tp_node);
 		flt_node = TREE_CHAIN (flt_node);
 	      }
 	    while (tp_node);
+	    if (! have_label)
+	      {
+	        remove_edge (find_edge (src, label_to_block (lab)));
+	        redirected = true;
+	      }
 	  }
 
 	/* Clean up the edge flags.  */
@@ -3132,6 +3188,7 @@
 
 	    VEC_free (tree, heap, labels);
 	  }
+	pointer_set_destroy (seen_values);
       }
       break;
 
@@ -3165,6 +3222,7 @@
 
   /* Replace the EH_DISPATCH with the SWITCH or COND generated above.  */
   gsi_remove (&gsi, true);
+  return redirected;
 }
 
 static unsigned
@@ -3172,6 +3230,7 @@
 {
   basic_block bb;
   bool any_rewritten = false;
+  bool redirected = false;
 
   assign_filter_values ();
 
@@ -3180,11 +3239,13 @@
       gimple last = last_stmt (bb);
       if (last && gimple_code (last) == GIMPLE_EH_DISPATCH)
 	{
-	  lower_eh_dispatch (bb, last);
+	  redirected |= lower_eh_dispatch (bb, last);
 	  any_rewritten = true;
 	}
     }
 
+  if (redirected)
+    delete_unreachable_blocks ();
   return any_rewritten ? TODO_update_ssa_only_virtuals : 0;
 }
 
@@ -3350,8 +3411,11 @@
   if ((e_in->flags & EDGE_EH) == 0 || (e_out->flags & EDGE_EH) != 0)
     return false;
 
-  /* The block must be empty except for the labels.  */
-  if (!gsi_end_p (gsi_after_labels (bb)))
+  /* The block must be empty except for the labels and debug insns.  */
+  gsi = gsi_after_labels (bb);
+  if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
+    gsi_next_nondebug (&gsi);
+  if (!gsi_end_p (gsi))
     return false;
 
   /* The destination block must not already have a landing pad