public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [trans-mem] EH merge vs GIMPLE_EH_ELSE
@ 2009-10-20 18:44 Richard Henderson
  0 siblings, 0 replies; only message in thread
From: Richard Henderson @ 2009-10-20 18:44 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 113 bytes --]

I somehow dropped half the support for GIMPLE_EH_ELSE when I merged the 
new EH code onto the branch.  Duh.


r~

[-- Attachment #2: z --]
[-- Type: text/plain, Size: 12034 bytes --]

        * gimple-pretty-print.c (dump_gimple_eh_else): Tidy.
        * tree-cfg.c (verify_types_in_gimple_seq_2): Handle GIMPLE_EH_ELSE.
        * tree-eh.c: Restore EH_ELSE from before merge.


diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 6c49b39..d6a2f25 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -855,7 +855,7 @@ dump_gimple_eh_else (pretty_printer *buffer, gimple gs, int spc, int flags)
                      gimple_eh_else_n_body (gs), gimple_eh_else_e_body (gs));
   else
     dump_gimple_fmt (buffer, spc, flags,
-                    "IF_NORMAL_EXIT%+{%S}%-ELSE_EH_EXIT%+{%S}",
+                    "<<<if_normal_exit>>>%+{%S}%-<<<else_eh_exit>>>%+{%S}",
                      gimple_eh_else_n_body (gs), gimple_eh_else_e_body (gs));
 }
 
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index acac3f0..43122cd 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -3854,6 +3854,11 @@ verify_types_in_gimple_seq_2 (gimple_seq stmts)
 	  err |= verify_types_in_gimple_seq_2 (gimple_eh_filter_failure (stmt));
 	  break;
 
+	case GIMPLE_EH_ELSE:
+	  err |= verify_types_in_gimple_seq_2 (gimple_eh_else_n_body (stmt));
+	  err |= verify_types_in_gimple_seq_2 (gimple_eh_else_e_body (stmt));
+	  break;
+
 	case GIMPLE_CATCH:
 	  err |= verify_types_in_gimple_seq_2 (gimple_catch_handler (stmt));
 	  break;
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index c0ea8d3..62e0942 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -300,6 +300,11 @@ collect_finally_tree (gimple stmt, gimple region)
       collect_finally_tree_1 (gimple_eh_filter_failure (stmt), region);
       break;
 
+    case GIMPLE_EH_ELSE:
+      collect_finally_tree_1 (gimple_eh_else_n_body (stmt), region);
+      collect_finally_tree_1 (gimple_eh_else_e_body (stmt), region);
+      break;
+
     default:
       /* A type, a decl, or some kind of statement that we're not
 	 interested in.  Don't walk them.  */
@@ -550,6 +555,10 @@ replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf,
     case GIMPLE_EH_FILTER:
       replace_goto_queue_stmt_list (gimple_eh_filter_failure (stmt), tf);
       break;
+    case GIMPLE_EH_ELSE:
+      replace_goto_queue_stmt_list (gimple_eh_else_n_body (stmt), tf);
+      replace_goto_queue_stmt_list (gimple_eh_else_e_body (stmt), tf);
+      break;
 
     default:
       /* These won't have gotos in them.  */
@@ -958,6 +967,21 @@ lower_try_finally_fallthru_label (struct leh_tf_state *tf)
   return label;
 }
 
+/* A subroutine of lower_try_finally.  If FINALLY consits of a
+   GIMPLE_EH_ELSE node, return it.  */
+
+static inline gimple
+get_eh_else (gimple_seq finally)
+{
+  gimple x = gimple_seq_first_stmt (finally);
+  if (gimple_code (x) == GIMPLE_EH_ELSE)
+    {
+      gcc_assert (gimple_seq_singleton_p (finally));
+      return x;
+    }
+  return NULL;
+}
+
 /* A subroutine of lower_try_finally.  If lang_protect_cleanup_actions
    returns non-null, then the language requires that the exception path out
    of a try_finally be treated specially.  To wit: the code within the
@@ -987,7 +1011,7 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
   gimple_stmt_iterator gsi;
   bool finally_may_fallthru;
   gimple_seq finally;
-  gimple x;
+  gimple x, eh_else;
 
   /* First check for nothing to do.  */
   if (lang_protect_cleanup_actions == NULL)
@@ -997,12 +1021,18 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
     return;
 
   finally = gimple_try_cleanup (tf->top_p);
-  finally_may_fallthru = gimple_seq_may_fallthru (finally);
+  eh_else = get_eh_else (finally);
 
   /* Duplicate the FINALLY block.  Only need to do this for try-finally,
-     and not for cleanups.  */
-  if (this_state)
+     and not for cleanups.  If we've got an EH_ELSE, extract it now.  */
+  if (eh_else)
+    {
+      finally = gimple_eh_else_e_body (eh_else);
+      gimple_try_set_cleanup (tf->top_p, gimple_eh_else_n_body (eh_else));
+    }
+  else if (this_state)
     finally = lower_try_finally_dup_block (finally, outer_state);
+  finally_may_fallthru = gimple_seq_may_fallthru (finally);
 
   /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP
      set, the handler of the TRY_CATCH_EXPR is another cleanup which ought
@@ -1048,7 +1078,7 @@ lower_try_finally_nofallthru (struct leh_state *state,
 			      struct leh_tf_state *tf)
 {
   tree lab, return_val;
-  gimple x;
+  gimple x, eh_else;
   gimple_seq finally;
   struct goto_queue_node *q, *qe;
 
@@ -1072,15 +1102,35 @@ lower_try_finally_nofallthru (struct leh_state *state,
 
   replace_goto_queue (tf);
 
-  lower_eh_constructs_1 (state, finally);
-  gimple_seq_add_seq (&tf->top_p_seq, finally);
+  /* Emit the finally block into the stream.  Lower EH_ELSE at this time.  */
+  eh_else = get_eh_else (finally);
+  if (eh_else)
+    {
+      finally = gimple_eh_else_n_body (eh_else);
+      lower_eh_constructs_1 (state, finally);
+      gimple_seq_add_seq (&tf->top_p_seq, finally);
 
-  if (tf->may_throw)
+      if (tf->may_throw)
+	{
+	  finally = gimple_eh_else_e_body (eh_else);
+	  lower_eh_constructs_1 (state, finally);
+
+	  emit_post_landing_pad (&eh_seq, tf->region);
+	  gimple_seq_add_seq (&eh_seq, finally);
+	}
+    }
+  else
     {
-      emit_post_landing_pad (&eh_seq, tf->region);
+      lower_eh_constructs_1 (state, finally);
+      gimple_seq_add_seq (&tf->top_p_seq, finally);
 
-      x = gimple_build_goto (lab);
-      gimple_seq_add_stmt (&eh_seq, x);
+      if (tf->may_throw)
+	{
+	  emit_post_landing_pad (&eh_seq, tf->region);
+
+	  x = gimple_build_goto (lab);
+	  gimple_seq_add_stmt (&eh_seq, x);
+	}
     }
 }
 
@@ -1100,6 +1150,18 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
   finally = gimple_try_cleanup (tf->top_p);
   tf->top_p_seq = gimple_try_eval (tf->top_p);
 
+  /* Since there's only one destination, and the destination edge can only
+     either be EH or non-EH, that implies that all of our incoming edges
+     are of the same type.  Therefore we can lower EH_ELSE immediately.  */
+  x = get_eh_else (finally);
+  if (x)
+    {
+      if (tf->may_throw)
+        finally = gimple_eh_else_e_body (x);
+      else
+        finally = gimple_eh_else_n_body (x);
+    }
+
   lower_eh_constructs_1 (state, finally);
 
   if (tf->may_throw)
@@ -1171,11 +1233,18 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
   gimple_seq finally;
   gimple_seq new_stmt;
   gimple_seq seq;
-  gimple x;
+  gimple x, eh_else;
   tree tmp;
   location_t tf_loc = gimple_location (tf->try_finally_expr);
 
   finally = gimple_try_cleanup (tf->top_p);
+
+  /* Notice EH_ELSE, and simplify some of the remaining code
+     by considering FINALLY to be the normal return path only.  */
+  eh_else = get_eh_else (finally);
+  if (eh_else)
+    finally = gimple_eh_else_n_body (eh_else);
+
   tf->top_p_seq = gimple_try_eval (tf->top_p);
   new_stmt = NULL;
 
@@ -1192,12 +1261,16 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
 
   if (tf->may_throw)
     {
-      emit_post_landing_pad (&eh_seq, tf->region);
-
-      seq = lower_try_finally_dup_block (finally, state);
+      /* We don't need to copy the EH path of EH_ELSE,
+	 since it is only emitted once.  */
+      if (eh_else)
+        seq = gimple_eh_else_e_body (eh_else);
+      else
+        seq = lower_try_finally_dup_block (finally, state);
       lower_eh_constructs_1 (state, seq);
-      gimple_seq_add_seq (&eh_seq, seq);
 
+      emit_post_landing_pad (&eh_seq, tf->region);
+      gimple_seq_add_seq (&eh_seq, seq);
       emit_resx (&eh_seq, tf->region);
     }
 
@@ -1294,7 +1367,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   tree last_case;
   VEC (tree,heap) *case_label_vec;
   gimple_seq switch_body;
-  gimple x;
+  gimple x, eh_else;
   tree tmp;
   gimple switch_stmt;
   gimple_seq finally;
@@ -1305,9 +1378,10 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   location_t finally_loc;
 
   switch_body = gimple_seq_alloc ();
+  finally = gimple_try_cleanup (tf->top_p);
+  eh_else = get_eh_else (finally);
 
   /* Mash the TRY block to the head of the chain.  */
-  finally = gimple_try_cleanup (tf->top_p);
   tf->top_p_seq = gimple_try_eval (tf->top_p);
 
   /* The location of the finally is either the last stmt in the finally
@@ -1323,7 +1397,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   nlabels = VEC_length (tree, tf->dest_array);
   return_index = nlabels;
   eh_index = return_index + tf->may_return;
-  fallthru_index = eh_index + tf->may_throw;
+  fallthru_index = eh_index + (tf->may_throw && !eh_else);
   ndests = fallthru_index + tf->may_fallthru;
 
   finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
@@ -1360,7 +1434,23 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       gimple_seq_add_stmt (&switch_body, x);
     }
 
-  if (tf->may_throw)
+  /* For EH_ELSE, emit the exception path (plus resx) now, then
+     subsequently we only need consider the normal path.  */
+  if (eh_else)
+    {
+      if (tf->may_throw)
+	{
+	  finally = gimple_eh_else_e_body (eh_else);
+	  lower_eh_constructs_1 (state, finally);
+
+	  emit_post_landing_pad (&eh_seq, tf->region);
+	  gimple_seq_add_seq (&eh_seq, finally);
+	  emit_resx (&eh_seq, tf->region);
+	}
+
+      finally = gimple_eh_else_n_body (eh_else);
+    }
+  else if (tf->may_throw)
     {
       emit_post_landing_pad (&eh_seq, tf->region);
 
@@ -1500,12 +1590,22 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
    the estimate of the size of the switch machinery we'd have to add.  */
 
 static bool
-decide_copy_try_finally (int ndests, gimple_seq finally)
+decide_copy_try_finally (int ndests, bool may_throw, gimple_seq finally)
 {
   int f_estimate, sw_estimate;
+  gimple eh_else;
+
+  /* If there's an EH_ELSE involved, the exception path is separate
+     and really doesn't come into play for this computation.  */
+  eh_else = get_eh_else (finally);
+  if (eh_else)
+    {
+      ndests -= may_throw;
+      finally = gimple_eh_else_n_body (eh_else);
+    }
 
   if (!optimize)
-    return false;
+    return ndests == 1;
 
   /* Finally estimate N times, plus N gotos.  */
   f_estimate = count_insns_seq (finally, &eni_size_weights);
@@ -1589,7 +1689,8 @@ lower_try_finally (struct leh_state *state, gimple tp)
   /* We can easily special-case redirection to a single destination.  */
   else if (ndests == 1)
     lower_try_finally_onedest (state, &this_tf);
-  else if (decide_copy_try_finally (ndests, gimple_try_cleanup (tp)))
+  else if (decide_copy_try_finally (ndests, this_tf.may_throw,
+				    gimple_try_cleanup (tp)))
     lower_try_finally_copy (state, &this_tf);
   else
     lower_try_finally_switch (state, &this_tf);
@@ -1936,6 +2037,9 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
 		case GIMPLE_EH_MUST_NOT_THROW:
 		    replace = lower_eh_must_not_throw (state, stmt);
 		    break;
+		case GIMPLE_EH_ELSE:
+		    /* This code is only valid with GIMPLE_TRY_FINALLY.  */
+		    gcc_unreachable ();
 		default:
 		    replace = lower_cleanup (state, stmt);
 		    break;
@@ -1950,6 +2054,10 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
       /* Return since we don't want gsi_next () */
       return;
 
+    case GIMPLE_EH_ELSE:
+      /* We should be eliminating this in lower_try_finally et al.  */
+      gcc_unreachable ();
+
     default:
       /* A type, a decl, or some kind of statement that we're not
 	 interested in.  Don't walk them.  */
@@ -2794,6 +2902,10 @@ refactor_eh_r (gimple_seq seq)
 	  case GIMPLE_EH_FILTER:
 	    refactor_eh_r (gimple_eh_filter_failure (one));
 	    break;
+	  case GIMPLE_EH_ELSE:
+	    refactor_eh_r (gimple_eh_else_n_body (one));
+	    refactor_eh_r (gimple_eh_else_e_body (one));
+	    break;
 	  default:
 	    break;
 	  }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2009-10-20 18:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-10-20 18:44 [trans-mem] EH merge vs GIMPLE_EH_ELSE Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).