From 1eaba2f2086b04bb92b153214d970146452b2fb4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 28 Jun 2004 23:59:35 -0700 Subject: [PATCH] tree-cfg.c (verify_stmt): Add last_in_block parameter. * tree-cfg.c (verify_stmt): Add last_in_block parameter. Verify that eh stmts can throw. (verify_stmts): Update verify_stmt call. (tree_purge_dead_eh_edges, tree_purge_all_dead_eh_edges): New. * tree-eh.c (remove_stmt_from_eh_region): New. (lower_eh_constructs): Fix throw_stmt_table delete routine. (tree_could_trap_p): Match may_trap_p. (maybe_clean_eh_stmt): New. * tree-flow.h: Update decls. * tree-ssa-ccp.c (pass_ccp): Add TODO_verify_stmts. (substitute_and_fold): Clean eh edges. * tree-ssa-dce.c (mark_control_dependent_edges_necessary): Handle empty basic blocks. * tree-ssa-dom.c (need_eh_cleanup): New. (tree_ssa_dominator_optimize): Allocate it. Cleanup eh edges. (optimize_stmt): Cleanup eh stmts; set need_eh_cleanup. From-SVN: r83843 --- gcc/ChangeLog | 19 ++++++++ gcc/tree-cfg.c | 67 +++++++++++++++++++++++++-- gcc/tree-eh.c | 111 +++++++++++++++++++++++++++++++++++++++++---- gcc/tree-flow.h | 5 ++ gcc/tree-ssa-ccp.c | 9 +++- gcc/tree-ssa-dce.c | 2 +- gcc/tree-ssa-dom.c | 34 +++++++++++--- 7 files changed, 223 insertions(+), 24 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7403553b171..854141fed44 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2004-06-28 Richard Henderson + + * tree-cfg.c (verify_stmt): Add last_in_block parameter. Verify + that eh stmts can throw. + (verify_stmts): Update verify_stmt call. + (tree_purge_dead_eh_edges, tree_purge_all_dead_eh_edges): New. + * tree-eh.c (remove_stmt_from_eh_region): New. + (lower_eh_constructs): Fix throw_stmt_table delete routine. + (tree_could_trap_p): Match may_trap_p. + (maybe_clean_eh_stmt): New. + * tree-flow.h: Update decls. + * tree-ssa-ccp.c (pass_ccp): Add TODO_verify_stmts. + (substitute_and_fold): Clean eh edges. + * tree-ssa-dce.c (mark_control_dependent_edges_necessary): Handle + empty basic blocks. + * tree-ssa-dom.c (need_eh_cleanup): New. + (tree_ssa_dominator_optimize): Allocate it. Cleanup eh edges. + (optimize_stmt): Cleanup eh stmts; set need_eh_cleanup. + 2004-06-29 Alan Modra * function.c (assign_parms): Don't abort with zero size stack diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 6855d712833..88e66f7badc 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -3316,15 +3316,14 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) TODO: Implement type checking. */ static bool -verify_stmt (tree stmt) +verify_stmt (tree stmt, bool last_in_block) { tree addr; if (!is_gimple_stmt (stmt)) { error ("Is not a valid GIMPLE statement."); - debug_generic_stmt (stmt); - return true; + goto fail; } addr = walk_tree (&stmt, verify_expr, NULL, NULL); @@ -3334,7 +3333,30 @@ verify_stmt (tree stmt) return true; } + /* If the statement is marked as part of an EH region, then it is + expected that the statement could throw. Verify that when we + have optimizations that simplify statements such that we prove + that they cannot throw, that we update other data structures + to match. */ + if (lookup_stmt_eh_region (stmt) >= 0) + { + if (!tree_could_throw_p (stmt)) + { + error ("Statement marked for throw, but doesn't."); + goto fail; + } + if (!last_in_block && tree_can_throw_internal (stmt)) + { + error ("Statement marked for throw in middle of block."); + goto fail; + } + } + return false; + + fail: + debug_generic_stmt (stmt); + return true; } @@ -3449,10 +3471,11 @@ verify_stmts (void) } } - for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + for (bsi = bsi_start (bb); !bsi_end_p (bsi); ) { tree stmt = bsi_stmt (bsi); - err |= verify_stmt (stmt); + bsi_next (&bsi); + err |= verify_stmt (stmt, bsi_end_p (bsi)); addr = walk_tree (&stmt, verify_node_sharing, htab, NULL); if (addr) { @@ -4637,6 +4660,40 @@ tree_flow_call_edges_add (sbitmap blocks) return blocks_split; } +bool +tree_purge_dead_eh_edges (basic_block bb) +{ + bool changed = false; + edge e, next; + tree stmt = last_stmt (bb); + + if (stmt && tree_can_throw_internal (stmt)) + return false; + + for (e = bb->succ; e ; e = next) + { + next = e->succ_next; + if (e->flags & EDGE_EH) + { + ssa_remove_edge (e); + changed = true; + } + } + + return changed; +} + +bool +tree_purge_all_dead_eh_edges (bitmap blocks) +{ + bool changed = false; + size_t i; + + EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, + { changed |= tree_purge_dead_eh_edges (BASIC_BLOCK (i)); }); + + return changed; +} struct cfg_hooks tree_cfg_hooks = { "tree", diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index f15fe099142..c0ddf3e7c3c 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -119,7 +119,27 @@ add_stmt_to_eh_region (tree t, int num) abort (); *slot = n; } - + +bool +remove_stmt_from_eh_region (tree t) +{ + struct throw_stmt_node dummy; + void **slot; + + if (!throw_stmt_table) + return false; + + dummy.stmt = t; + slot = htab_find_slot (throw_stmt_table, &dummy, NO_INSERT); + if (slot) + { + htab_clear_slot (throw_stmt_table, slot); + return true; + } + else + return false; +} + int lookup_stmt_eh_region (tree t) { @@ -1600,7 +1620,8 @@ lower_eh_constructs (void) tree *tp = &DECL_SAVED_TREE (current_function_decl); finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free); - throw_stmt_table = htab_create_ggc (31, struct_ptr_hash, struct_ptr_eq, free); + throw_stmt_table = htab_create_ggc (31, struct_ptr_hash, struct_ptr_eq, + ggc_free); collect_finally_tree (*tp, NULL); @@ -1670,15 +1691,32 @@ make_eh_edges (tree stmt) -/* Return true if the expr can trap, as in dereferencing an - invalid pointer location. */ +/* Return true if the expr can trap, as in dereferencing an invalid pointer + location or floating point arithmetic. C.f. the rtl version, may_trap_p. + This routine expects only GIMPLE lhs or rhs input. */ bool tree_could_trap_p (tree expr) { enum tree_code code = TREE_CODE (expr); + bool honor_nans = false; + bool honor_snans = false; + bool fp_operation = false; tree t; + if (TREE_CODE_CLASS (code) == '<' + || TREE_CODE_CLASS (code) == '1' + || TREE_CODE_CLASS (code) == '2') + { + t = TREE_TYPE (expr); + fp_operation = FLOAT_TYPE_P (t); + if (fp_operation) + { + honor_nans = flag_trapping_math && !flag_finite_math_only; + honor_snans = flag_signaling_nans != 0; + } + } + switch (code) { case ARRAY_REF: @@ -1691,7 +1729,10 @@ tree_could_trap_p (tree expr) return !t || tree_could_trap_p (t); case INDIRECT_REF: - return (TREE_THIS_NOTRAP (expr) == false); + return !TREE_THIS_NOTRAP (expr); + + case ASM_EXPR: + return TREE_THIS_VOLATILE (expr); case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: @@ -1702,16 +1743,57 @@ tree_could_trap_p (tree expr) case FLOOR_MOD_EXPR: case ROUND_MOD_EXPR: case TRUNC_MOD_EXPR: - return true; + case RDIV_EXPR: + if (honor_snans) + return true; + if (fp_operation && flag_trapping_math) + return true; + t = TREE_OPERAND (expr, 1); + if (!TREE_CONSTANT (t) || integer_zerop (t)) + return true; + return false; + + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case LTGT_EXPR: + /* Some floating point comparisons may trap. */ + return honor_nans; + + case EQ_EXPR: + case NE_EXPR: + case UNORDERED_EXPR: + case ORDERED_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + return honor_snans; + + case CONVERT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + /* Conversion of floating point might trap. */ + return honor_nans; + + case NEGATE_EXPR: + case ABS_EXPR: + case CONJ_EXPR: + /* These operations don't trap even with floating point. */ + return false; default: - break; + /* Any floating arithmetic may trap. */ + if (fp_operation && flag_trapping_math) + return true; + return false; } - - return false; } - bool tree_could_throw_p (tree t) { @@ -1750,4 +1832,13 @@ tree_can_throw_external (tree stmt) return can_throw_external_1 (region_nr); } +bool +maybe_clean_eh_stmt (tree stmt) +{ + if (!tree_could_throw_p (stmt)) + if (remove_stmt_from_eh_region (stmt)) + return true; + return false; +} + #include "gt-tree-eh.h" diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 0f97a5b9cf1..8b6690b21e7 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -497,6 +497,8 @@ extern void compute_dominance_frontiers (bitmap *); extern void verify_stmts (void); extern tree tree_block_label (basic_block bb); extern void extract_true_false_edges_from_block (basic_block, edge *, edge *); +extern bool tree_purge_dead_eh_edges (basic_block); +extern bool tree_purge_all_dead_eh_edges (bitmap); /* In tree-pretty-print.c. */ extern void dump_generic_bb (FILE *, basic_block, int, int); @@ -600,7 +602,10 @@ extern bool tree_could_trap_p (tree); extern bool tree_could_throw_p (tree); extern bool tree_can_throw_internal (tree); extern bool tree_can_throw_external (tree); +extern int lookup_stmt_eh_region (tree); extern void add_stmt_to_eh_region (tree, int); +extern bool remove_stmt_from_eh_region (tree); +extern bool maybe_clean_eh_stmt (tree); /* In tree-ssa-pre.c */ void add_to_value (tree, tree); diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index ef0c12be378..559f19b0765 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -248,7 +248,8 @@ struct tree_opt_pass pass_ccp = 0, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_dump_func | TODO_rename_vars - | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ + | TODO_ggc_collect | TODO_verify_ssa + | TODO_verify_stmts /* todo_flags_finish */ }; @@ -427,7 +428,11 @@ substitute_and_fold (void) /* If we folded a builtin function, we'll likely need to rename VDEFs. */ if (replaced_address || changed) - mark_new_vars_to_rename (stmt, vars_to_rename); + { + mark_new_vars_to_rename (stmt, vars_to_rename); + if (maybe_clean_eh_stmt (stmt)) + tree_purge_dead_eh_edges (bb); + } } if (dump_file && (dump_flags & TDF_DETAILS)) diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index 344f2249ada..e9ead5c0dfb 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -500,7 +500,7 @@ mark_control_dependent_edges_necessary (basic_block bb, struct edge_list *el) SET_BIT (last_stmt_necessary, cd_bb->index); t = last_stmt (cd_bb); - if (is_ctrl_stmt (t)) + if (t && is_ctrl_stmt (t)) mark_stmt_necessary (t, true); }); } diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 28780747736..ddd803bc4ba 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -95,6 +95,10 @@ static bitmap nonzero_vars; /* Track whether or not we have changed the control flow graph. */ static bool cfg_altered; +/* Bitmap of blocks that have had EH statements cleaned. We should + remove thier dead edges eventually. */ +static bitmap need_eh_cleanup; + /* Statistics for dominator optimizations. */ struct opt_stats_d { @@ -554,6 +558,7 @@ tree_ssa_dominator_optimize (void) nonzero_vars = BITMAP_XMALLOC (); VARRAY_EDGE_INIT (redirection_edges, 20, "redirection_edges"); VARRAY_GENERIC_PTR_INIT (vrp_data, num_ssa_names, "vrp_data"); + need_eh_cleanup = BITMAP_XMALLOC (); /* Setup callbacks for the generic dominator tree walker. */ walk_data.walk_stmts_backward = false; @@ -599,15 +604,24 @@ tree_ssa_dominator_optimize (void) if (VARRAY_ACTIVE_SIZE (redirection_edges) > 0) redirect_edges_and_update_ssa_graph (redirection_edges); + if (bitmap_first_set_bit (need_eh_cleanup) >= 0) + { + cfg_altered = tree_purge_all_dead_eh_edges (need_eh_cleanup); + bitmap_zero (need_eh_cleanup); + } + /* We may have made some basic blocks unreachable, remove them. */ cfg_altered |= delete_unreachable_blocks (); /* If the CFG was altered, then recompute the dominator tree. This is not strictly needed if we only removed unreachable blocks, but may produce better results. If we threaded jumps, then rebuilding - the dominator tree is strictly necessary. */ + the dominator tree is strictly necessary. Likewise with EH cleanup. + Free the dominance info first so that cleanup_tree_cfg doesn't try + to verify it. */ if (cfg_altered) { + free_dominance_info (CDI_DOMINATORS); cleanup_tree_cfg (); calculate_dominance_info (CDI_DOMINATORS); } @@ -656,6 +670,7 @@ tree_ssa_dominator_optimize (void) /* Free nonzero_vars. */ BITMAP_XFREE (nonzero_vars); + BITMAP_XFREE (need_eh_cleanup); } static bool @@ -2985,8 +3000,7 @@ cprop_into_stmt (tree stmt, varray_type const_and_copies) the variable in the LHS in the CONST_AND_COPIES table. */ static void -optimize_stmt (struct dom_walk_data *walk_data, - basic_block bb ATTRIBUTE_UNUSED, +optimize_stmt (struct dom_walk_data *walk_data, basic_block bb, block_stmt_iterator si) { stmt_ann_t ann; @@ -3100,11 +3114,19 @@ optimize_stmt (struct dom_walk_data *walk_data, else if (TREE_CODE (stmt) == SWITCH_EXPR) val = SWITCH_COND (stmt); - if (val && TREE_CODE (val) == INTEGER_CST - && find_taken_edge (bb_for_stmt (stmt), val)) + if (val && TREE_CODE (val) == INTEGER_CST && find_taken_edge (bb, val)) cfg_altered = true; + + /* If we simplified a statement in such a way as to be shown that it + cannot trap, update the eh information and the cfg to match. */ + if (maybe_clean_eh_stmt (stmt)) + { + bitmap_set_bit (need_eh_cleanup, bb->index); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " Flagged to clear EH edges.\n"); + } } - + if (may_have_exposed_new_symbols) { if (! bd->stmts_to_rescan)