diff options
author | Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz> | 2003-08-16 21:11:08 +0000 |
---|---|---|
committer | Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz> | 2003-08-16 21:11:08 +0000 |
commit | 55439f72ab5ea0f3a4b74f25938470424b629e2a (patch) | |
tree | 9d4a315d23e437af2e0de4fab396f24f76b73b5e | |
parent | f73d973a7e9ee26f3255f19d5f0c5475c25423b8 (diff) |
* basic-block.h (EDGE_CONSTRUCT_ENTRY): New.
* cfg.c (dump_edge_info): Add name for EDGE_CONSTRUCT_ENTRY flag.
* tree-cfg.c (remove_stmt, bsi_remove): Get basic block from argument
rather than from bb_for_stmt.
(remove_useless_stmts_and_vars): Export.
(make_edges): Mark edges with EDGE_CONSTRUCT_ENTRY.
(tree_redirect_edge_and_branch): Refuse to redirect abnormal edges.
Update phi nodes.
(cleanup_tree_cfg): Don't call remove_useless_stmts_and_vars.
(tree_merge_blocks): Handle phi nodes.
(tree_verify_flow_info): Add checks for phi nodes.
(dump_block_tree): Dump variables.
(tree_forwarder_block_p): Fail if successor is EDGE_CONSTRUCT_ENTRY,
or if block contains phi nodes.
(thread_jumps): Handle phi nodes.
(merge_seq_blocks): Don't merge with construct entry.
* tree-dfa.c (add_vdef): Export.
(virtual_op_p): Split off add_stmt_operand.
(add_stmt_operand): Use it.
* tree-flatten.c (tree_flatten_statement): Don't record BIND_EXPRs
with no variables.
(compact_to_block): Use EDGE_CONSTRUCT_ENTRY flag.
* tree-flow.h (remove_useless_stmts_and_vars, add_vdef,
virtual_op_p, fixup_var_scope): Declare.
* tree-optimize.c (optimize_function_tree): Enable dce.
* tree-ssa-copyprop.c (fixup_var_scope): Split off propagate_copy.
(propagate_copy): Use it.
* tree-ssa-dce.c: Disable removal of dead conditionals. Enable rest.
* tree-ssa-dom.c (optimize_stmt): Use fixup_var_scope.
* tree-ssa.c (rewrite_out_of_ssa): Call remove_useless_stmts_and_vars.
* tree.c (resize_phi_node): Zero new elements.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/tree-ssa-cfg-branch@70508 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog.tree-ssa-cfg | 34 | ||||
-rw-r--r-- | gcc/basic-block.h | 3 | ||||
-rw-r--r-- | gcc/cfg.c | 2 | ||||
-rw-r--r-- | gcc/tree-cfg.c | 229 | ||||
-rw-r--r-- | gcc/tree-dfa.c | 71 | ||||
-rw-r--r-- | gcc/tree-flatten.c | 58 | ||||
-rw-r--r-- | gcc/tree-flow.h | 4 | ||||
-rw-r--r-- | gcc/tree-optimize.c | 5 | ||||
-rw-r--r-- | gcc/tree-ssa-copyprop.c | 12 | ||||
-rw-r--r-- | gcc/tree-ssa-dce.c | 99 | ||||
-rw-r--r-- | gcc/tree-ssa-dom.c | 11 | ||||
-rw-r--r-- | gcc/tree-ssa.c | 1 | ||||
-rw-r--r-- | gcc/tree.c | 8 |
13 files changed, 398 insertions, 139 deletions
diff --git a/gcc/ChangeLog.tree-ssa-cfg b/gcc/ChangeLog.tree-ssa-cfg index b0e8acc497b..602399405d7 100644 --- a/gcc/ChangeLog.tree-ssa-cfg +++ b/gcc/ChangeLog.tree-ssa-cfg @@ -1,3 +1,37 @@ +2003-08-16 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz> + + * basic-block.h (EDGE_CONSTRUCT_ENTRY): New. + * cfg.c (dump_edge_info): Add name for EDGE_CONSTRUCT_ENTRY flag. + * tree-cfg.c (remove_stmt, bsi_remove): Get basic block from argument + rather than from bb_for_stmt. + (remove_useless_stmts_and_vars): Export. + (make_edges): Mark edges with EDGE_CONSTRUCT_ENTRY. + (tree_redirect_edge_and_branch): Refuse to redirect abnormal edges. + Update phi nodes. + (cleanup_tree_cfg): Don't call remove_useless_stmts_and_vars. + (tree_merge_blocks): Handle phi nodes. + (tree_verify_flow_info): Add checks for phi nodes. + (dump_block_tree): Dump variables. + (tree_forwarder_block_p): Fail if successor is EDGE_CONSTRUCT_ENTRY, + or if block contains phi nodes. + (thread_jumps): Handle phi nodes. + (merge_seq_blocks): Don't merge with construct entry. + * tree-dfa.c (add_vdef): Export. + (virtual_op_p): Split off add_stmt_operand. + (add_stmt_operand): Use it. + * tree-flatten.c (tree_flatten_statement): Don't record BIND_EXPRs + with no variables. + (compact_to_block): Use EDGE_CONSTRUCT_ENTRY flag. + * tree-flow.h (remove_useless_stmts_and_vars, add_vdef, + virtual_op_p, fixup_var_scope): Declare. + * tree-optimize.c (optimize_function_tree): Enable dce. + * tree-ssa-copyprop.c (fixup_var_scope): Split off propagate_copy. + (propagate_copy): Use it. + * tree-ssa-dce.c: Disable removal of dead conditionals. Enable rest. + * tree-ssa-dom.c (optimize_stmt): Use fixup_var_scope. + * tree-ssa.c (rewrite_out_of_ssa): Call remove_useless_stmts_and_vars. + * tree.c (resize_phi_node): Zero new elements. + 2003-08-14 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz> * Makefile.in (tree-flatten.o): Add. diff --git a/gcc/basic-block.h b/gcc/basic-block.h index f3f6ce950c6..b0af7ff0863 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -159,7 +159,8 @@ typedef struct edge_def { predicate is zero. */ #define EDGE_EXECUTABLE 4096 /* Edge is executable. Only valid during SSA-CCP. */ -#define EDGE_ALL_FLAGS 8191 +#define EDGE_CONSTRUCT_ENTRY 8192 /* An entry of block. */ +#define EDGE_ALL_FLAGS 16383 #define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH) diff --git a/gcc/cfg.c b/gcc/cfg.c index b03528e40b8..ecbb17d1c6f 100644 --- a/gcc/cfg.c +++ b/gcc/cfg.c @@ -639,7 +639,7 @@ dump_edge_info (FILE *file, edge e, int do_succ) static const char * const bitnames[] = { "fallthru", "ab", "abcall", "eh", "fake", "dfs_back", "can_fallthru", "irreducible", "sibcall", "loop_exit", - "true", "false", "exec" + "true", "false", "exec", "construct_entry" }; int comma = 0; int i, flags = e->flags; diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 10048c76d64..6c6c07db176 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -171,7 +171,7 @@ static void tree_loop_optimizer_finalize (struct loops *, FILE *); /* Flowgraph optimization and cleanup. */ static void remove_bb (basic_block); static void tree_merge_blocks (basic_block, basic_block); -static void remove_stmt (tree_cell); +static void remove_stmt (tree_cell, basic_block); static edge find_taken_edge_cond_expr (basic_block, tree); static edge find_taken_edge_switch_expr (basic_block, tree); static tree find_edge_goto (tree, edge); @@ -182,7 +182,6 @@ static void assign_vars_to_scope (struct block_tree *); static void remove_superfluous_labels (void); static void thread_jumps (void); static bool tree_forwarder_block_p (basic_block); -static void remove_useless_stmts_and_vars (void); static void merge_seq_blocks (void); /* Location to track pending stmt for edge insertion. */ @@ -568,6 +567,8 @@ static void make_edges (void) { basic_block bb; + struct block_tree *bti; + edge e; /* Create an edge from entry to the first block with executable statements in it. */ @@ -609,6 +610,18 @@ make_edges (void) /* We do not care about fake edges, so remove any that the CFG builder inserted for completeness. */ remove_fake_edges (); + + /* Mark special edges of constructs. */ + for (bti = bti_start (); !bti_end_p (bti); bti_next (&bti)) + if (bti->entry) + { + for (e = bti->entry->pred; e; e = e->pred_next) + if (e->flags & EDGE_FALLTHRU) + break; + + if (e) + e->flags |= EDGE_CONSTRUCT_ENTRY; + } } /* Create edges for control statement at basic block BB. */ @@ -875,6 +888,9 @@ tree_redirect_edge_and_branch (edge e, basic_block dest) if (e->dest == dest) return true; + if (e->flags & EDGE_ABNORMAL) + return false; + stmt = last_stmt (bb); bsi = bsi_last (bb); @@ -886,8 +902,7 @@ tree_redirect_edge_and_branch (edge e, basic_block dest) if (!stmt || !stmt_ends_bb_p (stmt)) { - if (bb->succ->succ_next - || !(e->flags & EDGE_FALLTHRU)) + if (!(e->flags & EDGE_FALLTHRU)) abort (); if (old) @@ -926,9 +941,15 @@ tree_redirect_edge_and_branch (edge e, basic_block dest) redirect: if (old) - remove_edge (e); + ssa_remove_edge (e); else - redirect_edge_succ (e, dest); + { + tree phi; + + for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi)) + remove_phi_arg (phi, e->src); + redirect_edge_succ (e, dest); + } tree_cleanup_block_edges (bb, false); return true; } @@ -1023,7 +1044,6 @@ cleanup_tree_cfg (int expensive) if (expensive) { remove_superfluous_labels (); - remove_useless_stmts_and_vars (); thread_jumps (); } delete_unreachable_blocks (); @@ -1128,6 +1148,7 @@ tree_merge_blocks (basic_block a, basic_block b) { block_stmt_iterator bsi; edge e; + tree phi, stmt; /* Ensure that b follows a. */ if (a->next_bb != b) @@ -1136,12 +1157,35 @@ tree_merge_blocks (basic_block a, basic_block b) if (!(a->succ->flags & EDGE_FALLTHRU)) abort (); - remove_edge (a->succ); - if (last_stmt (a) && stmt_ends_bb_p (last_stmt (a))) abort (); + /* Turn phi nodes into assignments. */ + bsi = bsi_last (a); + for (phi = phi_nodes (b); phi; phi = TREE_CHAIN (phi)) + { + tree src = PHI_ARG_DEF (phi, 0); + tree dest = PHI_RESULT (phi); + + if (virtual_op_p (SSA_NAME_VAR (dest))) + { + tree vdef; + + stmt = build_empty_stmt (); + get_stmt_ann (stmt); + add_vdef (SSA_NAME_VAR (dest), stmt, NULL); + vdef = VARRAY_TREE (vdef_ops (stmt), 0); + VDEF_RESULT (vdef) = dest; + VDEF_OP (vdef) = src; + } + else + stmt = build (MODIFY_EXPR, TREE_TYPE (dest), dest, src); + + SSA_NAME_DEF_STMT (dest) = stmt; + bsi_insert_after (&bsi, stmt, BSI_NEW_STMT); + } + /* Remove labels from B and set bb_for_stmt to A for other statements. */ for (bsi = bsi_start (b); !bsi_end_p (bsi);) { @@ -1154,6 +1198,8 @@ tree_merge_blocks (basic_block a, basic_block b) } } + remove_edge (a->succ); + /* Merge the chains. */ if (a->end_tree) a->end_tree->next = b->head_tree; @@ -1172,6 +1218,11 @@ tree_merge_blocks (basic_block a, basic_block b) for (e = a->succ; e; e = e->succ_next) e->src = a; + if (bb_ann (b)->block->entry == b) + abort (); + if (bb_ann (b)->block->exit == b) + bb_ann (b)->block->exit = a; + /* Remove B. */ delete_basic_block (b); } @@ -1185,7 +1236,7 @@ bsi_remove (block_stmt_iterator *i) bsi_next (i); - remove_stmt (cell); + remove_stmt (cell, i->bb); } @@ -1202,19 +1253,15 @@ bsi_replace (block_stmt_iterator bsi, tree stmt) modify_stmt (bsi_stmt (bsi)); } -/* Remove statement CELL. */ +/* Remove statement CELL in basic block BB. */ static void -remove_stmt (tree_cell cell) +remove_stmt (tree_cell cell, basic_block bb) { varray_type vdefs; size_t i; varray_type defs; tree stmt = cell->stmt; - basic_block bb = bb_for_stmt (cell->stmt); - - if (!bb) - abort (); /* If the statement is a LABEL_EXPR, remove the LABEL_DECL from the symbol table. */ @@ -2588,10 +2635,11 @@ tree_verify_flow_info (void) { basic_block bb; tree_cell stmt, last; - tree t, l, label; + tree t, l, label, phi; block_stmt_iterator si; edge e, le, te, fe; - int err = 0; + struct block_tree *bti; + int err = 0, degree; FOR_EACH_BB (bb) { @@ -2802,8 +2850,84 @@ tree_verify_flow_info (void) default: ; } } + + degree = 0; + for (e = bb->pred; e; e = e->pred_next) + { + if (bb != bb_ann (bb)->block->entry + && (e->flags & EDGE_CONSTRUCT_ENTRY)) + { + fprintf (stderr, + "Construct entry edge not entering construct entry: %d\n", + bb->index); + err = 1; + } + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + if (phi_arg_from_edge (phi, e) < 0) + { + fprintf (stderr, + "No entry for edge in phi node: %d\n", bb->index); + err = 1; + } + degree++; + } + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + if (PHI_NUM_ARGS (phi) != degree) + { + fprintf (stderr, + "Superfluous entries in phi node: %d\n", bb->index); + err = 1; + } } + /* Entry block should have just one successor. Exit block should have + at most one fallthru predecessor. */ + if (!ENTRY_BLOCK_PTR->succ + || ENTRY_BLOCK_PTR->succ->succ_next) + { + fprintf (stderr, "Wrong amount of edges from entry\n"); + err = 1; + } + + if (!(ENTRY_BLOCK_PTR->succ->flags & EDGE_FALLTHRU)) + { + fprintf (stderr, "Entry is not fallthru\n"); + err = 1; + } + + le = NULL; + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) + if (e->flags & EDGE_FALLTHRU) + { + if (le) + { + fprintf (stderr, "More than one fallthru to exit\n"); + err = 1; + break; + } + le = e; + } + + /* Check special edges of constructs. */ + for (bti = bti_start (); !bti_end_p (bti); bti_next (&bti)) + if (bti->entry) + { + le = NULL; + for (e = bti->entry->pred; e; e = e->pred_next) + if (e->flags & EDGE_CONSTRUCT_ENTRY) + { + if (le) + { + fprintf (stderr, "More than one construct %p entry\n", + (void *) bti); + err = 1; + break; + } + le = e; + } + } + return err; } @@ -2928,7 +3052,7 @@ redo: if (e_true->dest == bb->next_bb) { - remove_stmt (bb->end_tree); + bsi_remove (&bsi); e_true->flags |= EDGE_FALLTHRU; } break; @@ -2988,7 +3112,7 @@ redo: || (e->flags & EDGE_ABNORMAL)) continue; - remove_edge (e); + ssa_remove_edge (e); } } @@ -3099,6 +3223,7 @@ void dump_block_tree (FILE *file, int indent, struct block_tree *block) { int i; + tree var; for (i = 0; i < indent; i++) fprintf (file, " "); @@ -3109,6 +3234,15 @@ dump_block_tree (FILE *file, int indent, struct block_tree *block) fprintf (file, " of "); dump_block_tree_id (file, block->of); } + if (block->type == BT_BIND) + { + fprintf (file, " vars"); + for (var = BIND_EXPR_VARS (block->bind); var; var = TREE_CHAIN (var)) + { + fprintf (file, " "); + print_generic_stmt (file, var, 0); + } + } if (block->entry) fprintf (file, " entry %d", block->entry->index); @@ -3294,9 +3428,13 @@ tree_forwarder_block_p (basic_block bb) if (!bb->succ || bb->succ->succ_next || (bb->succ->flags & EDGE_ABNORMAL) + || (bb->succ->flags & EDGE_CONSTRUCT_ENTRY) || bb == ENTRY_BLOCK_PTR) return false; + if (phi_nodes (bb)) + return false; + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) switch (TREE_CODE (bsi_stmt (bsi))) { @@ -3316,9 +3454,11 @@ tree_forwarder_block_p (basic_block bb) static void thread_jumps () { - edge e, next; + edge e, next, last, old; basic_block bb, dest, slow; int set_slow; + tree phi, val1, val2; + int arg; FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb) { @@ -3335,6 +3475,7 @@ thread_jumps () next = e->succ_next; if ((e->flags & EDGE_ABNORMAL) + || (e->flags & EDGE_CONSTRUCT_ENTRY) || e->dest == EXIT_BLOCK_PTR || !tree_forwarder_block_p (e->dest) || e->dest->succ->dest == EXIT_BLOCK_PTR) @@ -3343,8 +3484,10 @@ thread_jumps () slow = e->dest; set_slow = 0; + last = e->dest->succ; for (dest = e->dest->succ->dest; tree_forwarder_block_p (dest); + last = dest->succ, dest = dest->succ->dest, set_slow ^= 1) { @@ -3358,8 +3501,45 @@ thread_jumps () break; } - if (dest != e->dest) - redirect_edge_and_branch (e, dest); + if (dest == e->dest) + continue; + + old = find_edge (bb, dest); + if (old) + { + /* If there already is an edge, check whether the values of + in phi nodes differ. */ + for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi)) + { + val1 = PHI_ARG_DEF (phi, phi_arg_from_edge (phi, last)); + val2 = PHI_ARG_DEF (phi, phi_arg_from_edge (phi, old)); + + if (!operand_equal_p (val1, val2, false)) + break; + } + if (phi) + { + /* The previous block is forwarder, so there are no + phi nodes to update. */ + dest = last->src; + } + } + + if (dest == e->dest) + continue; + + if (redirect_edge_and_branch (e, dest) + && !old) + { + /* Update phi nodes. */ + for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi)) + { + arg = phi_arg_from_edge (phi, last); + if (arg < 0) + abort (); + add_phi_arg (&phi, PHI_ARG_DEF (phi, arg), e); + } + } } } } @@ -3406,7 +3586,7 @@ find_edge_goto (tree stmt, edge e) } /* Removes unneccesary eh statements and variables. */ -static void +void remove_useless_stmts_and_vars () { struct block_tree *bti; @@ -3483,6 +3663,7 @@ merge_seq_blocks () bb->succ && !bb->succ->succ_next && !(bb->succ->flags & EDGE_ABNORMAL) + && !(bb->succ->flags & EDGE_CONSTRUCT_ENTRY) && bb->succ->dest != EXIT_BLOCK_PTR && bb->succ->dest != bb /* That has a single predecessor. */ diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index bfb681f76bf..4eb258bf689 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -128,7 +128,6 @@ static bool may_alias_p (tree, HOST_WIDE_INT, tree, HOST_WIDE_INT); static bool may_access_global_mem_p (tree); static void add_def (tree *, tree); static void add_use (tree *, tree); -static void add_vdef (tree, tree, voperands_t); static void add_stmt_operand (tree *, tree, int, voperands_t); static void add_immediate_use (tree, tree); static tree find_vars_r (tree *, int *, void *); @@ -515,6 +514,48 @@ get_expr_operands (tree stmt, tree *expr_p, int flags, voperands_t prev_vops) abort (); } +/* Checks whether the variable VAR should be accessed via virtual ops. */ +bool +virtual_op_p (tree var) +{ + bool is_scalar; + tree sym; + var_ann_t v_ann; + + is_scalar = (SSA_VAR_P (var) + && !AGGREGATE_TYPE_P (TREE_TYPE (var)) + && TREE_CODE (TREE_TYPE (var)) != COMPLEX_TYPE); + if (!is_scalar) + return true; + + if (!DECL_P (var)) + var = get_virtual_var (var); + + if (var == NULL_TREE || !SSA_VAR_P (var)) + abort (); + + sym = get_base_symbol (var); + v_ann = var_ann (sym); + + if (v_ann->has_hidden_use) + abort (); + + /* Globals, local statics and variables referenced in VA_ARG_EXPR are + always accessed using virtual operands. */ + if (decl_function_context (sym) == 0 + || TREE_STATIC (sym) + || v_ann->is_in_va_arg_expr) + return true; + + /* If the variable is an alias tag, it means that its address has been + taken and it's being accessed directly and via pointers. To avoid + mixing real and virtual operands, we treat all references to aliased + variables as virtual. */ + if (v_ann->is_alias_tag) + return true; + + return false; +} /* Add *VAR_P to the appropriate operand array of STMT. FLAGS is as in get_expr_operands. The following are the rules used to decide @@ -589,18 +630,7 @@ add_stmt_operand (tree *var_p, tree stmt, int flags, voperands_t prev_vops) return; } - /* Globals, local statics and variables referenced in VA_ARG_EXPR are - always accessed using virtual operands. */ - if (decl_function_context (sym) == 0 - || TREE_STATIC (sym) - || v_ann->is_in_va_arg_expr) - flags |= opf_force_vop; - - /* If the variable is an alias tag, it means that its address has been - taken and it's being accessed directly and via pointers. To avoid - mixing real and virtual operands, we treat all references to aliased - variables as virtual. */ - if (v_ann->is_alias_tag) + if (virtual_op_p (var)) flags |= opf_force_vop; aliases = v_ann->may_aliases; @@ -610,10 +640,10 @@ add_stmt_operand (tree *var_p, tree stmt, int flags, voperands_t prev_vops) opf_force_vop is set). */ if (flags & opf_is_def) { - if (is_scalar && !(flags & opf_force_vop)) - add_def (var_p, stmt); - else + if (flags & opf_force_vop) add_vdef (var, stmt, prev_vops); + else + add_def (var_p, stmt); /* If the variable is an alias tag, mark the statement. */ if (v_ann->is_alias_tag) @@ -621,11 +651,10 @@ add_stmt_operand (tree *var_p, tree stmt, int flags, voperands_t prev_vops) } else { - if (is_scalar - && !(flags & opf_force_vop)) - add_use (var_p, stmt); - else + if (flags & opf_force_vop) add_vuse (var, stmt, prev_vops); + else + add_use (var_p, stmt); /* If the variable is an alias tag, mark the statement. */ if (v_ann->is_alias_tag) @@ -725,7 +754,7 @@ add_use (tree *use_p, tree stmt) added here. This is done to preserve the SSA numbering of virtual operands. */ -static void +void add_vdef (tree var, tree stmt, voperands_t prev_vops) { tree vdef; diff --git a/gcc/tree-flatten.c b/gcc/tree-flatten.c index fed357917f5..46f746b75da 100644 --- a/gcc/tree-flatten.c +++ b/gcc/tree-flatten.c @@ -86,9 +86,21 @@ tree_flatten_statement (tree stmt, tree_cell *after, tree enclosing_switch) { case BIND_EXPR: { - append (after, stmt, TCN_BIND); + /* Do not record empty BIND_EXPRs, unless they are top-level ones + (or top-level ones of inlined functions). */ + tree block = BIND_EXPR_BLOCK (stmt); + int record = (BIND_EXPR_VARS (stmt) + || stmt == DECL_SAVED_TREE (current_function_decl) + || (block + && BLOCK_ABSTRACT_ORIGIN (block) + && (TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) + == FUNCTION_DECL))); + + if (record) + append (after, stmt, TCN_BIND); tree_flatten_statement (BIND_EXPR_BODY (stmt), after, enclosing_switch); - append (after, NULL_TREE, TCN_UNBIND); + if (record) + append (after, NULL_TREE, TCN_UNBIND); } break; @@ -377,8 +389,6 @@ static basic_block compact_to_block (struct block_tree *node) { basic_block entry, last, act, next; - edge e; - block_stmt_iterator bsi; if (!node->outer) { @@ -427,40 +437,30 @@ compact_to_block (struct block_tree *node) last = node->exit; } -#ifdef ENABLE_CHECKING - /* The entry block should only be accessed from outside. */ + /* Ensure that the block is entered through its entry edge as + fallthru. */ if (node->entry) { - for (e = entry->pred; e; e = e->pred_next) + edge e; + + for (e = node->entry->pred; e; e = e->pred_next) + if (e->flags & EDGE_CONSTRUCT_ENTRY) + break; + if (e) { - struct block_tree *block = bb_ann (e->src)->block; + if (entry->prev_bb != e->src) + tree_move_block_after (e->src, entry->prev_bb, false); - if (block->level >= node->level) + if (!(e->flags & EDGE_FALLTHRU)) { - while (block->level > node->level) - block = block->outer; - if (block == node) + act = split_edge (e); + tree_move_block_after (act, entry->prev_bb, false); + + if (!(act->succ->flags & EDGE_FALLTHRU)) abort (); } } } -#endif - - /* Ensure that the block is entered through fallthru or abnormal edges. - Do not do this for bind blocks, as it is irrelevant here. */ - if (node->type != BT_BIND - && first_stmt (entry) - && TREE_CODE (first_stmt (entry)) == LABEL_EXPR) - { - for (bsi = bsi_start (entry); !bsi_end_p (bsi); bsi_next (&bsi)) - if (TREE_CODE (bsi_stmt (bsi)) != LABEL_EXPR) - break; - - e = tree_split_block (entry, bsi); - - bb_ann (e->src)->block = node->outer; - entry = e->dest; - } } link_consec_statements (entry, last); diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 89adc9e5717..abb5bfb3478 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -457,6 +457,7 @@ extern void dump_cfg_stats (FILE *); extern void debug_cfg_stats (void); extern void tree_cfg2dot (FILE *); extern void cleanup_tree_cfg (int); +extern void remove_useless_stmts_and_vars (void); extern void remove_phi_nodes_and_edges_for_unreachable_block (basic_block); extern tree first_stmt (basic_block); extern tree last_stmt (basic_block); @@ -505,6 +506,8 @@ extern void dump_alias_info (FILE *); extern void debug_alias_info (void); extern tree get_virtual_var (tree); extern void add_vuse (tree, tree, voperands_t); +extern void add_vdef (tree, tree, voperands_t); +extern bool virtual_op_p (tree); extern void create_global_var (void); /* Flags used when computing reaching definitions and reached uses. */ @@ -545,6 +548,7 @@ void tree_ssa_dce (tree); /* In tree-ssa-copyprop.c */ void tree_ssa_copyprop (tree); void propagate_copy (basic_block, tree *, tree); +void fixup_var_scope (basic_block, tree); /* In tree-flow-inline.h */ diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c index ff4c7b78920..2d0fecfc43f 100644 --- a/gcc/tree-optimize.c +++ b/gcc/tree-optimize.c @@ -98,8 +98,7 @@ optimize_function_tree (tree fndecl) into must-alias relations. If DCE eliminated all the pointer assignments that were taking the address of a local variable X, we can now rename X as a non-aliased local. */ - if (0) - tree_ssa_dce (fndecl); + tree_ssa_dce (fndecl); if (flag_tree_dom && flag_tree_must_alias) tree_compute_must_alias (fndecl); } @@ -113,7 +112,7 @@ optimize_function_tree (tree fndecl) if (flag_tree_copyprop) tree_ssa_copyprop (fndecl); - if (0 && flag_tree_dce) + if (flag_tree_dce) tree_ssa_dce (fndecl); #if defined ENABLE_CHECKING diff --git a/gcc/tree-ssa-copyprop.c b/gcc/tree-ssa-copyprop.c index 232537ab2c6..bc1420ef893 100644 --- a/gcc/tree-ssa-copyprop.c +++ b/gcc/tree-ssa-copyprop.c @@ -214,8 +214,6 @@ get_original (tree var) void propagate_copy (basic_block bb, tree *op_p, tree var) { - struct block_tree *scope, *old_scope; - #if defined ENABLE_CHECKING if (!may_propagate_copy (*op_p, var)) abort (); @@ -233,6 +231,16 @@ propagate_copy (basic_block bb, tree *op_p, tree var) *op_p = var; + fixup_var_scope (bb, var); +} + +/* Moves variable VAR high enough in scope tree so that basic block BB is in + scope. */ +void +fixup_var_scope (basic_block bb, tree var) +{ + struct block_tree *scope, *old_scope; + /* Update scope of var. */ old_scope = var_ann (SSA_NAME_VAR (var))->scope; if (old_scope) diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index b76ca087c8c..80dcd9b5162 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -41,7 +41,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 2. Propagating necessary instructions, e.g., the instructions giving values to operands in necessary instructions; and 3. Removing dead instructions (except replacing dead conditionals - with unconditional jumps). */ + with unconditional jumps). + + Removing of unnecessary conditionals is disabled for now, since + determining control dependence is costly. This usually does not + matter, since cfg cleanup will remove the empty blocks anyway. */ #include "config.h" #include "system.h" @@ -69,8 +73,10 @@ static FILE *dump_file; static int dump_flags; static varray_type worklist; +#if 0 static dominance_info dom_info = NULL; static dominance_info pdom_info = NULL; +#endif static struct stmt_stats { @@ -93,7 +99,9 @@ static void process_worklist (void); static void remove_dead_stmts (void); static void remove_dead_stmt (block_stmt_iterator *, basic_block); static void remove_dead_phis (basic_block); -static void remove_conditional (basic_block) ATTRIBUTE_UNUSED; +#if 0 +static void remove_conditional (basic_block); +#endif /* Is a tree necessary? */ @@ -166,7 +174,6 @@ need_to_preserve_store (tree var) if (var == NULL) return false; - sym = SSA_NAME_VAR (var); base_symbol = get_base_symbol (var); /* File scope variables must be preserved. */ @@ -177,6 +184,7 @@ need_to_preserve_store (tree var) if (TREE_STATIC (base_symbol)) return true; + sym = SSA_NAME_VAR (var); /* If SYM may alias global memory, we also need to preserve the store. */ if (may_alias_global_mem_p (sym)) return true; @@ -224,22 +232,22 @@ stmt_useful_p (tree stmt) size_t i; /* Instructions that are implicitly live. Function calls, asm and return - statements are required. Labels and BIND_EXPR nodes are kept because - they are control flow, and we have no way of knowing whether they can - be removed. DCE can eliminate all the other statements in a block, - and CFG can then remove the block and labels. */ - if ((TREE_CODE (stmt) == ASM_EXPR) + statements are required. Labels are kept because they are control flow, + and we have no way of knowing whether they can be removed. DCE can + eliminate all the other statements in a block, and CFG can then remove the + labels. */ + if ( + /* The first three should be removed if unnecessary condition replacing + is readded. */ + (TREE_CODE (stmt) == COND_EXPR) + || (TREE_CODE (stmt) == SWITCH_EXPR) + || (TREE_CODE (stmt) == GOTO_EXPR) + || (TREE_CODE (stmt) == ASM_EXPR) || (TREE_CODE (stmt) == RETURN_EXPR) - || (TREE_CODE (stmt) == CASE_LABEL_EXPR) || (TREE_CODE (stmt) == LABEL_EXPR) - || (TREE_CODE (stmt) == BIND_EXPR) || (TREE_CODE (stmt) == CALL_EXPR) || ((TREE_CODE (stmt) == MODIFY_EXPR) - && (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)) - || (TREE_CODE (stmt) == TRY_CATCH_EXPR) - || (TREE_CODE (stmt) == TRY_FINALLY_EXPR) - || (TREE_CODE (stmt) == EH_FILTER_EXPR) - || (TREE_CODE (stmt) == CATCH_EXPR)) + && (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR))) return true; /* GOTO_EXPR nodes to nonlocal labels need to be kept (This fixes @@ -253,7 +261,7 @@ stmt_useful_p (tree stmt) if (bb) for (e = bb->succ; e; e = e->succ_next) - if (e->dest == EXIT_BLOCK_PTR && e->flags & EDGE_ABNORMAL) + if (e->dest == EXIT_BLOCK_PTR && (e->flags & EDGE_ABNORMAL)) return true; } @@ -285,15 +293,16 @@ stmt_useful_p (tree stmt) static void process_worklist (void) { + tree i; #if 0 - /* Tries to access parent_block. Disabled until fixed. */ basic_block bb; - tree i, j; + tree j; edge e; bitmap cond_checked, goto_checked; cond_checked = BITMAP_XMALLOC (); goto_checked = BITMAP_XMALLOC (); +#endif while (VARRAY_ACTIVE_SIZE (worklist) > 0) { @@ -308,6 +317,7 @@ process_worklist (void) fprintf (dump_file, "\n"); } +#if 0 /* Find any predecessor which 'goto's this block, and mark the goto as necessary since it is control flow. A block's predecessors only need to be checked once. */ @@ -326,6 +336,7 @@ process_worklist (void) mark_necessary (j); } } +#endif if (TREE_CODE (i) == PHI_NODE) { @@ -340,6 +351,7 @@ process_worklist (void) mark_tree_necessary (SSA_NAME_DEF_STMT (PHI_ARG_DEF (i, k))); } +#if 0 /* Look at all the predecessors, and if this PHI is being fed from a conditional expression, mark that conditional as necessary. Copies may be needed on an edge later. @@ -369,6 +381,7 @@ process_worklist (void) } } } +#endif } else { @@ -405,6 +418,7 @@ process_worklist (void) } } } +#if 0 BITMAP_XFREE (cond_checked); BITMAP_XFREE (goto_checked); #endif @@ -421,16 +435,18 @@ remove_dead_stmts (void) tree t; block_stmt_iterator i; +#if 0 dom_info = NULL; pdom_info = NULL; +#endif - FOR_EACH_BB_REVERSE (bb) + FOR_EACH_BB (bb) { /* Remove dead PHI nodes. */ remove_dead_phis (bb); /* Remove dead statements. */ - for (i = bsi_last (bb); !bsi_end_p (i); bsi_prev (&i)) + for (i = bsi_start (bb); !bsi_end_p (i); ) { t = bsi_stmt (i); stats.total++; @@ -438,15 +454,19 @@ remove_dead_stmts (void) /* If `i' is not in `necessary' then remove from B. */ if (!necessary_p (t)) remove_dead_stmt (&i, bb); + else + bsi_next (&i); } } +#if 0 /* If we needed the dominance info, free it now. */ if (dom_info != NULL) free_dominance_info (dom_info); if (pdom_info != NULL) free_dominance_info (pdom_info); +#endif } @@ -490,11 +510,8 @@ remove_dead_phis (basic_block bb) /* Remove dead statement pointed by iterator I from block BB. */ static void -remove_dead_stmt (block_stmt_iterator *i ATTRIBUTE_UNUSED, - basic_block bb ATTRIBUTE_UNUSED) +remove_dead_stmt (block_stmt_iterator *i, basic_block bb ATTRIBUTE_UNUSED) { -#if 0 - /* Tries to access parent. Disabled until fixed. */ tree t; t = bsi_stmt (*i); @@ -508,27 +525,20 @@ remove_dead_stmt (block_stmt_iterator *i ATTRIBUTE_UNUSED, stats.removed++; +#if 0 /* If we have determined that a conditional branch statement contributes nothing to the program, then we not only remove it, but change the flowgraph so that the block points directly to the immediate post-dominator. The flow graph will remove the blocks we are circumventing, and this block will then simply fall-thru to the post-dominator. This prevents us from having to add any branch - instuctions to replace the conditional statement. - - Only remove a conditional if its parent statement is live. This avoids - unnecessary calls to remove_conditional in the event of dead nested - conditionals. */ + instuctions to replace the conditional statement. */ if (TREE_CODE (t) == COND_EXPR || TREE_CODE (t) == SWITCH_EXPR) - { - tree parent = parent_stmt (t); - if (parent == NULL_TREE || necessary_p (parent)) - remove_conditional (bb); - } + remove_conditional (bb); +#endif bsi_remove (i); -#endif } /* Main routine to eliminate dead code. */ @@ -538,9 +548,6 @@ tree_ssa_dce (tree fndecl) { tree fnbody; - fprintf (stderr, "tree_ssa_dce broken now.\n"); - abort (); - timevar_push (TV_TREE_DCE); memset ((void *) &stats, 0, sizeof (stats)); @@ -567,7 +574,7 @@ tree_ssa_dce (tree fndecl) fprintf (dump_file, "\nEliminating unnecessary instructions:\n"); remove_dead_stmts (); - cleanup_tree_cfg (false); + cleanup_tree_cfg (true); /* Debugging dumps. */ if (dump_file) @@ -583,6 +590,7 @@ tree_ssa_dce (tree fndecl) } +#if 0 /* Remove the conditional statement starting at block BB. */ static void @@ -604,18 +612,10 @@ remove_conditional (basic_block bb) for (e = bb->succ; e; ) { edge tmp = e->succ_next; - /* If the edge BB->PDO_BB exists already, don't remove it. */ - if (e->dest != pdom_bb) - ssa_remove_edge (e); + ssa_remove_edge (e); e = tmp; } - /* If we haven't removed all the edges, there is no need to update the - PHI nodes at PDOM_BB because all the superfluous arguments have been - removed by ssa_remove_edge and we don't need any new arguments. */ - if (bb->succ) - return; - /* If there is no post dominator, then this block is going to the exit node. */ if (pdom_bb == NULL) @@ -636,5 +636,6 @@ remove_conditional (basic_block bb) #endif /* Add an edge to BB's post dominator. */ - make_edge (bb, pdom_bb, EDGE_FALLTHRU); + make_edge (bb, pdom_bb, EDGE_FALLTHRU); } +#endif diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index cc790e7be45..32cf99b7746 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -657,15 +657,8 @@ optimize_stmt (block_stmt_iterator si, varray_type *block_avail_exprs_p) opt_stats.num_re++; if (TREE_CODE (cached_lhs) == SSA_NAME) - { - *expr_p = cached_lhs; - /* This takes care of moving the variable to the right scope. - The assignment above is here so that it indeed looks like - copy propagation. */ - propagate_copy (bb_for_stmt (stmt), expr_p, cached_lhs); - } - else - *expr_p = cached_lhs; + fixup_var_scope (bb_for_stmt (stmt), cached_lhs); + *expr_p = cached_lhs; ann->modified = 1; } } diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 0f491f83f1f..dbe3c23eb88 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -1731,6 +1731,7 @@ rewrite_out_of_ssa (tree fndecl ATTRIBUTE_UNUSED) bsi_commit_edge_inserts (0, NULL); cleanup_tree_cfg (true); + remove_useless_stmts_and_vars (); if (dump_file && (dump_flags & TDF_DETAILS)) dump_tree_cfg (dump_file, dump_flags & ~TDF_DETAILS); diff --git a/gcc/tree.c b/gcc/tree.c index f5ebe6c81c8..4882a55797c 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -5030,6 +5030,7 @@ resize_phi_node (tree *phi, int len) { int size; tree new_phi; + int i, old_len; #ifdef ENABLE_CHECKING if (len < PHI_ARG_CAPACITY (*phi)) @@ -5038,8 +5039,15 @@ resize_phi_node (tree *phi, int len) size = sizeof (struct tree_phi_node) + (len - 1) * sizeof (struct phi_arg_d); new_phi = ggc_realloc (*phi, size); + old_len = PHI_ARG_CAPACITY (new_phi); PHI_ARG_CAPACITY (new_phi) = len; + for (i = old_len; i < len; i++) + { + PHI_ARG_DEF (new_phi, i) = NULL_TREE; + PHI_ARG_EDGE (new_phi, i) = NULL; + } + *phi = new_phi; } |