X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-eh.c;h=698c6548515b82f07d979e4a1ddd3f3cca4d15ab;hb=b0e959b9a82238d6d49f2f5bb05a2c0bc0349529;hp=42834e46c17b1566105a11434501a93d1e8b51a2;hpb=873f1e89a8b5e0c168f212021a018d9d6f3b21e2;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 42834e46c17..698c6548515 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -1,5 +1,5 @@ /* Exception handling semantics and decomposition for trees. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -77,7 +77,7 @@ struct_ptr_hash (const void *a) we get to rtl. Once we're done with lowering here, if we lose the information there's no way to recover it! - (2) There are many more statements that *cannot* throw as + (2) There are many more statements that *cannot* throw as compared to those that can. We should be saving some amount of space by only allocating memory for those that can throw. */ @@ -103,8 +103,7 @@ record_stmt_eh_region (struct eh_region *region, tree t) n->region_nr = get_eh_region_number (region); slot = htab_find_slot (throw_stmt_table, n, INSERT); - if (*slot) - abort (); + gcc_assert (!*slot); *slot = n; } @@ -114,16 +113,14 @@ add_stmt_to_eh_region (tree t, int num) struct throw_stmt_node *n; void **slot; - if (num < 0) - abort (); + gcc_assert (num >= 0); n = ggc_alloc (sizeof (*n)); n->stmt = t; n->region_nr = num; slot = htab_find_slot (throw_stmt_table, n, INSERT); - if (*slot) - abort (); + gcc_assert (!*slot); *slot = n; } @@ -186,8 +183,7 @@ record_in_finally_tree (tree child, tree parent) n->parent = parent; slot = htab_find_slot (finally_tree, n, INSERT); - if (*slot) - abort (); + gcc_assert (!*slot); *slot = n; } @@ -265,7 +261,7 @@ outside_finally_tree (tree start, tree target) struct leh_state { - /* What's "current" while constructing the eh region tree. These + /* What's "current" while constructing the eh region tree. These correspond to variables of the same name in cfun->eh, which we don't have easy access to. */ struct eh_region *cur_region; @@ -280,7 +276,7 @@ struct leh_state struct leh_tf_state { /* Pointer to the TRY_FINALLY node under discussion. The try_finally_expr - is the original TRY_FINALLY_EXPR. We need to retain this so that + is the original TRY_FINALLY_EXPR. We need to retain this so that outside_finally_tree can reliably reference the tree used in the collect_finally_tree data structures. */ tree try_finally_expr; @@ -311,7 +307,7 @@ struct leh_tf_state though subsequent transformations may have cleared that flag. */ tree fallthru_label; - /* A label that has been registered with except.c to be the + /* A label that has been registered with except.c to be the landing pad for this try block. */ tree eh_label; @@ -330,7 +326,7 @@ struct leh_tf_state static void lower_eh_filter (struct leh_state *, tree *); static void lower_eh_constructs_1 (struct leh_state *, tree *); -/* Comparison function for qsort/bsearch. We're interested in +/* Comparison function for qsort/bsearch. We're interested in searching goto queue elements for source statements. */ static int @@ -383,7 +379,7 @@ replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf, tsi_link_after (tsi, new, TSI_CONTINUE_LINKING); } -/* The real work of replace_goto_queue. Returns with TSI updated to +/* The real work of replace_goto_queue. Returns with TSI updated to point to the next statement. */ static void replace_goto_queue_stmt_list (tree, struct leh_tf_state *); @@ -422,7 +418,7 @@ replace_goto_queue_1 (tree t, struct leh_tf_state *tf, tree_stmt_iterator *tsi) break; case STATEMENT_LIST: - abort (); + gcc_unreachable (); default: /* These won't have gotos in them. */ @@ -447,6 +443,8 @@ replace_goto_queue_stmt_list (tree t, struct leh_tf_state *tf) static void replace_goto_queue (struct leh_tf_state *tf) { + if (tf->goto_queue_active == 0) + return; replace_goto_queue_stmt_list (*tf->top_p, tf); } @@ -471,7 +469,7 @@ maybe_record_in_goto_queue (struct leh_state *state, tree stmt) { tree lab = GOTO_DESTINATION (stmt); - /* Computed and non-local gotos do not get processed. Given + /* Computed and non-local gotos do not get processed. Given their nature we can neither tell whether we've escaped the finally block nor redirect them if we knew. */ if (TREE_CODE (lab) != LABEL_DECL) @@ -480,7 +478,7 @@ maybe_record_in_goto_queue (struct leh_state *state, tree stmt) /* No need to record gotos that don't leave the try block. */ if (! outside_finally_tree (lab, tf->try_finally_expr)) return; - + if (! tf->dest_array) { VARRAY_TREE_INIT (tf->dest_array, 10, "dest_array"); @@ -505,7 +503,7 @@ maybe_record_in_goto_queue (struct leh_state *state, tree stmt) break; default: - abort (); + gcc_unreachable (); } active = tf->goto_queue_active; @@ -520,7 +518,7 @@ maybe_record_in_goto_queue (struct leh_state *state, tree stmt) q = &tf->goto_queue[active]; tf->goto_queue_active = active + 1; - + memset (q, 0, sizeof (*q)); q->stmt = stmt; q->index = index; @@ -547,8 +545,7 @@ verify_norecord_switch_expr (struct leh_state *state, tree switch_expr) for (i = 0; i < n; ++i) { tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i)); - if (outside_finally_tree (lab, tf->try_finally_expr)) - abort (); + gcc_assert (!outside_finally_tree (lab, tf->try_finally_expr)); } } #else @@ -591,47 +588,51 @@ do_return_redirection (struct goto_queue_node *q, tree finlab, tree mod, depends, I guess, but it does make generation of the switch in lower_try_finally_switch easier. */ - if (TREE_CODE (ret_expr) == RESULT_DECL) + switch (TREE_CODE (ret_expr)) { + case RESULT_DECL: if (!*return_value_p) *return_value_p = ret_expr; - else if (*return_value_p != ret_expr) - abort (); - q->cont_stmt = q->stmt; - } - else if (TREE_CODE (ret_expr) == MODIFY_EXPR) - { - tree result = TREE_OPERAND (ret_expr, 0); - tree new, old = TREE_OPERAND (ret_expr, 1); - - if (!*return_value_p) - { - if (aggregate_value_p (TREE_TYPE (result), - TREE_TYPE (current_function_decl))) - /* If this function returns in memory, copy the argument - into the return slot now. Otherwise, we might need to - worry about magic return semantics, so we need to use a - temporary to hold the value until we're actually ready - to return. */ - new = result; - else - new = create_tmp_var (TREE_TYPE (old), "rettmp"); - *return_value_p = new; - } else - new = *return_value_p; + gcc_assert (*return_value_p == ret_expr); + q->cont_stmt = q->stmt; + break; - x = build (MODIFY_EXPR, TREE_TYPE (new), new, old); - append_to_statement_list (x, &q->repl_stmt); + case MODIFY_EXPR: + { + tree result = TREE_OPERAND (ret_expr, 0); + tree new, old = TREE_OPERAND (ret_expr, 1); + + if (!*return_value_p) + { + if (aggregate_value_p (TREE_TYPE (result), + TREE_TYPE (current_function_decl))) + /* If this function returns in memory, copy the argument + into the return slot now. Otherwise, we might need to + worry about magic return semantics, so we need to use a + temporary to hold the value until we're actually ready + to return. */ + new = result; + else + new = create_tmp_var (TREE_TYPE (old), "rettmp"); + *return_value_p = new; + } + else + new = *return_value_p; + + x = build (MODIFY_EXPR, TREE_TYPE (new), new, old); + append_to_statement_list (x, &q->repl_stmt); + + if (new == result) + x = result; + else + x = build (MODIFY_EXPR, TREE_TYPE (result), result, new); + q->cont_stmt = build1 (RETURN_EXPR, void_type_node, x); + } - if (new == result) - x = result; - else - x = build (MODIFY_EXPR, TREE_TYPE (result), result, new); - q->cont_stmt = build1 (RETURN_EXPR, void_type_node, x); + default: + gcc_unreachable (); } - else - abort (); } else { @@ -709,7 +710,7 @@ lower_try_finally_dup_block (tree t, struct leh_state *outer_state) { tree region = NULL; - t = lhd_unsave_expr_now (t); + t = unsave_expr_now (t); if (outer_state->tf) region = outer_state->tf->try_finally_expr; @@ -731,7 +732,7 @@ lower_try_finally_fallthru_label (struct leh_tf_state *tf) label = create_artificial_label (); tf->fallthru_label = label; if (tf->outer->tf) - record_in_finally_tree (label, tf->outer->tf->try_finally_expr); + record_in_finally_tree (label, tf->outer->tf->try_finally_expr); } return label; } @@ -752,9 +753,9 @@ lower_try_finally_fallthru_label (struct leh_tf_state *tf) where "fintmp" is the temporary used in the switch statement generation alternative considered below. For the nonce, we always choose the first - option. + option. - THIS_STATE may be null if if this is a try-cleanup, not a try-finally. */ + THIS_STATE may be null if this is a try-cleanup, not a try-finally. */ static void honor_protect_cleanup_actions (struct leh_state *outer_state, @@ -832,7 +833,8 @@ honor_protect_cleanup_actions (struct leh_state *outer_state, tsi_link_after (&i, x, TSI_CONTINUE_LINKING); x = build1 (RESX_EXPR, void_type_node, - build_int_2 (get_eh_region_number (tf->region), 0)); + build_int_cst (NULL_TREE, + get_eh_region_number (tf->region))); tsi_link_after (&i, x, TSI_CONTINUE_LINKING); } @@ -936,9 +938,10 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) append_to_statement_list (x, tf->top_p); append_to_statement_list (finally, tf->top_p); - + x = build1 (RESX_EXPR, void_type_node, - build_int_2 (get_eh_region_number (tf->region), 0)); + build_int_cst (NULL_TREE, + get_eh_region_number (tf->region))); append_to_statement_list (x, tf->top_p); return; @@ -975,7 +978,7 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) for (; q < qe; ++q) do_goto_redirection (q, finally_label, NULL); replace_goto_queue (tf); - + if (VARRAY_TREE (tf->dest_array, 0) == tf->fallthru_label) { /* Reachable by goto to fallthru label only. Redirect it @@ -1026,7 +1029,8 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf) append_to_statement_list (x, &new_stmt); x = build1 (RESX_EXPR, void_type_node, - build_int_2 (get_eh_region_number (tf->region), 0)); + build_int_cst (NULL_TREE, + get_eh_region_number (tf->region))); append_to_statement_list (x, &new_stmt); } @@ -1134,7 +1138,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) if (tf->may_fallthru) { x = build (MODIFY_EXPR, void_type_node, finally_tmp, - build_int_2 (fallthru_index, 0)); + build_int_cst (NULL_TREE, fallthru_index)); append_to_statement_list (x, tf->top_p); if (tf->may_throw) @@ -1145,7 +1149,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) last_case = build (CASE_LABEL_EXPR, void_type_node, - build_int_2 (fallthru_index, 0), NULL, + build_int_cst (NULL_TREE, fallthru_index), NULL, create_artificial_label ()); TREE_VEC_ELT (case_label_vec, last_case_index) = last_case; last_case_index++; @@ -1164,11 +1168,11 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) append_to_statement_list (x, tf->top_p); x = build (MODIFY_EXPR, void_type_node, finally_tmp, - build_int_2 (eh_index, 0)); + build_int_cst (NULL_TREE, eh_index)); append_to_statement_list (x, tf->top_p); last_case = build (CASE_LABEL_EXPR, void_type_node, - build_int_2 (eh_index, 0), NULL, + build_int_cst (NULL_TREE, eh_index), NULL, create_artificial_label ()); TREE_VEC_ELT (case_label_vec, last_case_index) = last_case; last_case_index++; @@ -1176,7 +1180,8 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case)); append_to_statement_list (x, &switch_body); x = build1 (RESX_EXPR, void_type_node, - build_int_2 (get_eh_region_number (tf->region), 0)); + build_int_cst (NULL_TREE, + get_eh_region_number (tf->region))); append_to_statement_list (x, &switch_body); } @@ -1198,14 +1203,14 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) if (q->index < 0) { mod = build (MODIFY_EXPR, void_type_node, finally_tmp, - build_int_2 (return_index, 0)); + build_int_cst (NULL_TREE, return_index)); do_return_redirection (q, finally_label, mod, &return_val); switch_id = return_index; } else { mod = build (MODIFY_EXPR, void_type_node, finally_tmp, - build_int_2 (q->index, 0)); + build_int_cst (NULL_TREE, q->index)); do_goto_redirection (q, finally_label, mod); switch_id = q->index; } @@ -1214,7 +1219,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) if (!TREE_VEC_ELT (case_label_vec, case_index)) { last_case = build (CASE_LABEL_EXPR, void_type_node, - build_int_2 (switch_id, 0), NULL, + build_int_cst (NULL_TREE, switch_id), NULL, create_artificial_label ()); TREE_VEC_ELT (case_label_vec, case_index) = last_case; @@ -1280,7 +1285,7 @@ decide_copy_try_finally (int ndests, tree finally) /* A subroutine of lower_eh_constructs_1. Lower a TRY_FINALLY_EXPR nodes to a sequence of labels and blocks, plus the exception region trees - that record all the magic. This is complicated by the need to + that record all the magic. This is complicated by the need to arrange for the FINALLY block to be executed on all exits. */ static void @@ -1370,7 +1375,7 @@ lower_try_finally (struct leh_state *state, tree *tp) } /* A subroutine of lower_eh_constructs_1. Lower a TRY_CATCH_EXPR with a - list of CATCH_EXPR nodes to a sequence of labels and blocks, plus the + list of CATCH_EXPR nodes to a sequence of labels and blocks, plus the exception region trees that record all the magic. */ static void @@ -1440,7 +1445,7 @@ lower_eh_filter (struct leh_state *state, tree *tp) struct eh_region *this_region; tree inner = expr_first (TREE_OPERAND (*tp, 1)); tree eh_label; - + if (EH_FILTER_MUST_NOT_THROW (inner)) this_region = gen_eh_region_must_not_throw (state->cur_region); else @@ -1448,7 +1453,7 @@ lower_eh_filter (struct leh_state *state, tree *tp) EH_FILTER_TYPES (inner)); this_state = *state; this_state.cur_region = this_region; - + lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); if (!get_eh_region_may_contain_throw (this_region)) @@ -1564,7 +1569,7 @@ lower_eh_constructs_1 (struct leh_state *state, tree *tp) record_stmt_eh_region (state->cur_region, t); note_eh_region_may_contain_throw (state->cur_region); - /* ??? For the benefit of calls.c, converting all this to rtl, + /* ??? For the benefit of calls.c, converting all this to rtl, we need to record the call expression, not just the outer modify statement. */ op = get_call_expr_in (t); @@ -1643,7 +1648,7 @@ lower_eh_constructs (void) collect_eh_region_array (); } -struct tree_opt_pass pass_lower_eh = +struct tree_opt_pass pass_lower_eh = { "eh", /* name */ NULL, /* gate */ @@ -1656,7 +1661,8 @@ struct tree_opt_pass pass_lower_eh = PROP_gimple_leh, /* properties_provided */ PROP_gimple_lcf, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + TODO_dump_func, /* todo_flags_finish */ + 0 /* letter */ }; @@ -1676,7 +1682,7 @@ make_eh_edge (struct eh_region *region, void *data) make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH); } - + void make_eh_edges (tree stmt) { @@ -1713,11 +1719,11 @@ tree_could_trap_p (tree expr) bool honor_snans = false; bool fp_operation = false; bool honor_trapv = false; - tree t, base, idx; + tree t, base; - if (TREE_CODE_CLASS (code) == '<' - || TREE_CODE_CLASS (code) == '1' - || TREE_CODE_CLASS (code) == '2') + if (TREE_CODE_CLASS (code) == tcc_comparison + || TREE_CODE_CLASS (code) == tcc_unary + || TREE_CODE_CLASS (code) == tcc_binary) { t = TREE_TYPE (expr); fp_operation = FLOAT_TYPE_P (t); @@ -1753,7 +1759,6 @@ tree_could_trap_p (tree expr) case ARRAY_REF: base = TREE_OPERAND (expr, 0); - idx = TREE_OPERAND (expr, 1); if (tree_could_trap_p (base)) return true; @@ -1763,6 +1768,8 @@ tree_could_trap_p (tree expr) return !in_array_bounds_p (expr); case INDIRECT_REF: + case ALIGN_INDIRECT_REF: + case MISALIGNED_INDIRECT_REF: return !TREE_THIS_NOTRAP (expr); case ASM_EXPR: @@ -1832,6 +1839,13 @@ tree_could_trap_p (tree expr) return true; return false; + case CALL_EXPR: + t = get_callee_fndecl (expr); + /* Assume that calls to weak functions may trap. */ + if (!t || !DECL_P (t) || DECL_WEAK (t)) + return true; + return false; + default: /* Any floating arithmetic may trap. */ if (fp_operation && flag_trapping_math)