* [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).