aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>2003-08-16 21:11:08 +0000
committerZdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>2003-08-16 21:11:08 +0000
commit55439f72ab5ea0f3a4b74f25938470424b629e2a (patch)
tree9d4a315d23e437af2e0de4fab396f24f76b73b5e
parentf73d973a7e9ee26f3255f19d5f0c5475c25423b8 (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-cfg34
-rw-r--r--gcc/basic-block.h3
-rw-r--r--gcc/cfg.c2
-rw-r--r--gcc/tree-cfg.c229
-rw-r--r--gcc/tree-dfa.c71
-rw-r--r--gcc/tree-flatten.c58
-rw-r--r--gcc/tree-flow.h4
-rw-r--r--gcc/tree-optimize.c5
-rw-r--r--gcc/tree-ssa-copyprop.c12
-rw-r--r--gcc/tree-ssa-dce.c99
-rw-r--r--gcc/tree-ssa-dom.c11
-rw-r--r--gcc/tree-ssa.c1
-rw-r--r--gcc/tree.c8
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;
}