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:
parent
afc066ef35
commit
1eaba2f208
@ -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
|
||||
|
@ -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",
|
||||
|
111
gcc/tree-eh.c
111
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"
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user