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
This commit is contained in:
Richard Henderson 2004-06-28 23:59:35 -07:00 committed by Richard Henderson
parent afc066ef35
commit 1eaba2f208
7 changed files with 223 additions and 24 deletions

View File

@ -1,3 +1,22 @@
2004-06-28 Richard Henderson <rth@redhat.com>
* 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 <amodra@bigpond.net.au>
* function.c (assign_parms): Don't abort with zero size stack

View File

@ -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",

View File

@ -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"

View File

@ -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);

View File

@ -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))

View File

@ -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);
});
}

View File

@ -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)