OSDN Git Service

Merge from tree-cleanup-branch: VRP, store CCP, store
authordnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 9 Apr 2005 01:37:54 +0000 (01:37 +0000)
committerdnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 9 Apr 2005 01:37:54 +0000 (01:37 +0000)
    copy-prop, incremental SSA updating of FUD chains and
    newly exposed symbols.

* Makefile.in (tree-ssa-copy.o): Depend on tree-ssa-propagate.h.
(OBJS-common): Add tree-vrp.o.
(tree-vrp.o): New rule.
* basic-block.h (nearest_common_dominator_for_set): Declare.
* common.opt (ftree-store-ccp): New flag.
(ftree-copy-prop): New flag.
(ftree-vrp): New flag.
(ftree-store-copy-prop): New flag.
* dominance.c (nearest_common_dominator_for_set): New.
* domwalk.c (walk_dominator_tree): Only traverse
statements in blocks marked in walk_data->interesting_blocks.
* domwalk.h (struct dom_walk_data): Add field interesting_blocks.
* fold-const.c (fold): Handle ASSERT_EXPR.
* opts.c (decode_options): Set flag_tree_copy_prop at -O1.
Set flag_tree_store_ccp, flag_tree_store_copy_prop and
flag_tree_vrp at -O2.
* timevar.def (TV_TREE_VRP): Define.
(TV_TREE_COPY_PROP): Define.
(TV_TREE_STORE_COPY_PROP): Define.
(TV_TREE_SSA_INCREMENTAL): Define.
(TV_TREE_STORE_CCP): Define.
* tree-cfg.c (tree_can_merge_blocks_p): Remove reference
to kill_redundant_phi_nodes from comment.
(verify_expr): Handle ASSERT_EXPR.
* tree-dfa.c (mark_new_vars_to_rename): Remove second
argument.  Update all users.
(mark_call_clobbered_vars_to_rename): Remove.  Update all
users.
* tree-flow-inline.h (unmodifiable_var_p): New.
* tree-flow.h (enum value_range_type): Declare.
(struct value_range_def): Declare.
(value_range): Declare.
(remove_all_phi_nodes_for): Remove.  Update all users.
(find_phi_node_for): Declare.
(add_type_alias): Declare.
(count_uses_and_derefs): Declare.
(kill_redundant_phi_nodes): Remove.
(rewrite_into_ssa): Remove.
(rewrite_def_def_chains): Remove.
(update_ssa, register_new_name_mapping, create_new_def_for,
need_ssa_update_p, name_registered_for_update_p,
release_ssa_name_after_update_ssa, dump_repl_tbl,
debug_repl_tbl, dump_names_replaced_by,
debug_names_replaced_by, mark_sym_for_renaming,
mark_set_for_renaming, get_current_def, set_current_def,
get_value_range, dump_value_range, debug_value_range,
dump_all_value_ranges, debug_all_value_ranges,
expr_computes_nonzero, loop_depth_of_name,
unmodifiable_var_p): Declare.
* tree-gimple.c (is_gimple_formal_tmp_rhs): Handle
ASSERT_EXPR.
* tree-into-ssa.c (block_defs_stack): Update comment.
(old_ssa_names, new_ssa_names, old_virtual_ssa_names,
syms_to_rename, names_to_release, repl_tbl,
need_to_initialize_update_ssa_p, need_to_update_vops_p,
need_to_replace_names_p): New locals.
(NAME_SETS_GROWTH_FACTOR): Define.
(struct repl_map_d): Declare.
(struct mark_def_sites_global_data): Add field
interesting_blocks.
(enum rewrite_mode): Declare.
(REGISTER_DEFS_IN_THIS_STMT): Define.
(compute_global_livein): Use last_basic_block instead of
n_basic_blocks.
(set_def_block): Remove last argument.  Update all callers.
(prepare_use_operand_for_rename): Remove.  Update all callers.
(prepare_def_operand_for_rename): Remove.  Update all callers.
(symbol_marked_for_renaming): New.
(is_old_name): New.
(is_new_name): New.
(repl_map_hash): New.
(repl_map_eq): New.
(repl_map_free): New.
(names_replaced_by): New.
(add_to_repl_tbl): New.
(add_new_name_mapping): New.
(mark_def_sites): Assume that all the operands in the
statement are in normal form.
(find_idf): Assert that the block in the stack is valid.
(get_default_def_for): New.
(insert_phi_nodes_for): Add new argument 'update_p'.
Add documentation.
If update_p is true, add a new mapping between the LHS of
each new PHI and the name that it replaces.
(insert_phi_nodes_1): Only call find_idf if needed.
(get_reaching_def): Call get_default_def_for.
(rewrite_operand): Remove.
(rewrite_stmt): Do nothing if REGISTER_DEFS_IN_THIS_STMT
and REWRITE_THIS_STMT are false.
Assume that all the operands in the statement are in
normal form.
(rewrite_add_phi_arguments): Don't use PHI_REWRITTEN.
(rewrite_virtual_phi_arguments): Remove.
(invalidate_name_tags): Remove.
(register_new_update_single, register_new_update_set,
rewrite_update_init_block, replace_use,
rewrite_update_fini_block, rewrite_update_stmt,
rewrite_update_phi_arguments): New.
rewrite_blocks): Remove argument 'fix_virtual_phis'.
Add arguments 'entry', 'what' and 'blocks'.
Initialize the dominator walker according to 'what' and
'blocks'.
Start the dominator walk at 'entry'.
(mark_def_site_blocks): Add argument 'interesting_blocks'.
Use it to configure the dominator walker.
(rewrite_into_ssa): Remove argument 'all'.
Make internal.
(rewrite_all_into_ssa): Remove.
(rewrite_def_def_chains): Remove.
(mark_def_interesting, mark_use_interesting,
prepare_phi_args_for_update, prepare_block_for_update,
prepare_def_site_for, prepare_def_sites,
dump_names_replaced_by, debug_names_replaced_by,
dump_repl_tbl, debug_repl_tbl, init_update_ssa,
delete_update_ssa, create_new_def_for,
register_new_name_mapping, mark_sym_for_renaming,
mark_set_for_renaming, need_ssa_update_p,
name_registered_for_update_p, ssa_names_to_replace,
release_ssa_name_after_update_ssa,
insert_updated_phi_nodes_for, update_ssa): New.
* tree-loop-linear.c (linear_transform_loops): Call
update_ssa instead of rewrite_into_ssa.
* tree-optimize.c (vars_to_rename): Remove.
Update all users.
(init_tree_optimization_passes): Replace
pass_redundant_phi with pass_copy_prop.
Add pass_vrp.
Replace pass_ccp with pass_store_ccp.
Add pass_store_copy_prop after pass_store_ccp.
(execute_todo): If the TODO_ flags don't include updating
the SSA form, assert that it does not need to be updated.
Call update_ssa instead of rewrite_into_ssa and
rewrite_def_def_chains.
If TODO_verify_loops is set, call verify_loop_closed_ssa.
(tree_rest_of_compilation):
* tree-pass.h (TODO_dump_func, TODO_ggc_collect,
TODO_verify_ssa, TODO_verify_flow, TODO_verify_stmts,
TODO_cleanup_cfg): Renumber.
(TODO_verify_loops, TODO_update_ssa,
TODO_update_ssa_no_phi, TODO_update_ssa_full_phi,
TODO_update_ssa_only_virtuals): Define.
(pass_copy_prop, pass_store_ccp, pass_store_copy_prop, pass_vrp):
Declare.
* tree-phinodes.c (make_phi_node): Update documentation.
(remove_all_phi_nodes_for): Remove.
(find_phi_node_for): New.
* tree-pretty-print.c (dump_generic_node): Handle ASSERT_EXPR.
* tree-scalar-evolution.c (follow_ssa_edge_in_rhs): Likewise.
(interpret_rhs_modify_expr): Likewise.
* tree-sra.c (decide_instantiations): Mark all symbols in
SRA_CANDIDATES for renaming.
(mark_all_v_defs_1): Rename from mark_all_v_defs.
(mark_all_v_defs): New function.  Update all users to call it
with the whole list of scalarized statements, not just the
first one.
* tree-ssa-alias.c (count_ptr_derefs): Make extern.
(compute_flow_insensitive_aliasing): If the tag is
unmodifiable and the variable isn't or vice-versa, don't
make them alias of each other.
(setup_pointers_and_addressables): If the type tag for
VAR is about to change, mark the old one for renaming.
(add_type_alias): New.
* tree-ssa-ccp.c: Document SSA-CCP and STORE-CCP.
(ccp_lattice_t): Rename from latticevalue.
(value): Remove.  Update all users.
(const_val): New local variable.
(do_store_ccp): New local variable.
(dump_lattice_value): Handle UNINITIALIZED.
(debug_lattice_value): New.
(get_default_value): Re-write.
(set_lattice_value): Re-write.
(def_to_varying): Remove.  Update all users.
(likely_value): Return VARYING for statements that make
stores when STORE_CCP is false.
Return VARYING for any statement other than MODIFY_EXPR,
COND_EXPR and SWITCH_EXPR.
(ccp_initialize): Re-write.
(replace_uses_in, replace_vuse_in, substitute_and_fold):
Move to tree-ssa-propagate.c.
(ccp_lattice_meet): Handle memory stores when
DO_STORE_CCP is true.
(ccp_visit_phi_node): Likewise.
(ccp_fold): Likewise.
(evaluate_stmt): Likewise.
(visit_assignment): Likewise.
(ccp_visit_stmt): Likewise.
(execute_ssa_ccp): Add argument 'store_ccp'.  Copy it
into DO_STORE_CCP.
(do_ssa_ccp): New.
(pass_ccp): Use it.
(do_ssa_store_ccp): New.
(gate_store_ccp): New.
(pass_store_ccp): Declare.
* tree-ssa-copy.c: Include tree-ssa-propagate.h.
(may_propagate_copy): Reformat.
Don't abort if ORIG is a virtual and DEST isn't.
If NEW does not have alias information but DEST does,
copy it.
(copy_of, cached_last_copy_of, do_store_copy_prop, enum
copy_prop_kind, which_copy_prop): Declare.
(stmt_may_generate_copy, get_copy_of_val,
get_last_copy_of, set_copy_of_val, dump_copy_of,
copy_prop_visit_assignment, copy_prop_visit_cond_stmt,
copy_prop_visit_stmt, copy_prop_visit_phi_node,
init_copy_prop, fini_copy_prop, execute_copy_prop,
gate_copy_prop, do_copy_prop, gate_store_copy_prop,
store_copy_prop): New.
(pass_copy_prop, pass_store_copy_prop): Declare.
* tree-ssa-dom.c (struct opt_stats_d): Add fields
'num_const_prop' and 'num_copy_prop'.
(cprop_operand): Update them.
(dump_dominator_optimization_stats): Dump them.
(tree_ssa_dominator_optimize): Call update_ssa instead of
rewrite_into_ssa.
(loop_depth_of_name): Declare extern.
(simplify_cond_and_lookup_avail_expr): Guard against NULL
values for LOW or HIGH.
(cprop_into_successor_phis): Only propagate if NEW != ORIG.
(record_equivalences_from_stmt): Call expr_computes_nonzero.
(cprop_operand): Only propagate if VAL != OP.
* tree-ssa-dse.c (dse_optimize_stmt): Mark symbols in removed
statement for renaming.
* tree-ssa-loop-im.c (move_computations): Call update_ssa.
* tree-ssa-loop-ivopts.c (rewrite_address_base): Call
add_type_alias if necessary.
Call mark_new_vars_to_rename.
(tree_ssa_iv_optimize): If new symbols need to be renamed,
mark every statement updated, call update_ssa and
rewrite_into_loop_closed_ssa.
* tree-ssa-loop-manip.c (add_exit_phis): Do not remove DEF_BB
from LIVEIN if VAR is a virtual.
* tree-ssa-loop.c (tree_loop_optimizer_init): Call update_ssa.
* tree-ssa-operands.c (get_expr_operands): Handle ASSERT_EXPR.
(get_call_expr_operands): Reformat statement.
(add_stmt_operand): Don't create V_MAY_DEFs for read-only
symbols.
* tree-ssa-propagate.c (ssa_prop_init): Initialize
SSA_NAME_VALUE for every name.
(first_vdef, stmt_makes_single_load, stmt_makes_single_store,
get_value_loaded_by): New.
(replace_uses_in, replace_vuses_in, replace_phi_args_in,
substitute_and_fold): Move from tree-ssa-ccp.c.
* tree-ssa-propagate.h (struct prop_value_d, prop_value_t,
first_vdef, stmt_makes_single_load, stmt_makes_single_store,
get_value_loaded_by, replace_uses_in, substitute_and_fold):
Declare.
* tree-ssa.c (verify_use): Fix error message.
(propagate_into_addr, replace_immediate_uses, get_eq_name,
check_phi_redundancy, kill_redundant_phi_nodes,
pass_redundant_phi): Remove.  Update all users.
* tree-vect-transform.c (vect_create_data_ref_ptr): Call
add_type_alias, if necessary.
* tree-vectorizer.h (struct _stmt_vect_info): Update
documentation for field 'memtag'.
* tree-vrp.c: New file.
* tree.def (ASSERT_EXPR): Define.
* tree.h (ASSERT_EXPR_VAR): Define.
(ASSERT_EXPR_COND): Define.
(SSA_NAME_VALUE_RANGE): Define.
(struct tree_ssa_name): Add field 'value_range'.
(PHI_REWRITTEN): Remove.
(struct tree_phi_node): Remove field 'rewritten'.
* doc/invoke.texi (-fdump-tree-storeccp, -ftree-copy-prop,
-ftree-store-copy-prop): Document.
* doc/tree-ssa.texi: Remove broken link to McCAT's compiler.
Document usage of update_ssa.

testsuite/ChangeLog

* g++.dg/tree-ssa/pr18178.C: New test.
* gcc.c-torture/execute/20030216-1.x: Ignore at -O1.
* gcc.c-torture/execute/20041019-1.c: New test.
* gcc.dg/tree-ssa/20041008-1.c: New test.
* gcc.dg/tree-ssa/ssa-ccp-12.c: New test.
* gcc.dg/tree-ssa/20030731-2.c: Update to use -fdump-tree-store_ccp.
* gcc.dg/tree-ssa/20030917-1.c: Likewise.
* gcc.dg/tree-ssa/20030917-3.c: Likewise.
* gcc.dg/tree-ssa/20040721-1.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-1.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-2.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-3.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-7.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-9.c: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@97884 138bc75d-0d04-0410-961f-82ee72b054a4

65 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/basic-block.h
gcc/common.opt
gcc/doc/invoke.texi
gcc/doc/tree-ssa.texi
gcc/dominance.c
gcc/domwalk.c
gcc/domwalk.h
gcc/fold-const.c
gcc/opts.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/pr18178.C [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/20030216-1.x [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/20041019-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/20030731-2.c
gcc/testsuite/gcc.dg/tree-ssa/20030917-1.c
gcc/testsuite/gcc.dg/tree-ssa/20030917-3.c
gcc/testsuite/gcc.dg/tree-ssa/20040721-1.c
gcc/testsuite/gcc.dg/tree-ssa/20041008-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-1.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-12.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-3.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-7.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-9.c
gcc/timevar.def
gcc/tree-cfg.c
gcc/tree-complex.c
gcc/tree-dfa.c
gcc/tree-flow-inline.h
gcc/tree-flow.h
gcc/tree-gimple.c
gcc/tree-if-conv.c
gcc/tree-into-ssa.c
gcc/tree-loop-linear.c
gcc/tree-optimize.c
gcc/tree-pass.h
gcc/tree-phinodes.c
gcc/tree-pretty-print.c
gcc/tree-scalar-evolution.c
gcc/tree-sra.c
gcc/tree-ssa-alias.c
gcc/tree-ssa-ccp.c
gcc/tree-ssa-copy.c
gcc/tree-ssa-dce.c
gcc/tree-ssa-dom.c
gcc/tree-ssa-dse.c
gcc/tree-ssa-loop-ch.c
gcc/tree-ssa-loop-im.c
gcc/tree-ssa-loop-ivopts.c
gcc/tree-ssa-loop-manip.c
gcc/tree-ssa-loop.c
gcc/tree-ssa-operands.c
gcc/tree-ssa-phiopt.c
gcc/tree-ssa-propagate.c
gcc/tree-ssa-propagate.h
gcc/tree-ssa-sink.c
gcc/tree-ssa.c
gcc/tree-vect-transform.c
gcc/tree-vectorizer.c
gcc/tree-vectorizer.h
gcc/tree-vrp.c [new file with mode: 0644]
gcc/tree.def
gcc/tree.h

index 269275c..6b7192f 100644 (file)
@@ -1,3 +1,276 @@
+2005-04-08  Diego Novillo  <dnovillo@redhat.com>
+
+       Merge from tree-cleanup-branch: VRP, store CCP, store
+           copy-prop, incremental SSA updating of FUD chains and
+           newly exposed symbols.
+
+       * Makefile.in (tree-ssa-copy.o): Depend on tree-ssa-propagate.h.
+       (OBJS-common): Add tree-vrp.o.
+       (tree-vrp.o): New rule.
+       * basic-block.h (nearest_common_dominator_for_set): Declare.
+       * common.opt (ftree-store-ccp): New flag.
+       (ftree-copy-prop): New flag.
+       (ftree-vrp): New flag.
+       (ftree-store-copy-prop): New flag.
+       * dominance.c (nearest_common_dominator_for_set): New.
+       * domwalk.c (walk_dominator_tree): Only traverse
+       statements in blocks marked in walk_data->interesting_blocks.
+       * domwalk.h (struct dom_walk_data): Add field interesting_blocks.
+       * fold-const.c (fold): Handle ASSERT_EXPR.
+       * opts.c (decode_options): Set flag_tree_copy_prop at -O1.
+       Set flag_tree_store_ccp, flag_tree_store_copy_prop and
+       flag_tree_vrp at -O2.
+       * timevar.def (TV_TREE_VRP): Define.
+       (TV_TREE_COPY_PROP): Define.
+       (TV_TREE_STORE_COPY_PROP): Define.
+       (TV_TREE_SSA_INCREMENTAL): Define.
+       (TV_TREE_STORE_CCP): Define.
+       * tree-cfg.c (tree_can_merge_blocks_p): Remove reference
+       to kill_redundant_phi_nodes from comment.
+       (verify_expr): Handle ASSERT_EXPR.
+       * tree-dfa.c (mark_new_vars_to_rename): Remove second
+       argument.  Update all users.
+       (mark_call_clobbered_vars_to_rename): Remove.  Update all
+       users.
+       * tree-flow-inline.h (unmodifiable_var_p): New.
+       * tree-flow.h (enum value_range_type): Declare.
+       (struct value_range_def): Declare.
+       (value_range): Declare.
+       (remove_all_phi_nodes_for): Remove.  Update all users.
+       (find_phi_node_for): Declare.
+       (add_type_alias): Declare.
+       (count_uses_and_derefs): Declare.
+       (kill_redundant_phi_nodes): Remove.
+       (rewrite_into_ssa): Remove.
+       (rewrite_def_def_chains): Remove.
+       (update_ssa, register_new_name_mapping, create_new_def_for,
+       need_ssa_update_p, name_registered_for_update_p,
+       release_ssa_name_after_update_ssa, dump_repl_tbl,
+       debug_repl_tbl, dump_names_replaced_by,
+       debug_names_replaced_by, mark_sym_for_renaming,
+       mark_set_for_renaming, get_current_def, set_current_def,
+       get_value_range, dump_value_range, debug_value_range,
+       dump_all_value_ranges, debug_all_value_ranges,
+       expr_computes_nonzero, loop_depth_of_name,
+       unmodifiable_var_p): Declare.
+       * tree-gimple.c (is_gimple_formal_tmp_rhs): Handle
+       ASSERT_EXPR.
+       * tree-into-ssa.c (block_defs_stack): Update comment.
+       (old_ssa_names, new_ssa_names, old_virtual_ssa_names,
+       syms_to_rename, names_to_release, repl_tbl,
+       need_to_initialize_update_ssa_p, need_to_update_vops_p,
+       need_to_replace_names_p): New locals.
+       (NAME_SETS_GROWTH_FACTOR): Define.
+       (struct repl_map_d): Declare.
+       (struct mark_def_sites_global_data): Add field
+       interesting_blocks.
+       (enum rewrite_mode): Declare.
+       (REGISTER_DEFS_IN_THIS_STMT): Define.
+       (compute_global_livein): Use last_basic_block instead of
+       n_basic_blocks.
+       (set_def_block): Remove last argument.  Update all callers.
+       (prepare_use_operand_for_rename): Remove.  Update all callers.
+       (prepare_def_operand_for_rename): Remove.  Update all callers.
+       (symbol_marked_for_renaming): New.
+       (is_old_name): New.
+       (is_new_name): New.
+       (repl_map_hash): New.
+       (repl_map_eq): New.
+       (repl_map_free): New.
+       (names_replaced_by): New.
+       (add_to_repl_tbl): New.
+       (add_new_name_mapping): New.
+       (mark_def_sites): Assume that all the operands in the
+       statement are in normal form.
+       (find_idf): Assert that the block in the stack is valid.
+       (get_default_def_for): New.
+       (insert_phi_nodes_for): Add new argument 'update_p'.
+       Add documentation.
+       If update_p is true, add a new mapping between the LHS of
+       each new PHI and the name that it replaces.
+       (insert_phi_nodes_1): Only call find_idf if needed.
+       (get_reaching_def): Call get_default_def_for.
+       (rewrite_operand): Remove.
+       (rewrite_stmt): Do nothing if REGISTER_DEFS_IN_THIS_STMT
+       and REWRITE_THIS_STMT are false.
+       Assume that all the operands in the statement are in
+       normal form.
+       (rewrite_add_phi_arguments): Don't use PHI_REWRITTEN.
+       (rewrite_virtual_phi_arguments): Remove.
+       (invalidate_name_tags): Remove.
+       (register_new_update_single, register_new_update_set,
+       rewrite_update_init_block, replace_use,
+       rewrite_update_fini_block, rewrite_update_stmt,
+       rewrite_update_phi_arguments): New.
+       rewrite_blocks): Remove argument 'fix_virtual_phis'.
+       Add arguments 'entry', 'what' and 'blocks'.
+       Initialize the dominator walker according to 'what' and
+       'blocks'.
+       Start the dominator walk at 'entry'.
+       (mark_def_site_blocks): Add argument 'interesting_blocks'.
+       Use it to configure the dominator walker.
+       (rewrite_into_ssa): Remove argument 'all'.
+       Make internal.
+       (rewrite_all_into_ssa): Remove.
+       (rewrite_def_def_chains): Remove.
+       (mark_def_interesting, mark_use_interesting,
+       prepare_phi_args_for_update, prepare_block_for_update,
+       prepare_def_site_for, prepare_def_sites,
+       dump_names_replaced_by, debug_names_replaced_by,
+       dump_repl_tbl, debug_repl_tbl, init_update_ssa,
+       delete_update_ssa, create_new_def_for,
+       register_new_name_mapping, mark_sym_for_renaming,
+       mark_set_for_renaming, need_ssa_update_p,
+       name_registered_for_update_p, ssa_names_to_replace,
+       release_ssa_name_after_update_ssa,
+       insert_updated_phi_nodes_for, update_ssa): New.
+       * tree-loop-linear.c (linear_transform_loops): Call
+       update_ssa instead of rewrite_into_ssa.
+       * tree-optimize.c (vars_to_rename): Remove.
+       Update all users.
+       (init_tree_optimization_passes): Replace
+       pass_redundant_phi with pass_copy_prop.
+       Add pass_vrp.
+       Replace pass_ccp with pass_store_ccp.
+       Add pass_store_copy_prop after pass_store_ccp.
+       (execute_todo): If the TODO_ flags don't include updating
+       the SSA form, assert that it does not need to be updated.
+       Call update_ssa instead of rewrite_into_ssa and
+       rewrite_def_def_chains.
+       If TODO_verify_loops is set, call verify_loop_closed_ssa.
+       (tree_rest_of_compilation):
+       * tree-pass.h (TODO_dump_func, TODO_ggc_collect,
+       TODO_verify_ssa, TODO_verify_flow, TODO_verify_stmts,
+       TODO_cleanup_cfg): Renumber.
+       (TODO_verify_loops, TODO_update_ssa,
+       TODO_update_ssa_no_phi, TODO_update_ssa_full_phi,
+       TODO_update_ssa_only_virtuals): Define.
+       (pass_copy_prop, pass_store_ccp, pass_store_copy_prop, pass_vrp):
+       Declare.
+       * tree-phinodes.c (make_phi_node): Update documentation.
+       (remove_all_phi_nodes_for): Remove.
+       (find_phi_node_for): New.
+       * tree-pretty-print.c (dump_generic_node): Handle ASSERT_EXPR.
+       * tree-scalar-evolution.c (follow_ssa_edge_in_rhs): Likewise.
+       (interpret_rhs_modify_expr): Likewise.
+       * tree-sra.c (decide_instantiations): Mark all symbols in
+       SRA_CANDIDATES for renaming.
+       (mark_all_v_defs_1): Rename from mark_all_v_defs.
+       (mark_all_v_defs): New function.  Update all users to call it 
+       with the whole list of scalarized statements, not just the
+       first one.
+       * tree-ssa-alias.c (count_ptr_derefs): Make extern.
+       (compute_flow_insensitive_aliasing): If the tag is
+       unmodifiable and the variable isn't or vice-versa, don't
+       make them alias of each other.
+       (setup_pointers_and_addressables): If the type tag for
+       VAR is about to change, mark the old one for renaming.
+       (add_type_alias): New.
+       * tree-ssa-ccp.c: Document SSA-CCP and STORE-CCP.
+       (ccp_lattice_t): Rename from latticevalue.
+       (value): Remove.  Update all users.
+       (const_val): New local variable.
+       (do_store_ccp): New local variable.
+       (dump_lattice_value): Handle UNINITIALIZED.
+       (debug_lattice_value): New.
+       (get_default_value): Re-write.
+       (set_lattice_value): Re-write.
+       (def_to_varying): Remove.  Update all users.
+       (likely_value): Return VARYING for statements that make
+       stores when STORE_CCP is false.
+       Return VARYING for any statement other than MODIFY_EXPR,
+       COND_EXPR and SWITCH_EXPR.
+       (ccp_initialize): Re-write.
+       (replace_uses_in, replace_vuse_in, substitute_and_fold):
+       Move to tree-ssa-propagate.c.
+       (ccp_lattice_meet): Handle memory stores when
+       DO_STORE_CCP is true.
+       (ccp_visit_phi_node): Likewise.
+       (ccp_fold): Likewise.
+       (evaluate_stmt): Likewise.
+       (visit_assignment): Likewise.
+       (ccp_visit_stmt): Likewise.
+       (execute_ssa_ccp): Add argument 'store_ccp'.  Copy it
+       into DO_STORE_CCP.
+       (do_ssa_ccp): New.
+       (pass_ccp): Use it.
+       (do_ssa_store_ccp): New.
+       (gate_store_ccp): New.
+       (pass_store_ccp): Declare.
+       * tree-ssa-copy.c: Include tree-ssa-propagate.h.
+       (may_propagate_copy): Reformat.
+       Don't abort if ORIG is a virtual and DEST isn't.
+       If NEW does not have alias information but DEST does,
+       copy it.
+       (copy_of, cached_last_copy_of, do_store_copy_prop, enum
+       copy_prop_kind, which_copy_prop): Declare.
+       (stmt_may_generate_copy, get_copy_of_val,
+       get_last_copy_of, set_copy_of_val, dump_copy_of,
+       copy_prop_visit_assignment, copy_prop_visit_cond_stmt,
+       copy_prop_visit_stmt, copy_prop_visit_phi_node,
+       init_copy_prop, fini_copy_prop, execute_copy_prop,
+       gate_copy_prop, do_copy_prop, gate_store_copy_prop,
+       store_copy_prop): New.
+       (pass_copy_prop, pass_store_copy_prop): Declare.
+       * tree-ssa-dom.c (struct opt_stats_d): Add fields
+       'num_const_prop' and 'num_copy_prop'.
+       (cprop_operand): Update them.
+       (dump_dominator_optimization_stats): Dump them.
+       (tree_ssa_dominator_optimize): Call update_ssa instead of
+       rewrite_into_ssa.
+       (loop_depth_of_name): Declare extern.
+       (simplify_cond_and_lookup_avail_expr): Guard against NULL
+       values for LOW or HIGH.
+       (cprop_into_successor_phis): Only propagate if NEW != ORIG.
+       (record_equivalences_from_stmt): Call expr_computes_nonzero.
+       (cprop_operand): Only propagate if VAL != OP.
+       * tree-ssa-dse.c (dse_optimize_stmt): Mark symbols in removed
+       statement for renaming.
+       * tree-ssa-loop-im.c (move_computations): Call update_ssa.
+       * tree-ssa-loop-ivopts.c (rewrite_address_base): Call
+       add_type_alias if necessary.
+       Call mark_new_vars_to_rename.
+       (tree_ssa_iv_optimize): If new symbols need to be renamed,
+       mark every statement updated, call update_ssa and
+       rewrite_into_loop_closed_ssa.
+       * tree-ssa-loop-manip.c (add_exit_phis): Do not remove DEF_BB
+       from LIVEIN if VAR is a virtual.
+       * tree-ssa-loop.c (tree_loop_optimizer_init): Call update_ssa.
+       * tree-ssa-operands.c (get_expr_operands): Handle ASSERT_EXPR.
+       (get_call_expr_operands): Reformat statement.
+       (add_stmt_operand): Don't create V_MAY_DEFs for read-only
+       symbols.
+       * tree-ssa-propagate.c (ssa_prop_init): Initialize
+       SSA_NAME_VALUE for every name.
+       (first_vdef, stmt_makes_single_load, stmt_makes_single_store,
+       get_value_loaded_by): New.
+       (replace_uses_in, replace_vuses_in, replace_phi_args_in,
+       substitute_and_fold): Move from tree-ssa-ccp.c.
+       * tree-ssa-propagate.h (struct prop_value_d, prop_value_t,
+       first_vdef, stmt_makes_single_load, stmt_makes_single_store,
+       get_value_loaded_by, replace_uses_in, substitute_and_fold):
+       Declare.
+       * tree-ssa.c (verify_use): Fix error message.
+       (propagate_into_addr, replace_immediate_uses, get_eq_name,
+       check_phi_redundancy, kill_redundant_phi_nodes,
+       pass_redundant_phi): Remove.  Update all users.
+       * tree-vect-transform.c (vect_create_data_ref_ptr): Call
+       add_type_alias, if necessary.
+       * tree-vectorizer.h (struct _stmt_vect_info): Update
+       documentation for field 'memtag'.
+       * tree-vrp.c: New file.
+       * tree.def (ASSERT_EXPR): Define.
+       * tree.h (ASSERT_EXPR_VAR): Define.
+       (ASSERT_EXPR_COND): Define.
+       (SSA_NAME_VALUE_RANGE): Define.
+       (struct tree_ssa_name): Add field 'value_range'.
+       (PHI_REWRITTEN): Remove.
+       (struct tree_phi_node): Remove field 'rewritten'.
+       * doc/invoke.texi (-fdump-tree-storeccp, -ftree-copy-prop,
+       -ftree-store-copy-prop): Document.
+       * doc/tree-ssa.texi: Remove broken link to McCAT's compiler.
+       Document usage of update_ssa.
+
 2005-04-08  David Edelsohn  <edelsohn@gnu.org>
 
        PR target/20814
index 2576739..f115e5d 100644 (file)
@@ -958,7 +958,8 @@ OBJS-common = \
  varasm.o varray.o vec.o version.o vmsdbgout.o xcoffout.o alloc-pool.o    \
  et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o    \
  rtl-profile.o tree-profile.o rtlhooks.o cfgexpand.o lambda-mat.o          \
- lambda-trans.o        lambda-code.o tree-loop-linear.o tree-ssa-sink.o
+ lambda-trans.o lambda-code.o tree-loop-linear.o tree-ssa-sink.o           \
+ tree-vrp.o
 
 OBJS-md = $(out_object_file)
 OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o               \
@@ -1654,7 +1655,7 @@ tree-nrv.o : tree-nrv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 tree-ssa-copy.o : tree-ssa-copy.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
    $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \
    errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
-   $(BASIC_BLOCK_H) tree-pass.h langhooks.h
+   $(BASIC_BLOCK_H) tree-pass.h langhooks.h tree-ssa-propagate.h
 tree-ssa-propagate.o : tree-ssa-propagate.c $(TREE_FLOW_H) $(CONFIG_H) \
    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \
    diagnostic.h errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h \
@@ -1691,6 +1692,10 @@ tree-ssa-pre.o : tree-ssa-pre.c $(TREE_FLOW_H) $(CONFIG_H) \
 tree-vn.o : tree-vn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GGC_H) \
    $(TREE_H) $(TREE_FLOW_H) $(HASHTAB_H) langhooks.h tree-pass.h \
    $(TREE_DUMP_H) diagnostic.h
+tree-vrp.o : tree-vrp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
+   $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) diagnostic.h $(GGC_H) \
+   $(BASIC_BLOCK_H) tree-ssa-propagate.h $(FLAGS_H) $(TREE_DUMP_H) \
+   $(CFGLOOP_H) tree-scalar-evolution.h tree-chrec.h
 tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
    $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
    diagnostic.h errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h \
index a767c6b..0fa8ce5 100644 (file)
@@ -896,6 +896,8 @@ extern void calculate_dominance_info (enum cdi_direction);
 extern void free_dominance_info (enum cdi_direction);
 extern basic_block nearest_common_dominator (enum cdi_direction,
                                             basic_block, basic_block);
+extern basic_block nearest_common_dominator_for_set (enum cdi_direction, 
+                                                    bitmap);
 extern void set_immediate_dominator (enum cdi_direction, basic_block,
                                     basic_block);
 extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
index ae1fe9c..b75785c 100644 (file)
@@ -828,6 +828,10 @@ ftree-ccp
 Common Report Var(flag_tree_ccp)
 Enable SSA-CCP optimization on trees
 
+ftree-store-ccp
+Common Report Var(flag_tree_store_ccp)
+Enable SSA-CCP optimization for stores and loads
+
 ftree-ch
 Common Report Var(flag_tree_ch)
 Enable loop header copying on trees
@@ -840,6 +844,14 @@ ftree-copyrename
 Common Report Var(flag_tree_copyrename)
 Replace SSA temporaries with better names in copies.
 
+ftree-copy-prop
+Common Report Var(flag_tree_copy_prop)
+Enable copy propagation on trees
+
+ftree-store-copy-prop
+Common Report Var(flag_tree_store_copy_prop)
+Enable copy propagation for stores and loads
+
 ftree-dce
 Common Report Var(flag_tree_dce)
 Enable SSA dead code elimination optimization on trees
@@ -896,6 +908,10 @@ ftree-lrs
 Common Report Var(flag_tree_live_range_split)
 Perform live range splitting during the SSA->normal pass.
 
+ftree-vrp
+Common Report Var(flag_tree_vrp) Init(0)
+Perform Value Range Propagation on trees
+
 funit-at-a-time
 Common Report Var(flag_unit_at_a_time)
 Compile whole compilation unit at a time
index e36aa3a..8a1cfbb 100644 (file)
@@ -269,6 +269,7 @@ Objective-C and Objective-C++ Dialects}.
 -fdump-tree-salias @gol
 -fdump-tree-fre@r{[}-@var{n}@r{]} @gol
 -ftree-vectorizer-verbose=@var{n} @gol
+-fdump-tree-storeccp@r{[}-@var{n}@r{]} @gol
 -feliminate-dwarf2-dups -feliminate-unused-debug-types @gol
 -feliminate-unused-debug-symbols -fmem-report -fprofile-arcs -ftree-based-profiling @gol
 -frandom-seed=@var{string} -fsched-verbose=@var{n} @gol
@@ -324,6 +325,7 @@ Objective-C and Objective-C++ Dialects}.
 -ftree-dominator-opts -ftree-dse -ftree-copyrename -ftree-sink @gol
 -ftree-ch -ftree-sra -ftree-ter -ftree-lrs -ftree-fre -ftree-vectorize @gol
 -ftree-salias -fweb @gol
+-ftree-copy-prop -ftree-store-ccp -ftree-store-copy-prop @gol
 --param @var{name}=@var{value}
 -O  -O0  -O1  -O2  -O3  -Os}
 
@@ -3879,6 +3881,11 @@ appending @file{.alias} to the source file name.
 Dump each function after CCP@.  The file name is made by appending
 @file{.ccp} to the source file name.
 
+@item storeccp
+@opindex fdump-tree-storeccp
+Dump each function after STORE-CCP.  The file name is made by appending
+@file{.storeccp} to the source file name.
+
 @item pre
 @opindex fdump-tree-pre
 Dump trees after partial redundancy elimination.  The file name is made
@@ -3889,6 +3896,16 @@ by appending @file{.pre} to the source file name.
 Dump trees after full redundancy elimination.  The file name is made
 by appending @file{.fre} to the source file name.
 
+@item copyprop
+@opindex fdump-tree-copyprop
+Dump trees after copy propagation.  The file name is made
+by appending @file{.copyprop} to the source file name.
+
+@item store_copyprop
+@opindex fdump-tree-store_copyprop
+Dump trees after store copy-propagation.  The file name is made
+by appending @file{.store_copyprop} to the source file name.
+
 @item dce
 @opindex fdump-tree-dce
 Dump each function after dead code elimination.  The file name is made by
@@ -4745,6 +4762,17 @@ that are computed on all paths leading to the redundant computation.
 This analysis faster than PRE, though it exposes fewer redundancies.
 This flag is enabled by default at @option{-O} and higher.
 
+@item -ftree-copy-prop
+Perform copy propagation on trees.  This pass eliminates unnecessary
+copy operations.  This flag is enabled by default at @option{-O} and
+higher.
+
+@item -ftree-store-copy-prop
+Perform copy propagation of memory loads and stores.  This pass
+eliminates unnecessary copy operations in memory references
+(structures, global variables, arrays, etc).  This flag is enabled by
+default at @option{-O2} and higher.
+
 @item -ftree-salias
 Perform structural alias analysis on trees.  This flag
 is enabled by default at @option{-O} and higher.
@@ -4754,8 +4782,15 @@ Perform forward store motion  on trees.  This flag is
 enabled by default at @option{-O} and higher.
 
 @item -ftree-ccp
-Perform sparse conditional constant propagation (CCP) on trees.  This flag
-is enabled by default at @option{-O} and higher.
+Perform sparse conditional constant propagation (CCP) on trees.  This
+pass only operates on local scalar variables and is enabled by default
+at @option{-O} and higher.
+
+@item -ftree-store-ccp
+Perform sparse conditional constant propagation (CCP) on trees.  This
+pass operates on both local scalar variables and memory stores and
+loads (global variables, structures, arrays, etc).  This flag is
+enabled by default at @option{-O2} and higher.
 
 @item -ftree-dce
 Perform dead code elimination (DCE) on trees.  This flag is enabled by
index 27e0d34..d4cf838 100644 (file)
@@ -83,8 +83,7 @@ perfectly happy to take it as input and spit out GIMPLE@.
 
 GIMPLE is a simplified subset of GENERIC for use in optimization.  The
 particular subset chosen (and the name) was heavily influenced by the
-SIMPLE IL used by the McCAT compiler project at McGill University
-(@uref{http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html}),
+SIMPLE IL used by the McCAT compiler project at McGill University,
 though we have made some different choices.  For one thing, SIMPLE
 doesn't support @code{goto}; a production compiler can't afford that
 kind of restriction.
@@ -1111,18 +1110,129 @@ Returns the @code{SSA_NAME} for the @var{i}th argument of @var{phi}.
 
 
 @subsection Preserving the SSA form
-@findex vars_to_rename
+@findex update_ssa
 @cindex preserving SSA form
 Some optimization passes make changes to the function that
 invalidate the SSA property.  This can happen when a pass has
-added new variables or changed the program so that variables that
-were previously aliased aren't anymore.
-
-Whenever something like this happens, the affected variables must
-be renamed into SSA form again.  To do this, you should mark the
-new variables in the global bitmap @code{vars_to_rename}.  Once
-your pass has finished, the pass manager will invoke the SSA
-renamer to put the program into SSA once more.
+added new symbols or changed the program so that variables that
+were previously aliased aren't anymore.  Whenever something like this
+happens, the affected symbols must be renamed into SSA form again.  
+Transformations that emit new code or replicate existing statements
+will also need to update the SSA form@.
+
+Since GCC implements two different SSA forms for register and virtual
+variables, keeping the SSA form up to date depends on whether you are
+updating register or virtual names.  In both cases, the general idea
+behind incremental SSA updates is similar: when new SSA names are
+created, they typically are meant to replace other existing names in
+the program@.
+
+For instance, given the following code:
+
+@smallexample
+     1 L0:
+     2 x_1 = PHI (0, x_5)
+     3 if (x_1 < 10)
+     4   if (x_1 > 7)
+     5     y_2 = 0
+     6   else
+     7     y_3 = x_1 + x_7
+     8   endif
+     9   x_5 = x_1 + 1
+     10   goto L0;
+     11        endif
+@end smallexample
+
+Suppose that we insert new names @code{x_10} and @code{x_11} (lines
+@code{4} and @code{8})@.
+
+@smallexample
+     1 L0:
+     2 x_1 = PHI (0, x_5)
+     3 if (x_1 < 10)
+     4   x_10 = ...
+     5   if (x_1 > 7)
+     6     y_2 = 0
+     7   else
+     8     x_11 = ...
+     9     y_3 = x_1 + x_7
+     10          endif
+     11          x_5 = x_1 + 1
+     12          goto L0;
+     13        endif
+@end smallexample
+
+We want to replace all the uses of @code{x_1} with the new definitions
+of @code{x_10} and @code{x_11}.  Note that the only uses that should
+be replaced are those at lines @code{5}, @code{9} and @code{11}.
+Also, the use of @code{x_7} at line @code{9} should @emph{not} be
+replaced (this is why we cannot just mark symbol @code{x} for
+renaming)@.
+
+Additionally, we may need to insert a PHI node at line @code{11}
+because that is a merge point for @code{x_10} and @code{x_11}.  So the
+use of @code{x_1} at line @code{11} will be replaced with the new PHI
+node.  The insertion of PHI nodes is optional.  They are not strictly
+necessary to preserve the SSA form, and depending on what the caller
+inserted, they may not even be useful for the optimizers@.
+
+Updating the SSA form is a two step process.  First, the pass has to
+identify which names need to be updated and/or which symbols need to
+be renamed into SSA form for the first time.  When new names are
+introduced to replace existing names in the program, the mapping
+between the old and the new names are registered by calling
+@code{register_new_name_mapping} (note that if your pass creates new
+code by duplicating basic blocks, the call to @code{tree_duplicate_bb}
+will set up the necessary mappings automatically).  On the other hand,
+if your pass exposes a new symbol that should be put in SSA form for
+the first time, the new symbol should be registered with
+@code{mark_sym_for_renaming}.
+
+After the replacement mappings have been registered and new symbols
+marked for renaming, a call to @code{update_ssa} makes the registered
+changes.  This can be done with an explicit call or by creating
+@code{TODO} flags in the @code{tree_opt_pass} structure for your pass.
+There are several @code{TODO} flags that control the behaviour of
+@code{update_ssa}:
+
+@itemize @bullet
+@item @code{TODO_update_ssa}.  Update the SSA form inserting PHI nodes
+      for newly exposed symbols and virtual names marked for updating.
+      When updating real names, only insert PHI nodes for a real name
+      @code{O_j} in blocks reached by all the new and old definitions for
+      @code{O_j}.  If the iterated dominance frontier for @code{O_j}
+      is not pruned, we may end up inserting PHI nodes in blocks that
+      have one or more edges with no incoming definition for
+      @code{O_j}.  This would lead to uninitialized warnings for
+      @code{O_j}'s symbol@.
+
+@item @code{TODO_update_ssa_no_phi}.  Update the SSA form without
+      inserting any new PHI nodes at all.  This is used by passes that
+      have either inserted all the PHI nodes themselves or passes that
+      need only to patch use-def and def-def chains for virtuals
+      (e.g., DCE)@.
+
+
+@item @code{TODO_update_ssa_full_phi}.  Insert PHI nodes everywhere
+      they are needed.  No prunning of the IDF is done.  This is used
+      by passes that need the PHI nodes for @code{O_j} even if it
+      means that some arguments will come from the default definition
+      of @code{O_j}'s symbol (e.g., @code{pass_linear_transform})@.
+
+      WARNING: If you need to use this flag, chances are that your
+      pass may be doing something wrong.  Inserting PHI nodes for an
+      old name where not all edges carry a new replacement may lead to
+      silent codegen errors or spurious uninitialized warnings@.
+
+@item @code{TODO_update_ssa_only_virtuals}.  Passes that update the
+      SSA form on their own may want to delegate the updating of
+      virtual names to the generic updater.  Since FUD chains are
+      easier to maintain, this simplifies the work they need to do.
+      NOTE: If this flag is used, any OLD->NEW mappings for real names
+      are explicitly destroyed and only the symbols marked for
+      renaming are processed@.
+@end itemize
+
 
 @subsection Examining @code{SSA_NAME} nodes
 @cindex examining SSA_NAMEs
index d48701d..b07f6c2 100644 (file)
@@ -797,6 +797,27 @@ nearest_common_dominator (enum cdi_direction dir, basic_block bb1, basic_block b
   return et_nca (bb1->dom[dir], bb2->dom[dir])->data;
 }
 
+
+/* Find the nearest common dominator for the basic blocks in BLOCKS,
+   using dominance direction DIR.  */
+
+basic_block
+nearest_common_dominator_for_set (enum cdi_direction dir, bitmap blocks)
+{
+  unsigned i, first;
+  bitmap_iterator bi;
+  basic_block dom;
+  
+  first = bitmap_first_set_bit (blocks);
+  dom = BASIC_BLOCK (first);
+  EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
+    if (dom != BASIC_BLOCK (i))
+      dom = nearest_common_dominator (dir, dom, BASIC_BLOCK (i));
+
+  return dom;
+}
+
+
 /* Return TRUE in case BB1 is dominated by BB2.  */
 bool
 dominated_by_p (enum cdi_direction dir, basic_block bb1, basic_block bb2)
index 15b1dff..87c841b 100644 (file)
@@ -145,6 +145,14 @@ walk_dominator_tree (struct dom_walk_data *walk_data, basic_block bb)
   void *bd = NULL;
   basic_block dest;
   block_stmt_iterator bsi;
+  bool is_interesting;
+
+  /* If block BB is not interesting to the caller, then none of the
+     callbacks that walk the statements in BB are going to be
+     executed.  */
+  is_interesting = bb->index < 0
+                  || walk_data->interesting_blocks == NULL
+                  || TEST_BIT (walk_data->interesting_blocks, bb->index);
 
   /* Callback to initialize the local data structure.  */
   if (walk_data->initialize_block_local_data)
@@ -179,7 +187,7 @@ walk_dominator_tree (struct dom_walk_data *walk_data, basic_block bb)
     (*walk_data->before_dom_children_before_stmts) (walk_data, bb);
 
   /* Statement walk before walking dominator children.  */
-  if (walk_data->before_dom_children_walk_stmts)
+  if (is_interesting && walk_data->before_dom_children_walk_stmts)
     {
       if (walk_data->walk_stmts_backward)
        for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
@@ -211,7 +219,7 @@ walk_dominator_tree (struct dom_walk_data *walk_data, basic_block bb)
     (*walk_data->after_dom_children_before_stmts) (walk_data, bb);
 
   /* Statement walk after walking dominator children.  */
-  if (walk_data->after_dom_children_walk_stmts)
+  if (is_interesting && walk_data->after_dom_children_walk_stmts)
     {
       if (walk_data->walk_stmts_backward)
        for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
index fbf549b..44ea396 100644 (file)
@@ -105,6 +105,14 @@ struct dom_walk_data
 
   /* Stack of available block local structures.  */
   varray_type free_block_data;
+
+  /* Interesting blocks to process.  If this field is not NULL, this
+     set is used to determine which blocks to walk.  If we encounter
+     block I in the dominator traversal, but block I is not present in
+     INTERESTING_BLOCKS, then none of the callback functions are
+     invoked on it.  This is useful when a particular traversal wants
+     to filter out non-interesting blocks from the dominator tree.  */
+  sbitmap interesting_blocks;
 };
 
 void walk_dominator_tree (struct dom_walk_data *, basic_block);
index c59a981..6a84630 100644 (file)
@@ -10005,6 +10005,21 @@ fold (tree expr)
     case CONST_DECL:
       return fold (DECL_INITIAL (t));
 
+    case ASSERT_EXPR:
+      {
+       /* Given ASSERT_EXPR <Y, COND>, return Y if COND can be folded
+          to boolean_true_node.  If COND folds to boolean_false_node,
+          return ASSERT_EXPR <Y, 0>.  Otherwise, return the original
+          expression.  */
+       tree c = fold (ASSERT_EXPR_COND (t));
+       if (c == boolean_true_node)
+         return ASSERT_EXPR_VAR (t);
+       else if (c == boolean_false_node)
+         return build (ASSERT_EXPR, TREE_TYPE (t), ASSERT_EXPR_VAR (t), c);
+       else
+         return t;
+      }
+
     default:
       return t;
     } /* switch (code) */
index bd971c8..70a9b22 100644 (file)
@@ -524,6 +524,7 @@ decode_options (unsigned int argc, const char **argv)
       flag_tree_sra = 1;
       flag_tree_copyrename = 1;
       flag_tree_fre = 1;
+      flag_tree_copy_prop = 1;
       flag_tree_sink = 1;
       flag_tree_salias = 1;
 
@@ -562,6 +563,9 @@ decode_options (unsigned int argc, const char **argv)
       flag_reorder_blocks = 1;
       flag_reorder_functions = 1;
       flag_unit_at_a_time = 1;
+      flag_tree_store_ccp = 1;
+      flag_tree_store_copy_prop = 1;
+      flag_tree_vrp = 1;
 
       if (!optimize_size)
        {
index c8ccbcd..f6f8cef 100644 (file)
@@ -1,3 +1,20 @@
+2005-04-08  Diego Novillo  <dnovillo@redhat.com>
+
+       * g++.dg/tree-ssa/pr18178.C: New test.
+       * gcc.c-torture/execute/20030216-1.x: Ignore at -O1.
+       * gcc.c-torture/execute/20041019-1.c: New test.
+       * gcc.dg/tree-ssa/20041008-1.c: New test.
+       * gcc.dg/tree-ssa/ssa-ccp-12.c: New test.
+       * gcc.dg/tree-ssa/20030731-2.c: Update to use -fdump-tree-store_ccp.
+       * gcc.dg/tree-ssa/20030917-1.c: Likewise.
+       * gcc.dg/tree-ssa/20030917-3.c: Likewise.
+       * gcc.dg/tree-ssa/20040721-1.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-ccp-1.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-ccp-2.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-ccp-3.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-ccp-7.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-ccp-9.c: Likewise.
+
 2005-04-09  Hans-Peter Nilsson  <hp@axis.com>
 
        PR rtl-optimization/20466
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr18178.C b/gcc/testsuite/g++.dg/tree-ssa/pr18178.C
new file mode 100644 (file)
index 0000000..fd1777a
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp" } */
+
+// Define this to see it work.
+// #define WORK_WORK_WORK
+
+#define THIRD
+
+#ifdef THIRD
+#define FIRST  i < 0 || 
+#define ORIG int
+#define CAST
+#else
+
+#define FIRST
+#ifdef WORK_WORK_WORK
+#define ORIG unsigned int
+#define CAST
+#else
+#define ORIG int
+#define CAST (unsigned)
+#endif // WORK_WORK_WORK
+
+#endif // THIRD
+
+struct array
+{
+  const ORIG len;
+  int *data;
+};
+
+extern void call (ORIG);
+
+void doit (array *a)
+{
+  for (ORIG i = 0; i < a->len; ++i)
+    {
+      if (FIRST  CAST (i) >= CAST (a->len))
+       throw 5;
+      call (a->data[i]);
+    }
+}
+
+/* VRP should remove all but 1 if() in the loop.  */
+
+/* { dg-final { scan-tree-dump-times "if " 1 "vrp"} } */
diff --git a/gcc/testsuite/gcc.c-torture/execute/20030216-1.x b/gcc/testsuite/gcc.c-torture/execute/20030216-1.x
new file mode 100644 (file)
index 0000000..a0e03e3
--- /dev/null
@@ -0,0 +1,12 @@
+# This test requires constant propagation of loads and stores to be
+# enabled.  This is only guaranteed at -O2 and higher.  Do not run
+# at -O1.
+
+set torture_eval_before_compile {
+  if {[string match {*-O1*} "$option"]} {
+    continue
+  }
+}
+
+return 0
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/20041019-1.c b/gcc/testsuite/gcc.c-torture/execute/20041019-1.c
new file mode 100644 (file)
index 0000000..3c56b31
--- /dev/null
@@ -0,0 +1,52 @@
+test_store_ccp (int i)
+{
+  int *p, a, b, c;
+
+  if (i < 5)
+    p = &a;
+  else if (i > 8)
+    p = &b;
+  else
+    p = &c;
+
+  *p = 10;
+  b = 3;
+
+  /* STORE-CCP was wrongfully propagating 10 into *p.  */
+  return *p + 2;
+}
+
+
+test_store_copy_prop (int i)
+{
+  int *p, a, b, c;
+
+  if (i < 5)
+    p = &a;
+  else if (i > 8)
+    p = &b;
+  else
+    p = &c;
+
+  *p = i;
+  b = i + 1;
+
+  /* STORE-COPY-PROP was wrongfully propagating i into *p.  */
+  return *p;
+}
+
+
+main()
+{
+  int x;
+  
+  x = test_store_ccp (10);
+  if (x == 12)
+    abort ();
+  
+  x = test_store_copy_prop (9);
+  if (x == 9)
+    abort ();
+
+  return 0;
+}
index 885bca1..9b20581 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-ccp" } */
+/* { dg-options "-O1 -fdump-tree-store_ccp" } */
   
 
 bar (int i, int partial, int args_addr)
@@ -13,5 +13,5 @@ bar (int i, int partial, int args_addr)
 
 /* There should be only one IF conditional since the first does nothing
    useful.  */
-/* { dg-final { scan-tree-dump-times "if " 1 "ccp"} } */
-/* { dg-final { cleanup-tree-dump "ccp" } } */
+/* { dg-final { scan-tree-dump-times "if " 1 "store_ccp"} } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */
index 62f5b24..b7a5450 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-ccp" } */
+/* { dg-options "-O1 -fdump-tree-store_ccp" } */
   
 
 extern int board[];
@@ -15,5 +15,5 @@ findbestextension (int blah, int blah2)
 }
 
 /* The argument to "foo" should be a variable, not a constant.  */
-/* { dg-final { scan-tree-dump-times "foo .defval" 1 "ccp"} } */
-/* { dg-final { cleanup-tree-dump "ccp" } } */
+/* { dg-final { scan-tree-dump-times "foo .defval" 1 "store_ccp"} } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */
index bfa2f8a..2420146 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fno-tree-dominator-opts -fdump-tree-ccp" } */
+/* { dg-options "-O1 -fno-tree-dominator-opts -fdump-tree-store_ccp" } */
 
 extern int printf (const char *, ...); 
 
@@ -20,5 +20,5 @@ main ()
 
 
 /* The argument to "printf" should be a constant, not a variable.  */
-/* { dg-final { scan-tree-dump-times "printf.*, 0" 1 "ccp"} } */
-/* { dg-final { cleanup-tree-dump "ccp" } } */
+/* { dg-final { scan-tree-dump-times "printf.*, 0" 1 "store_ccp"} } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */
index 44dacef..4df313c 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-ccp-vops" } */
+/* { dg-options "-O2 -fdump-tree-store_ccp-vops" } */
 
 /* Test to check whether global variables are being
    constant propagated. */
@@ -24,5 +24,5 @@ main ()
 }
 
 /* There should be no G on the RHS of an assignment. */
-/* { dg-final { scan-tree-dump-times "= G;" 0 "ccp"} } */
-/* { dg-final { cleanup-tree-dump "ccp" } } */
+/* { dg-final { scan-tree-dump-times "= G;" 0 "store_ccp"} } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20041008-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20041008-1.c
new file mode 100644 (file)
index 0000000..ca24427
--- /dev/null
@@ -0,0 +1,38 @@
+/* { dg-do run } */ 
+/* { dg-options "-O2" } */
+
+struct A {
+    int x;
+    int y;
+};
+
+baz (struct A *a)
+{
+  a->x = 3;
+  a->y = 2;
+}
+
+foo (int i)
+{
+  struct A a;
+
+  /* Make sure we can't scalarize 'a'.  */
+  baz (&a);
+
+  if (i > 10)
+    a.x = i;
+  else
+    a.x = i;
+
+  /* Copy propagation should prove that this predicate is always false.  */
+  if (a.x != i)
+    link_error ();
+
+  return a.x;
+}
+
+main ()
+{
+  foo (30);
+  return 0;
+}
index a7d5cd8..259d12a 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */ 
-/* { dg-options "-O1 -fdump-tree-ccp" } */
+/* { dg-options "-O1 -fdump-tree-store_ccp" } */
 
 extern void link_error (void);
 
@@ -71,5 +71,5 @@ void test11111 (int p, int q, int r)
 
 /* There should be not link_error calls, if there is any the
    optimization has failed */
-/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */
-/* { dg-final { cleanup-tree-dump "ccp" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp"} } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-12.c
new file mode 100644 (file)
index 0000000..8ee9eb8
--- /dev/null
@@ -0,0 +1,32 @@
+/* { dg-do run } */ 
+/* { dg-options "-O2" } */
+
+struct A
+{
+  int a;
+  int b;
+};
+
+struct A a;
+const int B = 42;
+
+void foo (int i)
+{
+  if (i > 10)
+    a.a = 42;
+  else
+    {
+      a.b = 21;
+      a.a = a.b + 21;
+    }
+
+  /* This should be folded to 'if (0)' as a.a and B are both 42.  */
+  if (a.a != B)
+    link_error ();
+}
+
+main ()
+{
+  foo (3);
+  return 0;
+}
index aad1a3f..5f614f0 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */ 
-/* { dg-options "-O1 -fdump-tree-ccp" } */
+/* { dg-options "-O1 -fdump-tree-store_ccp" } */
 
 extern void link_error (void);
 
@@ -168,5 +168,5 @@ int test99999 (void)
 
 /* There should be not link_error calls, if there is any the
    optimization has failed */
-/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */
-/* { dg-final { cleanup-tree-dump "ccp" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp"} } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */
index f15ba1e..d978511 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-ccp" } */
+/* { dg-options "-O1 -fdump-tree-store_ccp" } */
 
 extern void link_error (void);
 
@@ -131,5 +131,5 @@ int* test666 (int * __restrict__ rp1, int * __restrict__ rp2, int *p1)
    optimization has failed */
 /* ??? While we indeed don't handle some of these, a couple of the
    restrict tests are incorrect.  */
-/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp" { xfail *-*-* } } } */
-/* { dg-final { cleanup-tree-dump "ccp" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp" { xfail *-*-* } } } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */
index bd97b89..7f20f06 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-ccp" } */
+/* { dg-options "-O1 -fdump-tree-store_ccp" } */
 
 extern void link_error (void);
 
@@ -23,5 +23,5 @@ int test7 (int a)
 
 /* There should be not link_error calls, if there is any the
    optimization has failed */
-/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */
-/* { dg-final { cleanup-tree-dump "ccp" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp"} } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */
index db19b00..1508ff0 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-ccp" } */
+/* { dg-options "-O1 -fdump-tree-store_ccp" } */
 
 /* Check that cprop works for assignments to array elements and structs.  */
 
@@ -51,5 +51,5 @@ test99999 (int *arr, int j)
 
 /* There should be no link_error calls, if there is any, the
    optimization has failed */
-/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */
-/* { dg-final { cleanup-tree-dump "ccp" } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp"} } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */
index 3df7c25..b8d9408 100644 (file)
@@ -65,15 +65,20 @@ DEFTIMEVAR (TV_TREE_GIMPLIFY             , "tree gimplify")
 DEFTIMEVAR (TV_TREE_EH              , "tree eh")
 DEFTIMEVAR (TV_TREE_CFG                     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG             , "tree CFG cleanup")
+DEFTIMEVAR (TV_TREE_VRP              , "tree VRP")
+DEFTIMEVAR (TV_TREE_COPY_PROP        , "tree copy propagation")
+DEFTIMEVAR (TV_TREE_STORE_COPY_PROP  , "tree store copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find referenced vars")
 DEFTIMEVAR (TV_TREE_PTA                     , "tree PTA")
 DEFTIMEVAR (TV_TREE_MAY_ALIAS        , "tree alias analysis")
 DEFTIMEVAR (TV_TREE_INSERT_PHI_NODES , "tree PHI insertion")
 DEFTIMEVAR (TV_TREE_SSA_REWRITE_BLOCKS, "tree SSA rewrite")
 DEFTIMEVAR (TV_TREE_SSA_OTHER       , "tree SSA other")
+DEFTIMEVAR (TV_TREE_SSA_INCREMENTAL  , "tree SSA incremental")
 DEFTIMEVAR (TV_TREE_OPS                     , "tree operand scan")
 DEFTIMEVAR (TV_TREE_SSA_DOMINATOR_OPTS   , "dominator optimization")
 DEFTIMEVAR (TV_TREE_SRA              , "tree SRA")
+DEFTIMEVAR (TV_TREE_STORE_CCP       , "tree STORE-CCP")
 DEFTIMEVAR (TV_TREE_CCP                     , "tree CCP")
 DEFTIMEVAR (TV_TREE_SPLIT_EDGES      , "tree split crit edges")
 DEFTIMEVAR (TV_TREE_PRE                     , "tree PRE")
index bb8e256..38d8215 100644 (file)
@@ -1282,8 +1282,7 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
       && DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)))
     return false;
 
-  /* There may be no phi nodes at the start of b.  Most of these degenerate
-     phi nodes should be cleaned up by kill_redundant_phi_nodes.  */
+  /* There may be no PHI nodes at the start of B.  */
   if (phi_nodes (b))
     return false;
 
@@ -3428,6 +3427,15 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
        }
       break;
 
+    case ASSERT_EXPR:
+      x = fold (ASSERT_EXPR_COND (t));
+      if (x == boolean_false_node)
+       {
+         error ("ASSERT_EXPR with an always-false condition");
+         return *tp;
+       }
+      break;
+
     case MODIFY_EXPR:
       x = TREE_OPERAND (t, 0);
       if (TREE_CODE (x) == BIT_FIELD_REF
index e673aed..74e7465 100644 (file)
@@ -1023,7 +1023,7 @@ struct tree_opt_pass pass_lower_vector_ssa =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_rename_vars    /* todo_flags_finish */
+  TODO_dump_func | TODO_update_ssa     /* todo_flags_finish */
     | TODO_ggc_collect | TODO_verify_ssa
     | TODO_verify_stmts | TODO_verify_flow,
   0                                    /* letter */
index 38d60c0..c923cda 100644 (file)
@@ -215,8 +215,9 @@ make_rename_temp (tree type, const char *prefix)
   if (referenced_vars)
     {
       add_referenced_tmp_var (t);
-      bitmap_set_bit (vars_to_rename, var_ann (t)->uid);
+      mark_sym_for_renaming (t);
     }
+
   return t;
 }
 
@@ -617,11 +618,11 @@ add_referenced_tmp_var (tree var)
 }
 
 
-/* Add all the non-SSA variables found in STMT's operands to the bitmap
-   VARS_TO_RENAME.  */
+/* Mark all the non-SSA variables found in STMT's operands to be
+   processed by update_ssa.  */
 
 void
-mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename)
+mark_new_vars_to_rename (tree stmt)
 {
   ssa_op_iter iter;
   tree val;
@@ -660,13 +661,11 @@ mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename)
   v_must_defs_after = NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt));
 
   FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_ALL_OPERANDS)
-    {
-      if (DECL_P (val))
-       {
-         found_exposed_symbol = true;
-         bitmap_set_bit (vars_to_rename, var_ann (val)->uid);
-       }
-    }
+    if (DECL_P (val))
+      {
+       found_exposed_symbol = true;
+       mark_sym_for_renaming (val);
+      }
 
   /* If we found any newly exposed symbols, or if there are fewer VDEF
      operands in the statement, add the variables we had set in
@@ -676,7 +675,7 @@ mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename)
   if (found_exposed_symbol
       || v_may_defs_before > v_may_defs_after
       || v_must_defs_before > v_must_defs_after)
-    bitmap_ior_into (vars_to_rename, vars_in_vops_to_rename);
+    mark_set_for_renaming (vars_in_vops_to_rename);
 
   BITMAP_FREE (vars_in_vops_to_rename);
 }
@@ -691,7 +690,10 @@ find_new_referenced_vars_1 (tree *tp, int *walk_subtrees,
   tree t = *tp;
 
   if (TREE_CODE (t) == VAR_DECL && !var_ann (t))
-    add_referenced_tmp_var (t);
+    {
+      add_referenced_tmp_var (t);
+      mark_sym_for_renaming (t);
+    }
 
   if (IS_TYPE_OR_DECL_P (t))
     *walk_subtrees = 0;
@@ -706,20 +708,6 @@ find_new_referenced_vars (tree *stmt_p)
 }
 
 
-/* Mark all call-clobbered variables for renaming.  */
-
-void
-mark_call_clobbered_vars_to_rename (void)
-{
-  unsigned i;
-  bitmap_iterator bi;
-  EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
-    {
-      tree var = referenced_var (i);
-      bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
-    }
-}
-
 /* If REF is a COMPONENT_REF for a structure that can have sub-variables, and
    we know where REF is accessing, return the variable in REF that has the
    sub-variables.  If the return value is not NULL, POFFSET will be the
index 169dce2..993c1de 100644 (file)
@@ -1176,6 +1176,17 @@ op_iter_init_maydef (ssa_op_iter *ptr, tree stmt, use_operand_p *use,
   op_iter_next_maydef (use, def, ptr);
 }
 
+/* Return true if VAR cannot be modified by the program.  */
+
+static inline bool
+unmodifiable_var_p (tree var)
+{
+  if (TREE_CODE (var) == SSA_NAME)
+    var = SSA_NAME_VAR (var);
+  return TREE_READONLY (var) && (TREE_STATIC (var) || DECL_EXTERNAL (var));
+}
+
+
 /* Initialize iterator PTR to the operands in STMT.  Return the first operands
    in KILL and DEF.  */
 static inline void
index 00a1af7..eaaa32d 100644 (file)
@@ -80,6 +80,34 @@ struct ptr_info_def GTY(())
 };
 
 
+/* Types of value ranges.  */
+enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING };
+
+
+/* Ranges of values that can be associated with an SSA_NAME after VRP
+   has executed.  */
+struct value_range_def GTY(())
+{
+  /* Lattice value represented by this range.  */
+  enum value_range_type type;
+
+  /* Minimum and maximum values represented by this range.  These
+     values are _CST nodes that should be interpreted as follows:
+
+       - If TYPE == VR_UNDEFINED then MIN and MAX must be NULL.
+
+       - If TYPE == VR_RANGE then MIN holds the minimum value and
+         MAX holds the maximum value of the range [MIN, MAX].
+
+       - If TYPE == ANTI_RANGE the variable is known to NOT
+         take any values in the range [MIN, MAX].  */
+  tree min;
+  tree max;
+};
+
+typedef struct value_range_def value_range;
+
+
 /*---------------------------------------------------------------------------
                   Tree annotations stored in tree_common.ann
 ---------------------------------------------------------------------------*/
@@ -534,7 +562,7 @@ extern tree create_phi_node (tree, basic_block);
 extern void add_phi_arg (tree, tree, edge);
 extern void remove_phi_args (edge);
 extern void remove_phi_node (tree, tree);
-extern void remove_all_phi_nodes_for (bitmap);
+extern tree find_phi_node_for (basic_block, tree, tree *);
 extern tree phi_reverse (tree);
 extern void dump_dfa_stats (FILE *);
 extern void debug_dfa_stats (void);
@@ -544,9 +572,8 @@ extern void dump_variable (FILE *, tree);
 extern void debug_variable (tree);
 extern tree get_virtual_var (tree);
 extern void add_referenced_tmp_var (tree);
-extern void mark_new_vars_to_rename (tree, bitmap);
+extern void mark_new_vars_to_rename (tree);
 extern void find_new_referenced_vars (tree *);
-void mark_call_clobbered_vars_to_rename (void);
 
 extern tree make_rename_temp (tree, const char *);
 
@@ -568,6 +595,8 @@ extern void dump_points_to_info_for (FILE *, tree);
 extern void debug_points_to_info_for (tree);
 extern bool may_be_aliased (tree);
 extern struct ptr_info_def *get_ptr_info (tree);
+extern void add_type_alias (tree, tree);
+extern void count_uses_and_derefs (tree, tree, unsigned *, unsigned *, bool *);
 static inline subvar_t get_subvars_for_var (tree);
 static inline bool ref_contains_array_ref (tree);
 extern tree okay_component_ref_for_subvars (tree, HOST_WIDE_INT *,
@@ -596,24 +625,43 @@ extern void verify_ssa (bool);
 extern void delete_tree_ssa (void);
 extern void register_new_def (tree, VEC (tree_on_heap) **);
 extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
-extern void kill_redundant_phi_nodes (void);
 extern bool stmt_references_memory_p (tree);
 
 /* In tree-into-ssa.c  */
-extern void rewrite_into_ssa (bool);
 extern void rewrite_ssa_into_ssa (void);
-extern void rewrite_def_def_chains (void);
 
+void update_ssa (unsigned);
+void register_new_name_mapping (tree, tree);
+tree create_new_def_for (tree, tree, def_operand_p);
+bool need_ssa_update_p (void);
+bool name_registered_for_update_p (tree);
+bitmap ssa_names_to_replace (void);
+void release_ssa_name_after_update_ssa (tree name);
+void dump_repl_tbl (FILE *);
+void debug_repl_tbl (void);
+void dump_names_replaced_by (FILE *, tree);
+void debug_names_replaced_by (tree);
 void compute_global_livein (bitmap, bitmap);
 tree duplicate_ssa_name (tree, tree);
+void mark_sym_for_renaming (tree);
+void mark_set_for_renaming (bitmap);
 
 /* In tree-ssa-ccp.c  */
 bool fold_stmt (tree *);
 tree widen_bitfield (tree, tree, tree);
 
+/* In tree-vrp.c  */
+value_range *get_value_range (tree);
+void dump_value_range (FILE *, value_range *);
+void debug_value_range (value_range *);
+void dump_all_value_ranges (FILE *);
+void debug_all_value_ranges (void);
+bool expr_computes_nonzero (tree);
+
 /* In tree-ssa-dom.c  */
 extern void dump_dominator_optimization_stats (FILE *);
 extern void debug_dominator_optimization_stats (void);
+int loop_depth_of_name (tree);
 
 /* In tree-ssa-copy.c  */
 extern void propagate_value (use_operand_p, tree);
@@ -711,6 +759,7 @@ extern enum move_pos movement_possibility (tree);
 static inline bool is_call_clobbered (tree);
 static inline void mark_call_clobbered (tree);
 static inline void set_is_used (tree);
+static inline bool unmodifiable_var_p (tree);
 
 /* In tree-eh.c  */
 extern void make_eh_edges (tree);
index 5d1edce..e723b47 100644 (file)
@@ -73,6 +73,7 @@ is_gimple_formal_tmp_rhs (tree t)
     case COMPLEX_CST:
     case VECTOR_CST:
     case OBJ_TYPE_REF:
+    case ASSERT_EXPR:
       return true;
 
     default:
index fe446d9..e63dc66 100644 (file)
@@ -117,7 +117,8 @@ static void add_to_predicate_list (basic_block, tree);
 static tree add_to_dst_predicate_list (struct loop * loop, basic_block, tree, tree,
                                       block_stmt_iterator *);
 static void clean_predicate_lists (struct loop *loop);
-static basic_block find_phi_replacement_condition (basic_block, tree *,
+static basic_block find_phi_replacement_condition (struct loop *loop,
+                                                  basic_block, tree *,
                                                   block_stmt_iterator *);
 static void replace_phi_with_cond_modify_expr (tree, tree, basic_block,
                                                block_stmt_iterator *);
@@ -677,7 +678,8 @@ clean_predicate_lists (struct loop *loop)
    whose phi arguments are selected when cond is true.  */
 
 static basic_block
-find_phi_replacement_condition (basic_block bb, tree *cond,
+find_phi_replacement_condition (struct loop *loop, 
+                               basic_block bb, tree *cond,
                                 block_stmt_iterator *bsi)
 {
   edge e;
@@ -702,12 +704,22 @@ find_phi_replacement_condition (basic_block bb, tree *cond,
   tmp_cond = p1->aux;
   if (TREE_CODE (tmp_cond) == TRUTH_NOT_EXPR)
     {
-      *cond  = p2->aux;
+      /* If p2 is loop->header than its aux field does not have useful
+        info. Instead use !(cond) where cond is p1's aux field.  */
+      if (p2 == loop->header)
+       *cond = invert_truthvalue (unshare_expr (p1->aux));
+      else
+       *cond  = p2->aux;
       true_bb = p2;
     }
   else
     {
-      *cond  = p1->aux;
+      /* If p1 is loop->header than its aux field does not have useful
+        info. Instead use !(cond) where cond is p2's aux field.  */
+      if (p1 == loop->header)
+       *cond = invert_truthvalue (unshare_expr (p2->aux));
+      else
+       *cond  = p1->aux;
       true_bb = p1;
     }
 
@@ -828,7 +840,7 @@ process_phi_nodes (struct loop *loop)
       /* BB has two predecessors. Using predecessor's aux field, set
         appropriate condition for the PHI node replacement.  */
       if (phi)
-       true_bb = find_phi_replacement_condition (bb, &cond, &bsi);
+       true_bb = find_phi_replacement_condition (loop, bb, &cond, &bsi);
 
       while (phi)
        {
@@ -1113,20 +1125,17 @@ gate_tree_if_conversion (void)
 
 struct tree_opt_pass pass_if_conversion =
 {
-  "ifcvt",                           /* name */
-  gate_tree_if_conversion,           /* gate */
-  main_tree_if_conversion,           /* execute */
-  NULL,                              /* sub */
-  NULL,                              /* next */
-  0,                                 /* static_pass_number */
-  0,                                 /* tv_id */
-  PROP_cfg | PROP_ssa | PROP_alias,  /* properties_required */
-  0,                                 /* properties_provided */
-  0,                                 /* properties_destroyed */
-  TODO_dump_func,                    /* todo_flags_start */
-  TODO_dump_func
-    | TODO_verify_ssa
-    | TODO_verify_stmts
-    | TODO_verify_flow,              /* todo_flags_finish */
-  0                                 /* letter */
+  "ifcvt",                             /* name */
+  gate_tree_if_conversion,             /* gate */
+  main_tree_if_conversion,             /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  0,                                   /* tv_id */
+  PROP_cfg | PROP_ssa | PROP_alias,    /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_dump_func | TODO_verify_loops,  /* todo_flags_finish */
+  0                                    /* letter */
 };
index 09e6d1f..f15b5ef 100644 (file)
@@ -84,50 +84,95 @@ struct def_blocks_d
 static htab_t def_blocks;
 
 /* Stack of trees used to restore the global currdefs to its original
-   state after completing rewriting of a block and its dominator children.
+   state after completing rewriting of a block and its dominator
+   children.  Its elements have the following properties:
 
-   This vector is used in two contexts.  The first is rewriting of _DECL
-   nodes into SSA_NAMEs.  In that context its elements have the
-   following properties:
+   - An SSA_NAME indicates that the current definition of the
+     underlying variable should be set to the given SSA_NAME.
 
-     An SSA_NAME indicates that the current definition of the underlying
-     variable should be set to the given SSA_NAME.
+   - A _DECL node indicates that the underlying variable has no
+     current definition.
 
-     A _DECL node indicates that the underlying variable has no current
-     definition.
+   - A NULL node is used to mark the last node associated with the
+     current block.
 
-     A NULL node is used to mark the last node associated with the
-     current block. 
-
-   This vector is also used when rewriting an SSA_NAME which has multiple
-   definition sites into multiple SSA_NAMEs.  In that context entries come
-   in pairs.
-
-     The top entry is an SSA_NAME and the top-1 entry is the
-     current value for that SSA_NAME. 
-
-     A NULL node at the top entry is used to mark the last node associated
-     with the current block.  */
+   - A NULL node at the top entry is used to mark the last node
+     associated with the current block.  */
 static VEC(tree_on_heap) *block_defs_stack;
 
 /* Basic block vectors used in this file ought to be allocated in the heap.  */
 DEF_VEC_MALLOC_P(int);
 
+/* Set of existing SSA names being replaced by update_ssa.  */
+static sbitmap old_ssa_names;
+
+/* Set of new SSA names being added by update_ssa.  Note that both
+   NEW_SSA_NAMES and OLD_SSA_NAMES are dense bitmaps because most of
+   the operations done on them are presence tests.  */
+static sbitmap new_ssa_names;
+
+/* Set of virtual SSA names to be updated.  Since virtuals are always
+   in FUD chain form, these names are not used as a mapping mechanism
+   like OLD_SSA_NAMES and NEW_SSA_NAMES.  Instead, the names in this
+   set are used by ssa_names_to_replace to inform its caller which
+   names are going to be updated.  */
+static bitmap old_virtual_ssa_names;
+
+/* Symbols whose SSA form needs to be updated or created for the first
+   time.  */
+static bitmap syms_to_rename;
+
+/* Set of SSA names that have been marked to be released after they
+   were registered in the replacement table.  They will be finally
+   released after we finish updating the SSA web.  */
+static bitmap names_to_release;
+
+/* Growth factor for NEW_SSA_NAMES and OLD_SSA_NAMES.  These sets need
+   to grow as the callers to register_new_name_mapping will typically
+   create new names on the fly.  FIXME.  Currently set to 1/3 to avoid
+   frequent reallocations but still need to find a reasonable growth
+   strategy.  */
+#define NAME_SETS_GROWTH_FACTOR        (MAX (3, num_ssa_names / 3))
+
+/* Tuple used to represent replacement mappings.  */
+struct repl_map_d
+{
+  tree name;
+  bitmap set;
+};
+
+/* NEW -> OLD_SET replacement table.  If we are replacing several
+   existing SSA names O_1, O_2, ..., O_j with a new name N_i,
+   then REPL_TBL[N_i] = { O_1, O_2, ..., O_j }.  */
+static htab_t repl_tbl;
+
+/* true if register_new_name_mapping needs to initialize the data
+   structures needed by update_ssa.  */
+static bool need_to_initialize_update_ssa_p = true;
+
+/* true if update_ssa needs to update virtual operands.  */
+static bool need_to_update_vops_p = false;
+
+/* true if update_ssa is replacing existing SSA names.  */
+static bool need_to_replace_names_p = false;
+
 /* Global data to attach to the main dominator walk structure.  */
 struct mark_def_sites_global_data
 {
-  /* This sbitmap contains the variables which are set before they
-     are used in a basic block.  We keep it as a global variable
-     solely to avoid the overhead of allocating and deallocating
-     the bitmap.  */
+  /* This bitmap contains the variables which are set before they
+     are used in a basic block.  */
   bitmap kills;
 
   /* Bitmap of names to rename.  */
   sbitmap names_to_rename;
+
+  /* Set of blocks that mark_def_sites deems interesting for the
+     renamer to process.  */
+  sbitmap interesting_blocks;
 };
 
 
-/* Information stored for ssa names.  */
+/* Information stored for SSA names.  */
 struct ssa_name_info
 {
   /* This field indicates whether or not the variable may need PHI nodes.
@@ -140,11 +185,36 @@ struct ssa_name_info
 };
 
 
+/* The main entry point to the SSA renamer (rewrite_blocks) may be
+   called several times to do different, but related, tasks.
+   Initially, we need it to rename the whole program into SSA form.
+   At other times, we may need it to only rename into SSA newly
+   exposed symbols.  Finally, we can also call it to incrementally fix
+   an already built SSA web.  */
+enum rewrite_mode {
+    /* Convert the whole function into SSA form.  */
+    REWRITE_ALL,
+
+    /* Incrementally update the SSA web by replacing existing SSA
+       names with new ones.  See update_ssa for details.  */
+    REWRITE_UPDATE
+};
+
+
 /* Use TREE_VISITED to keep track of which statements we want to
    rename.  When renaming a subset of the variables, not all
    statements will be processed.  This is decided in mark_def_sites.  */
 #define REWRITE_THIS_STMT(T)   TREE_VISITED (T)
 
+/* Use the unsigned flag to keep track of which statements we want to
+   visit when marking new definition sites.  This is slightly
+   different than REWRITE_THIS_STMT: it's used by update_ssa to
+   distinguish statements that need to have both uses and defs
+   processed from those that only need to have their defs processed.
+   Statements that define new SSA names only need to have their defs
+   registered, but they don't need to have their uses renamed.  */
+#define REGISTER_DEFS_IN_THIS_STMT(T)  (T)->common.unsigned_flag
+
 
 /* Get the information associated with NAME.  */
 
@@ -222,7 +292,7 @@ compute_global_livein (bitmap livein, bitmap def_blocks)
   bitmap_iterator bi;
 
   tos = worklist
-    = (basic_block *) xmalloc (sizeof (basic_block) * (n_basic_blocks + 1));
+    = (basic_block *) xmalloc (sizeof (basic_block) * (last_basic_block + 1));
 
   EXECUTE_IF_SET_IN_BITMAP (livein, 0, i, bi)
     {
@@ -288,18 +358,14 @@ get_def_blocks_for (tree var)
 
 
 /* Mark block BB as the definition site for variable VAR.  PHI_P is true if
-   VAR is defined by a PHI node.  IS_UPDATE is true if the caller is
-   updating an existing SSA form.  */
+   VAR is defined by a PHI node.  */
 
 static void
-set_def_block (tree var, basic_block bb, bool phi_p, bool is_update)
+set_def_block (tree var, basic_block bb, bool phi_p)
 {
   struct def_blocks_d *db_p;
   enum need_phi_state state;
 
-  if (!is_update && TREE_CODE (var) == SSA_NAME)
-    var = SSA_NAME_VAR (var);
-
   state = get_phi_state (var);
   db_p = get_def_blocks_for (var);
 
@@ -360,50 +426,170 @@ set_livein_block (tree var, basic_block bb)
 }
 
 
-/* If the use operand pointed to by OP_P needs to be renamed, then strip away 
-   any SSA_NAME wrapping the operand, set *UID_P to the underlying variable's 
-   uid, and return true.  Otherwise return false.  If the operand was an 
-   SSA_NAME, change it to the stripped name.  */
+/* Return true if symbol SYM is marked for renaming.  */
 
-static bool
-prepare_use_operand_for_rename (use_operand_p op_p, size_t *uid_p)
+static inline bool
+symbol_marked_for_renaming (tree sym)
 {
-  tree use = USE_FROM_PTR (op_p);
-  tree var = (TREE_CODE (use) != SSA_NAME) ? use : SSA_NAME_VAR (use);
-  *uid_p = var_ann (var)->uid;
+  gcc_assert (DECL_P (sym));
+  return bitmap_bit_p (syms_to_rename, var_ann (sym)->uid);
+}
+
+
+/* Return true if NAME is in OLD_SSA_NAMES.  */
 
-  /* Ignore variables that don't need to be renamed.  */
-  if (vars_to_rename && !bitmap_bit_p (vars_to_rename, *uid_p))
+static inline bool
+is_old_name (tree name)
+{
+  if (!need_to_replace_names_p)
     return false;
 
-  /* The variable needs to be renamed.  If this is a use which already
-     has an SSA_NAME, then strip it off.
+  return TEST_BIT (old_ssa_names, SSA_NAME_VERSION (name));
+}
+
+
+/* Return true if NAME is in NEW_SSA_NAMES.  */
 
-     By not throwing away SSA_NAMEs on assignments, we avoid a lot of 
-     useless churn of SSA_NAMEs without having to overly complicate the
-     renamer.  */
-  if (TREE_CODE (use) == SSA_NAME)
-    SET_USE (op_p, var);
+static inline bool
+is_new_name (tree name)
+{
+  if (!need_to_replace_names_p)
+    return false;
 
-  return true;
+  return TEST_BIT (new_ssa_names, SSA_NAME_VERSION (name));
 }
 
 
-/* If the def variable DEF needs to be renamed, then strip away any SSA_NAME 
-   wrapping the operand, set *UID_P to the underlying variable's uid and return
-   true.  Otherwise return false.  */
+/* Hashing and equality functions for REPL_TBL.  */
 
-static bool
-prepare_def_operand_for_rename (tree def, size_t *uid_p)
+static hashval_t
+repl_map_hash (const void *p)
 {
-  tree var = (TREE_CODE (def) != SSA_NAME) ? def : SSA_NAME_VAR (def);
-  *uid_p = var_ann (var)->uid;
+  return htab_hash_pointer ((const void *)((const struct repl_map_d *)p)->name);
+}
 
-  /* Ignore variables that don't need to be renamed.  */
-  if (vars_to_rename && !bitmap_bit_p (vars_to_rename, *uid_p))
-    return false;
+static int
+repl_map_eq (const void *p1, const void *p2)
+{
+  return ((const struct repl_map_d *)p1)->name
+        == ((const struct repl_map_d *)p2)->name;
+}
+
+static void
+repl_map_free (void *p)
+{
+  BITMAP_FREE (((struct repl_map_d *)p)->set);
+  free (p);
+}
+
+
+/* Return the names replaced by NEW (i.e., REPL_TBL[NEW].SET).  */
+
+static inline bitmap
+names_replaced_by (tree new)
+{
+  struct repl_map_d m;
+  void **slot;
+
+  m.name = new;
+  slot = htab_find_slot (repl_tbl, (void *) &m, NO_INSERT);
+
+  /* If N was not registered in the replacement table, return NULL.  */
+  if (slot == NULL || *slot == NULL)
+    return NULL;
+
+  return ((struct repl_map_d *) *slot)->set;
+}
+
+
+/* Add OLD to REPL_TBL[NEW].SET.  */
+
+static inline void
+add_to_repl_tbl (tree new, tree old)
+{
+  struct repl_map_d m, *mp;
+  void **slot;
+
+  m.name = new;
+  slot = htab_find_slot (repl_tbl, (void *) &m, INSERT);
+  if (*slot == NULL)
+    {
+      mp = xmalloc (sizeof (*mp));
+      mp->name = new;
+      mp->set = BITMAP_ALLOC (NULL);
+      *slot = (void *) mp;
+    }
+  else
+    mp = (struct repl_map_d *) *slot;
+
+  bitmap_set_bit (mp->set, SSA_NAME_VERSION (old));
+}
+
+
+/* Add a new mapping NEW -> OLD REPL_TBL.  Every entry N_i in REPL_TBL
+   represents the set of names O_1 ... O_j replaced by N_i.  This is
+   used by update_ssa and its helpers to introduce new SSA names in an
+   already formed SSA web.  */
+
+static void
+add_new_name_mapping (tree new, tree old)
+{
+  timevar_push (TV_TREE_SSA_INCREMENTAL);
+
+  /* We may need to grow NEW_SSA_NAMES and OLD_SSA_NAMES because our
+     caller may have created new names since the set was created.  */
+  if (new_ssa_names->n_bits <= num_ssa_names - 1)
+    {
+      unsigned int new_sz = num_ssa_names + NAME_SETS_GROWTH_FACTOR;
+      new_ssa_names = sbitmap_resize (new_ssa_names, new_sz, 0);
+      old_ssa_names = sbitmap_resize (old_ssa_names, new_sz, 0);
+    }
+
+  /* We don't need to keep replacement mappings for virtual names.
+     Since these names are kept in FUD-chain form, we need to traverse
+     the CFG from ENTRY to repair FUD chains.  */
+  if (!is_gimple_reg (new))
+    {
+      tree sym;
+
+      gcc_assert (!is_gimple_reg (old));
+
+      if (DECL_P (old))
+       sym = new;
+      else
+       {
+         sym = SSA_NAME_VAR (old);
+         bitmap_set_bit (old_virtual_ssa_names, SSA_NAME_VERSION (old));
+       }
+
+      mark_sym_for_renaming (sym);
+      need_to_update_vops_p = true;
+
+      timevar_pop (TV_TREE_SSA_INCREMENTAL);
+
+      return;
+    }
+
+  /* Assume that OLD and NEW are different GIMPLE register names.  */
+  gcc_assert (new != old && is_gimple_reg (old));
+
+  /* Update the REPL_TBL table.  */
+  add_to_repl_tbl (new, old);
 
-  return true;
+  /* If OLD had already been registered as a new name, then all the
+     names that OLD replaces should also be replaced by NEW.  */
+  if (is_new_name (old))
+    bitmap_ior_into (names_replaced_by (new), names_replaced_by (old));
+
+  /* Register NEW and OLD in NEW_SSA_NAMES and OLD_SSA_NAMES,
+     respectively.  */
+  SET_BIT (new_ssa_names, SSA_NAME_VERSION (new));
+  SET_BIT (old_ssa_names, SSA_NAME_VERSION (old));
+
+  /* Indicate that we are going to be replacing existing names.  */
+  need_to_replace_names_p = true;
+
+  timevar_pop (TV_TREE_SSA_INCREMENTAL);
 }
 
 
@@ -429,31 +615,27 @@ mark_def_sites (struct dom_walk_data *walk_data,
 {
   struct mark_def_sites_global_data *gd = walk_data->global_data;
   bitmap kills = gd->kills;
-  size_t uid;
   tree stmt, def;
   use_operand_p use_p;
   def_operand_p def_p;
   ssa_op_iter iter;
 
-  /* Mark all the blocks that have definitions for each variable in the
-     VARS_TO_RENAME bitmap.  */
   stmt = bsi_stmt (bsi);
   update_stmt_if_modified (stmt);
 
+  REGISTER_DEFS_IN_THIS_STMT (stmt) = 0;
   REWRITE_THIS_STMT (stmt) = 0;
 
   /* If a variable is used before being set, then the variable is live
      across a block boundary, so mark it live-on-entry to BB.  */
-
   FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter,
                            SSA_OP_USE | SSA_OP_VUSE | SSA_OP_VMUSTDEFKILL)
     {
-      if (prepare_use_operand_for_rename (use_p, &uid))
-       {
-         REWRITE_THIS_STMT (stmt) = 1;
-         if (!bitmap_bit_p (kills, uid))
-           set_livein_block (USE_FROM_PTR (use_p), bb);
-       }
+      tree sym = USE_FROM_PTR (use_p);
+      gcc_assert (DECL_P (sym));
+      if (!bitmap_bit_p (kills, var_ann (sym)->uid))
+       set_livein_block (sym, bb);
+      REWRITE_THIS_STMT (stmt) = 1;
     }
   
   /* Note that virtual definitions are irrelevant for computing KILLS
@@ -463,29 +645,27 @@ mark_def_sites (struct dom_walk_data *walk_data,
      live-on-entry.  */
   FOR_EACH_SSA_MAYDEF_OPERAND (def_p, use_p, stmt, iter)
     {
-      if (prepare_use_operand_for_rename (use_p, &uid))
-       {
-         /* If we do not already have an SSA_NAME for our destination,
-            then set the destination to the source.  */
-         if (TREE_CODE (DEF_FROM_PTR (def_p)) != SSA_NAME)
-           SET_DEF (def_p, USE_FROM_PTR (use_p));
-           
-          set_livein_block (USE_FROM_PTR (use_p), bb);
-         set_def_block (DEF_FROM_PTR (def_p), bb, false, false);
-         REWRITE_THIS_STMT (stmt) = 1;
-       }
+      tree sym = USE_FROM_PTR (use_p);
+      gcc_assert (DECL_P (sym));
+      set_livein_block (sym, bb);
+      set_def_block (sym, bb, false);
+      REGISTER_DEFS_IN_THIS_STMT (stmt) = 1;
+      REWRITE_THIS_STMT (stmt) = 1;
     }
 
   /* Now process the defs and must-defs made by this statement.  */
   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF | SSA_OP_VMUSTDEF)
     {
-      if (prepare_def_operand_for_rename (def, &uid))
-       {
-         set_def_block (def, bb, false, false);
-         bitmap_set_bit (kills, uid);
-         REWRITE_THIS_STMT (stmt) = 1;
-       }
+      gcc_assert (DECL_P (def));
+      set_def_block (def, bb, false);
+      bitmap_set_bit (kills, var_ann (def)->uid);
+      REGISTER_DEFS_IN_THIS_STMT (stmt) = 1;
     }
+
+  /* If we found the statement interesting then also mark the block BB
+     as interesting.  */
+  if (REWRITE_THIS_STMT (stmt) || REGISTER_DEFS_IN_THIS_STMT (stmt))
+    SET_BIT (gd->interesting_blocks, bb->index);
 }
 
 
@@ -525,9 +705,16 @@ find_idf (bitmap def_blocks, bitmap *dfs)
   while (VEC_length (int, work_stack) > 0)
     {
       bb_index = VEC_pop (int, work_stack);
-      
+
+      /* Since the registration of NEW -> OLD name mappings is done
+        separately from the call to update_ssa, when updating the SSA
+        form, the basic blocks where new and/or old names are defined
+        may have disappeared by CFG cleanup calls.  In this case,
+        we may pull a non-existing block from the work stack.  */
+      gcc_assert (bb_index < (unsigned) last_basic_block);
+
       EXECUTE_IF_AND_COMPL_IN_BITMAP (dfs[bb_index], phi_insertion_points,
-                                     0, bb_index, bi)
+                                     0, bb_index, bi)
        {
          /* Use a safe push because if there is a definition of VAR
             in every basic block, then WORK_STACK may eventually have
@@ -556,11 +743,36 @@ find_def_blocks_for (tree var)
 }
 
 
+/* Retrieve or create a default definition for symbol SYM.  */
+
+static inline tree
+get_default_def_for (tree sym)
+{
+  tree ddef = default_def (sym);
+
+  if (ddef == NULL_TREE)
+    {
+      ddef = make_ssa_name (sym, build_empty_stmt ());
+      set_default_def (sym, ddef);
+    }
+
+  return ddef;
+}
+
+
 /* Insert PHI nodes for variable VAR using the iterated dominance
-   frontier given in PHI_INSERTION_POINTS.  */
+   frontier given in PHI_INSERTION_POINTS.  If UPDATE_P is true, this
+   function assumes that the caller is incrementally updating the SSA
+   form, in which case (1) VAR is assumed to be an SSA name, (2) a new
+   SSA name is created for VAR's symbol, and, (3) all the arguments
+   for the newly created PHI node are set to VAR.
+
+   PHI_INSERTION_POINTS is updated to reflect nodes that already had a
+   PHI node for VAR.  On exit, only the nodes that received a PHI node
+   for VAR will be present in PHI_INSERTION_POINTS.  */
 
 static void
-insert_phi_nodes_for (tree var, bitmap phi_insertion_points)
+insert_phi_nodes_for (tree var, bitmap phi_insertion_points, bool update_p)
 {
   unsigned bb_index;
   edge e;
@@ -570,6 +782,7 @@ insert_phi_nodes_for (tree var, bitmap phi_insertion_points)
   struct def_blocks_d *def_map;
 
   def_map = find_def_blocks_for (var);
+  gcc_assert (def_map);
 
   /* Remove the blocks where we already have PHI nodes for VAR.  */
   bitmap_and_compl_into (phi_insertion_points, def_map->phi_blocks);
@@ -585,13 +798,36 @@ insert_phi_nodes_for (tree var, bitmap phi_insertion_points)
       bb = BASIC_BLOCK (bb_index);
       phi = create_phi_node (var, bb);
 
-      /* If we are rewriting SSA names, add also the PHI arguments.  */
       if (TREE_CODE (var) == SSA_NAME)
        {
          edge_iterator ei;
+
+         /* FIXME.  After removing rewrite_ssa_into_ssa, change this
+            if() to gcc_assert().  */
+         if (update_p)
+           {
+             /* If we are rewriting SSA names, create the LHS of the
+                PHI node by duplicating VAR.  This is useful in the
+                case of pointers, to also duplicate pointer
+                attributes (alias information, in particular).  */
+             tree new_lhs = duplicate_ssa_name (var, phi);
+             SET_PHI_RESULT (phi, new_lhs);
+             add_new_name_mapping (new_lhs, var);
+           }
+
+         /* Add VAR to every argument slot of PHI.  We need VAR in
+            every argument so that rewrite_update_phi_arguments knows
+            which name is this PHI node replacing.  If VAR is a
+            symbol marked for renaming, this is not necessary, the
+            renamer will use the symbol on the LHS to get its
+            reaching definition.  */
          FOR_EACH_EDGE (e, ei, bb->preds)
            add_phi_arg (phi, var, e);
        }
+
+      /* Mark this PHI node as interesting for update_ssa.  */
+      REGISTER_DEFS_IN_THIS_STMT (phi) = 1;
+      REWRITE_THIS_STMT (phi) = 1;
     }
 }
 
@@ -609,12 +845,12 @@ insert_phi_nodes_1 (tree var, bitmap *dfs)
   if (def_map == NULL)
     return;
 
-  idf = find_idf (def_map->def_blocks, dfs);
-
   if (get_phi_state (var) != NEED_PHI_STATE_NO)
-    insert_phi_nodes_for (var, idf);
-
-  BITMAP_FREE (idf);
+    {
+      idf = find_idf (def_map->def_blocks, dfs);
+      insert_phi_nodes_for (var, idf, false);
+      BITMAP_FREE (idf);
+    }
 }
 
 
@@ -630,25 +866,17 @@ static void
 insert_phi_nodes (bitmap *dfs, bitmap names_to_rename)
 {
   unsigned i;
-  bitmap_iterator bi;
 
   timevar_push (TV_TREE_INSERT_PHI_NODES);
 
-  /* Iterate over all variables in VARS_TO_RENAME.  For each variable, add
-     to the work list all the blocks that have a definition for the
-     variable.  PHI nodes will be added to the dominance frontier blocks of
-     each definition block.  */
   if (names_to_rename)
     {
+      bitmap_iterator bi;
+
       EXECUTE_IF_SET_IN_BITMAP (names_to_rename, 0, i, bi)
        if (ssa_name (i))
          insert_phi_nodes_1 (ssa_name (i), dfs);
     }
-  else if (vars_to_rename)
-    {
-      EXECUTE_IF_SET_IN_BITMAP (vars_to_rename, 0, i, bi)
-       insert_phi_nodes_1 (referenced_var (i), dfs);
-    }
   else
     {
       for (i = 0; i < num_referenced_vars; i++)
@@ -757,57 +985,23 @@ rewrite_initialize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
 static tree
 get_reaching_def (tree var)
 {
-  tree default_d, currdef_var, avar;
+  tree currdef_var, avar;
   
   /* Lookup the current reaching definition for VAR.  */
-  default_d = NULL_TREE;
   currdef_var = get_current_def (var);
 
   /* If there is no reaching definition for VAR, create and register a
      default definition for it (if needed).  */
   if (currdef_var == NULL_TREE)
     {
-      if (TREE_CODE (var) == SSA_NAME)
-       avar = SSA_NAME_VAR (var);
-      else
-       avar = var;
-
-      default_d = default_def (avar);
-      if (default_d == NULL_TREE)
-       {
-         default_d = make_ssa_name (avar, build_empty_stmt ());
-         set_default_def (avar, default_d);
-       }
-      set_current_def (var, default_d);
+      avar = DECL_P (var) ? var : SSA_NAME_VAR (var);
+      currdef_var = get_default_def_for (avar);
+      set_current_def (var, currdef_var);
     }
 
   /* Return the current reaching definition for VAR, or the default
      definition, if we had to create one.  */
-  return (currdef_var) ? currdef_var : default_d;
-}
-
-
-/* Replace the operand pointed by OP_P with its immediate reaching
-   definition.  */
-
-static inline void
-rewrite_operand (use_operand_p op_p)
-{
-  tree var = USE_FROM_PTR (op_p);
-  if (TREE_CODE (var) != SSA_NAME)
-    SET_USE (op_p, get_reaching_def (var));
-  else
-    {
-#if defined ENABLE_CHECKING
-      /* If we get to this point, VAR is an SSA_NAME.  If VAR's symbol
-        was marked for renaming, make sure that its reaching
-        definition is VAR itself.  Otherwise, something has gone
-        wrong.  */
-      tree sym = SSA_NAME_VAR (var);
-      if (bitmap_bit_p (vars_to_rename, var_ann (sym)->uid))
-       gcc_assert (var == get_reaching_def (SSA_NAME_VAR (var)));
-#endif
-    }
+  return currdef_var;
 }
 
 
@@ -829,7 +1023,7 @@ rewrite_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
 
   /* If mark_def_sites decided that we don't need to rewrite this
      statement, ignore it.  */
-  if (!REWRITE_THIS_STMT (stmt))
+  if (!REWRITE_THIS_STMT (stmt) && !REGISTER_DEFS_IN_THIS_STMT (stmt))
     return;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -839,22 +1033,25 @@ rewrite_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
       fprintf (dump_file, "\n");
     }
 
-  get_stmt_operands (stmt);
-
   /* Step 1.  Rewrite USES and VUSES in the statement.  */
-  FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES | SSA_OP_ALL_KILLS)
-    rewrite_operand (use_p);
+  if (REWRITE_THIS_STMT (stmt))
+    FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter,
+                             SSA_OP_ALL_USES|SSA_OP_ALL_KILLS)
+      {
+       tree var = USE_FROM_PTR (use_p);
+       gcc_assert (DECL_P (var));
+       SET_USE (use_p, get_reaching_def (var));
+      }
 
   /* Step 2.  Register the statement's DEF and VDEF operands.  */
-  FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_ALL_DEFS)
-    {
-      if (TREE_CODE (DEF_FROM_PTR (def_p)) != SSA_NAME)
-       SET_DEF (def_p, make_ssa_name (DEF_FROM_PTR (def_p), stmt));
-
-      /* FIXME: We shouldn't be registering new defs if the variable
-        doesn't need to be renamed.  */
-      register_new_def (DEF_FROM_PTR (def_p), &block_defs_stack);
-    }
+  if (REGISTER_DEFS_IN_THIS_STMT (stmt))
+    FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_ALL_DEFS)
+      {
+       tree var = DEF_FROM_PTR (def_p);
+       gcc_assert (DECL_P (var));
+       SET_DEF (def_p, make_ssa_name (var, stmt));
+       register_new_def (DEF_FROM_PTR (def_p), &block_defs_stack);
+      }
 }
 
 
@@ -877,13 +1074,6 @@ rewrite_add_phi_arguments (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
       for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
        {
          tree currdef;
-
-         /* If this PHI node has already been rewritten, then there is
-            nothing to do for this PHI or any following PHIs since we
-            always add new PHI nodes at the start of the PHI chain.  */
-         if (PHI_REWRITTEN (phi))
-           break;
-
          currdef = get_reaching_def (SSA_NAME_VAR (PHI_RESULT (phi)));
          add_phi_arg (phi, currdef, e);
        }
@@ -891,43 +1081,6 @@ rewrite_add_phi_arguments (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
 }
 
 
-/*  Rewrite existing virtual PHI arguments so that they have the correct
-    reaching definitions.  BB is the basic block whose successors contain the
-    PHI nodes we want to add arguments for.  */
-
-static void
-rewrite_virtual_phi_arguments (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
-                              basic_block bb)
-{
-  edge e;
-  use_operand_p op;
-  edge_iterator ei;
-
-  FOR_EACH_EDGE (e, ei, bb->succs)
-    {
-      tree phi;
-
-      if (e->dest == EXIT_BLOCK_PTR)
-       continue;
-
-      for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
-       {
-         tree result = PHI_RESULT (phi);
-         op = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
-         
-         if (is_gimple_reg (result) 
-             || !bitmap_bit_p (vars_to_rename, 
-                               var_ann (SSA_NAME_VAR (result))->uid))
-           continue;
-
-         SET_USE (op, get_reaching_def (SSA_NAME_VAR (result)));
-         if (e->flags & EDGE_ABNORMAL)
-           SSA_NAME_OCCURS_IN_ABNORMAL_PHI (USE_FROM_PTR (op)) = 1;
-       }
-    }
-}
-
-
 /* Called after visiting basic block BB.  Restore CURRDEFS to its
    original value.  */
 
@@ -1084,115 +1237,402 @@ debug_def_blocks (void)
 }
 
 
-/* If a variable V in VARS_TO_RENAME is a pointer, the renaming
-   process will cause us to lose the name memory tags that may have
-   been associated with the various SSA_NAMEs of V.  This means that
-   the variables aliased to those name tags also need to be renamed
-   again.
+/* Register NEW_NAME to be the new reaching definition for OLD_NAME.  */
 
-   FIXME 1- We should either have a better scheme for renaming
-           pointers that doesn't lose name tags or re-run alias
-           analysis to recover points-to information.
+static inline void
+register_new_update_single (tree new_name, tree old_name)
+{
+  tree currdef = get_current_def (old_name);
 
-        2- Currently we just invalidate *all* the name tags.  This
-           should be more selective.  */
+  /* Push the current reaching definition into *BLOCK_DEFS_P.
+     This stack is later used by the dominator tree callbacks to
+     restore the reaching definitions for all the variables
+     defined in the block after a recursive visit to all its
+     immediately dominated blocks.  */
+  VEC_safe_push (tree_on_heap, block_defs_stack, currdef);
+  VEC_safe_push (tree_on_heap, block_defs_stack, old_name);
 
-static void
-invalidate_name_tags (bitmap vars_to_rename)
-{
-  unsigned i;
-  bool rename_name_tags_p;
-  bitmap_iterator bi;
+  /* Set the current reaching definition for OLD_NAME to be
+     NEW_NAME.  */
+  set_current_def (old_name, new_name);
+}
 
-  rename_name_tags_p = false;
-  EXECUTE_IF_SET_IN_BITMAP (vars_to_rename, 0, i, bi)
-    {
-      if (POINTER_TYPE_P (TREE_TYPE (referenced_var (i))))
-       {
-         rename_name_tags_p = true;
-         break;
-       }
-    }
 
-  if (rename_name_tags_p)
-    for (i = 0; i < num_referenced_vars; i++)
-      {
-       var_ann_t ann = var_ann (referenced_var (i));
+/* Register NEW_NAME to be the new reaching definition for all the
+   names in OLD_NAMES.  Used by the incremental SSA update routines to
+   replace old SSA names with new ones.  */
 
-       if (ann->mem_tag_kind == NAME_TAG)
-         {
-           size_t j;
-           varray_type may_aliases = ann->may_aliases;
+static inline void
+register_new_update_set (tree new_name, bitmap old_names)
+{
+  bitmap_iterator bi;
+  unsigned i;
 
-           bitmap_set_bit (vars_to_rename, ann->uid);
-           if (ann->may_aliases)
-             for (j = 0; j < VARRAY_ACTIVE_SIZE (may_aliases); j++)
-               {
-                 tree var = VARRAY_TREE (may_aliases, j);
-                 bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
-               }
-         }
-      }
+  EXECUTE_IF_SET_IN_BITMAP (old_names, 0, i, bi)
+    register_new_update_single (new_name, ssa_name (i));
 }
 
 
-/* Rewrite the actual blocks, statements, and PHI arguments, to be in SSA
-   form.  FIX_VIRTUAL_PHIS is true if we should only be fixing up virtual
-   PHI arguments, instead of adding new PHI arguments for just added PHI
-   nodes.  */
+/* Initialization of block data structures for the incremental SSA
+   update pass.  Create a block local stack of reaching definitions
+   for new SSA names produced in this block (BLOCK_DEFS).  Register
+   new definitions for every PHI node in the block.  */
 
 static void
-rewrite_blocks (bool fix_virtual_phis)
+rewrite_update_init_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+                          basic_block bb)
 {
-  struct dom_walk_data walk_data;
-  
-  /* Rewrite all the basic blocks in the program.  */
-  timevar_push (TV_TREE_SSA_REWRITE_BLOCKS);
-
-  /* Setup callbacks for the generic dominator tree walker.  */
-  walk_data.walk_stmts_backward = false;
-  walk_data.dom_direction = CDI_DOMINATORS;
-  walk_data.initialize_block_local_data = NULL;
-  walk_data.before_dom_children_before_stmts = rewrite_initialize_block;
-  walk_data.before_dom_children_walk_stmts = rewrite_stmt;
-  walk_data.before_dom_children_after_stmts = NULL;
-  if (!fix_virtual_phis)
-    walk_data.before_dom_children_after_stmts = rewrite_add_phi_arguments;
-  else
-    walk_data.before_dom_children_after_stmts = rewrite_virtual_phi_arguments;
-  
-  walk_data.after_dom_children_before_stmts =  NULL;
-  walk_data.after_dom_children_walk_stmts =  NULL;
-  walk_data.after_dom_children_after_stmts =  rewrite_finalize_block;
-  walk_data.global_data = NULL;
-  walk_data.block_local_data_size = 0;
-
-  block_defs_stack = VEC_alloc (tree_on_heap, 10);
+  edge e;
+  edge_iterator ei;
+  tree phi;
+  bool is_abnormal_phi;
 
-  /* Initialize the dominator walker.  */
-  init_walk_dominator_tree (&walk_data);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "\n\nRegistering new PHI nodes in block #%d\n\n",
+            bb->index);
 
-  /* Recursively walk the dominator tree rewriting each statement in
-     each basic block.  */
-  walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
+  /* Mark the unwind point for this block.  */
+  VEC_safe_push (tree_on_heap, block_defs_stack, NULL_TREE);
 
-  /* Finalize the dominator walker.  */
-  fini_walk_dominator_tree (&walk_data);
+  /* Mark the LHS if any of the arguments flows through an abnormal
+     edge.  */
+  is_abnormal_phi = false;
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    if (e->flags & EDGE_ABNORMAL)
+      {
+       is_abnormal_phi = true;
+       break;
+      }
 
-  /* Debugging dumps.  */
-  if (dump_file && (dump_flags & TDF_STATS))
+  /* If any of the PHI nodes is a replacement for a name in
+     OLD_SSA_NAMES or it's one of the names in NEW_SSA_NAMES, then
+     register it as a new definition for its corresponding name.  Also
+     register definitions for names whose underlying symbols are
+     marked for renaming.  */
+  for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
     {
-      dump_dfa_stats (dump_file);
-      dump_tree_ssa_stats (dump_file);
-    }
+      tree lhs, lhs_sym;
 
-  htab_delete (def_blocks);
-  def_blocks = NULL;
-  
-  VEC_free (tree_on_heap, block_defs_stack);
-  block_defs_stack = NULL;
+      if (!REGISTER_DEFS_IN_THIS_STMT (phi))
+       continue;
+      
+      lhs = PHI_RESULT (phi);
+      lhs_sym = SSA_NAME_VAR (lhs);
 
-  timevar_pop (TV_TREE_SSA_REWRITE_BLOCKS);
+      if (symbol_marked_for_renaming (lhs_sym))
+       register_new_update_single (lhs, lhs_sym);
+      else
+       {
+         /* If LHS is a new name, register a new definition for all
+            the names replaced by LHS.  */
+         if (is_new_name (lhs))
+           register_new_update_set (lhs, names_replaced_by (lhs));
+         
+         /* If LHS is an OLD name, register it as a new definition
+            for itself.  */
+         if (is_old_name (lhs))
+           register_new_update_single (lhs, lhs);
+       }
+
+      if (is_abnormal_phi)
+       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs) = 1;
+    }
+}
+
+
+/* Replace the operand pointed by USE_P with USE's current reaching
+   definition.  */
+
+static inline void
+replace_use (use_operand_p use_p, tree use)
+{
+  tree rdef = get_reaching_def (use);
+  if (rdef != use)
+    SET_USE (use_p, rdef);
+}
+
+
+/* Called after visiting block BB.  Unwind BLOCK_DEFS_STACK to restore
+   the current reaching definition of every name re-written in BB to
+   the original reaching definition before visiting BB.  This
+   unwinding must be done in the opposite order to what is done in
+   register_new_update_set.  */
+
+static void
+rewrite_update_fini_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+                          basic_block bb ATTRIBUTE_UNUSED)
+{
+  while (VEC_length (tree_on_heap, block_defs_stack) > 0)
+    {
+      tree var = VEC_pop (tree_on_heap, block_defs_stack);
+      tree saved_def;
+      
+      /* NULL indicates the unwind stop point for this block (see
+        rewrite_update_init_block).  */
+      if (var == NULL)
+       return;
+
+      saved_def = VEC_pop (tree_on_heap, block_defs_stack);
+      set_current_def (var, saved_def);
+    }
+}
+
+
+/* Update every variable used in the statement pointed-to by SI.  The
+   statement is assumed to be in SSA form already.  Names in
+   OLD_SSA_NAMES used by SI will be updated to their current reaching
+   definition.  Names in OLD_SSA_NAMES or NEW_SSA_NAMES defined by SI
+   will be registered as a new definition for their corresponding name
+   in OLD_SSA_NAMES.  */
+
+static void
+rewrite_update_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+                    basic_block bb ATTRIBUTE_UNUSED,
+                    block_stmt_iterator si)
+{
+  stmt_ann_t ann;
+  tree stmt;
+  use_operand_p use_p;
+  def_operand_p def_p;
+  ssa_op_iter iter;
+
+  stmt = bsi_stmt (si);
+  ann = stmt_ann (stmt);
+
+  /* Only update marked statements.  */
+  if (!REWRITE_THIS_STMT (stmt) && !REGISTER_DEFS_IN_THIS_STMT (stmt))
+    return;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Updating SSA information for statement ");
+      print_generic_stmt (dump_file, stmt, TDF_SLIM);
+      fprintf (dump_file, "\n");
+    }
+
+  /* Rewrite USES included in OLD_SSA_NAMES and USES whose underlying
+     symbol is marked for renaming.  */
+  if (REWRITE_THIS_STMT (stmt))
+    {
+      FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+       {
+         tree use = USE_FROM_PTR (use_p);
+         tree sym = DECL_P (use) ? use : SSA_NAME_VAR (use);
+
+         if (symbol_marked_for_renaming (sym))
+           replace_use (use_p, sym);
+         else if (is_old_name (use))
+           replace_use (use_p, use);
+       }
+
+      if (need_to_update_vops_p)
+       FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter,
+                                 SSA_OP_VIRTUAL_USES | SSA_OP_VIRTUAL_KILLS)
+         {
+           tree use = USE_FROM_PTR (use_p);
+           tree sym = DECL_P (use) ? use : SSA_NAME_VAR (use);
+
+           if (symbol_marked_for_renaming (sym))
+             replace_use (use_p, sym);
+         }
+    }
+
+  /* Register definitions of names in NEW_SSA_NAMES and OLD_SSA_NAMES.
+     Also register definitions for names whose underlying symbol is
+     marked for renaming.  */
+  if (REGISTER_DEFS_IN_THIS_STMT (stmt))
+    {
+      FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_DEF)
+       {
+         tree def = DEF_FROM_PTR (def_p);
+         tree sym = DECL_P (def) ? def : SSA_NAME_VAR (def);
+
+         /* If DEF is a naked symbol that needs renaming, create a
+            new name for it.  */
+         if (symbol_marked_for_renaming (sym))
+           {
+             if (DECL_P (def))
+               {
+                 def = make_ssa_name (def, stmt);
+                 SET_DEF (def_p, def);
+               }
+
+             register_new_update_single (def, sym);
+           }
+         else
+           {
+             /* If DEF is a new name, register it as a new definition
+                for all the names replaced by DEF.  */
+             if (is_new_name (def))
+               register_new_update_set (def, names_replaced_by (def));
+
+             /* If DEF is an old name, register DEF as a new
+                definition for itself.  */
+             if (is_old_name (def))
+               register_new_update_single (def, def);
+           }
+       }
+
+      if (need_to_update_vops_p)
+       FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_VIRTUAL_DEFS)
+         {
+           tree def = DEF_FROM_PTR (def_p);
+           tree sym = DECL_P (def) ? def : SSA_NAME_VAR (def);
+
+           if (symbol_marked_for_renaming (sym))
+             {
+               if (DECL_P (def))
+                 {
+                   def = make_ssa_name (def, stmt);
+                   SET_DEF (def_p, def);
+                 }
+
+               register_new_update_single (def, sym);
+             }
+         }
+    }
+}
+
+
+/* Visit all the successor blocks of BB looking for PHI nodes.  For
+   every PHI node found, check if any of its arguments is in
+   OLD_SSA_NAMES.  If so, and if the argument has a current reaching
+   definition, replace it.  */
+
+static void
+rewrite_update_phi_arguments (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+                             basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    {
+      tree phi;
+
+      for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
+       {
+         tree arg;
+         use_operand_p arg_p;
+
+         /* Skip PHI nodes that are not marked for rewrite.  */
+         if (!REWRITE_THIS_STMT (phi))
+           continue;
+
+         arg_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
+         arg = USE_FROM_PTR (arg_p);
+
+         if (arg && !DECL_P (arg) && TREE_CODE (arg) != SSA_NAME)
+           continue;
+
+         if (arg == NULL_TREE)
+           {
+             /* When updating a PHI node for a recently introduced
+                symbol we may find NULL arguments.  That's why we
+                take the symbol from the LHS of the PHI node.  */
+             replace_use (arg_p, SSA_NAME_VAR (PHI_RESULT (phi)));
+           }
+         else
+           {
+             tree sym = DECL_P (arg) ? arg : SSA_NAME_VAR (arg);
+
+             if (symbol_marked_for_renaming (sym))
+               replace_use (arg_p, sym);
+             else if (is_old_name (arg))
+               replace_use (arg_p, arg);
+           }
+
+         if (e->flags & EDGE_ABNORMAL)
+           SSA_NAME_OCCURS_IN_ABNORMAL_PHI (USE_FROM_PTR (arg_p)) = 1;
+       }
+    }
+}
+
+
+/* Rewrite the actual blocks, statements, and PHI arguments, to be in SSA
+   form.  
+
+   ENTRY indicates the block where to start.  Every block dominated by
+      ENTRY will be rewritten.
+
+   WHAT indicates what actions will be taken by the renamer (see enum
+      rewrite_mode).
+
+   BLOCKS are the set of interesting blocks for the dominator walker
+      to process.  If this set is NULL, then all the nodes dominated
+      by ENTRY are walked.  Otherwise, blocks dominated by ENTRY that
+      are not present in BLOCKS are ignored.  */
+
+static void
+rewrite_blocks (basic_block entry, enum rewrite_mode what, sbitmap blocks)
+{
+  struct dom_walk_data walk_data;
+  
+  /* Rewrite all the basic blocks in the program.  */
+  timevar_push (TV_TREE_SSA_REWRITE_BLOCKS);
+
+  /* Setup callbacks for the generic dominator tree walker.  */
+  memset (&walk_data, 0, sizeof (walk_data));
+
+  walk_data.dom_direction = CDI_DOMINATORS;
+  walk_data.interesting_blocks = blocks;
+
+  if (what == REWRITE_UPDATE)
+    walk_data.before_dom_children_before_stmts = rewrite_update_init_block;
+  else
+    walk_data.before_dom_children_before_stmts = rewrite_initialize_block;
+
+  if (what == REWRITE_ALL)
+    walk_data.before_dom_children_walk_stmts = rewrite_stmt;
+  else if (what == REWRITE_UPDATE)
+    walk_data.before_dom_children_walk_stmts = rewrite_update_stmt;
+  else
+    gcc_unreachable ();
+
+  if (what == REWRITE_ALL)
+    walk_data.before_dom_children_after_stmts = rewrite_add_phi_arguments;
+  else if (what == REWRITE_UPDATE)
+    walk_data.before_dom_children_after_stmts = rewrite_update_phi_arguments;
+  else
+    gcc_unreachable ();
+  
+  if (what == REWRITE_ALL)
+    walk_data.after_dom_children_after_stmts =  rewrite_finalize_block;
+  else if (what == REWRITE_UPDATE)
+    walk_data.after_dom_children_after_stmts = rewrite_update_fini_block;
+  else
+    gcc_unreachable ();
+
+  block_defs_stack = VEC_alloc (tree_on_heap, 10);
+
+  /* Initialize the dominator walker.  */
+  init_walk_dominator_tree (&walk_data);
+
+  /* Recursively walk the dominator tree rewriting each statement in
+     each basic block.  */
+  walk_dominator_tree (&walk_data, entry);
+
+  /* Finalize the dominator walker.  */
+  fini_walk_dominator_tree (&walk_data);
+
+  /* Debugging dumps.  */
+  if (dump_file && (dump_flags & TDF_STATS))
+    {
+      dump_dfa_stats (dump_file);
+      if (def_blocks)
+       dump_tree_ssa_stats (dump_file);
+    }
+
+  if (def_blocks)
+    {
+      htab_delete (def_blocks);
+      def_blocks = NULL;
+    }
+  
+  VEC_free (tree_on_heap, block_defs_stack);
+  block_defs_stack = NULL;
+
+  timevar_pop (TV_TREE_SSA_REWRITE_BLOCKS);
 }
 
 
@@ -1209,11 +1649,15 @@ mark_def_sites_initialize_block (struct dom_walk_data *walk_data,
 }
 
 
-/* Mark the definition site blocks for each variable, so that we know where
-   the variable is actually live.  */
+/* Mark the definition site blocks for each variable, so that we know
+   where the variable is actually live.
+
+   INTERESTING_BLOCKS will be filled in with all the blocks that
+      should be processed by the renamer.  It is assumed to be
+      initialized and zeroed by the caller.  */
 
-static void 
-mark_def_site_blocks (void)
+static void
+mark_def_site_blocks (sbitmap interesting_blocks)
 {
   size_t i;
   struct dom_walk_data walk_data;
@@ -1226,9 +1670,6 @@ mark_def_site_blocks (void)
   for (i = 0; i < num_referenced_vars; i++)
     set_current_def (referenced_var (i), NULL_TREE);
 
-  /* Ensure that the dominance information is OK.  */
-  calculate_dominance_info (CDI_DOMINATORS);
-
   /* Setup callbacks for the generic dominator tree walker to find and
      mark definition sites.  */
   walk_data.walk_stmts_backward = false;
@@ -1240,11 +1681,16 @@ mark_def_site_blocks (void)
   walk_data.after_dom_children_before_stmts =  NULL;
   walk_data.after_dom_children_walk_stmts =  NULL;
   walk_data.after_dom_children_after_stmts =  NULL;
+  walk_data.interesting_blocks = NULL;
 
   /* Notice that this bitmap is indexed using variable UIDs, so it must be
      large enough to accommodate all the variables referenced in the
      function, not just the ones we are renaming.  */
   mark_def_sites_global_data.kills = BITMAP_ALLOC (NULL);
+
+  /* Create the set of interesting blocks that will be filled by
+     mark_def_sites.  */
+  mark_def_sites_global_data.interesting_blocks = interesting_blocks;
   walk_data.global_data = &mark_def_sites_global_data;
 
   /* We do not have any local data.  */
@@ -1265,96 +1711,73 @@ mark_def_site_blocks (void)
 
 
 /* Main entry point into the SSA builder.  The renaming process
-   proceeds in five main phases:
-
-   1- If VARS_TO_RENAME has any entries, any existing PHI nodes for
-      those variables are removed from the flow graph so that they can
-      be computed again.
+   proceeds in four main phases:
 
-   2- Compute dominance frontier, needed to insert PHI nodes and
-      rename the function in dominator tree order.
+   1- Compute dominance frontier and immediate dominators, needed to
+      insert PHI nodes and rename the function in dominator tree
+      order.
 
-   3- Find and mark all the blocks that define variables
+   2- Find and mark all the blocks that define variables
       (mark_def_site_blocks).
 
-   4- Insert PHI nodes at dominance frontiers (insert_phi_nodes).
+   3- Insert PHI nodes at dominance frontiers (insert_phi_nodes).
 
-   5- Rename all the blocks (rewrite_blocks) and statements in the program.
+   4- Rename all the blocks (rewrite_blocks) and statements in the program.
 
    Steps 3 and 5 are done using the dominator tree walker
-   (walk_dominator_tree).
+   (walk_dominator_tree).  */
 
-   ALL is true if all variables should be renamed (otherwise just those
-   mentioned in vars_to_rename are taken into account).  */
-
-void
-rewrite_into_ssa (bool all)
+static void
+rewrite_into_ssa (void)
 {
   bitmap *dfs;
   basic_block bb;
-  bitmap old_vars_to_rename = vars_to_rename;
+  sbitmap interesting_blocks;
   
   timevar_push (TV_TREE_SSA_OTHER);
 
-  if (all)
-    vars_to_rename = NULL;
-  else
-    {
-      /* Initialize the array of variables to rename.  */
-      gcc_assert (vars_to_rename);
-
-      if (bitmap_empty_p (vars_to_rename))
-       {
-         timevar_pop (TV_TREE_SSA_OTHER);
-         return;
-       }
-      
-      invalidate_name_tags (vars_to_rename);
-
-      /* Now remove all the existing PHI nodes (if any) for the variables
-        that we are about to rename into SSA.  */
-      remove_all_phi_nodes_for (vars_to_rename);
-    }
+  /* Initialize operand data structures.  */
+  init_ssa_operands ();
 
-  mark_def_site_blocks ();
+  /* Initialize the set of interesting blocks.  The callback
+     mark_def_sites will add to this set those blocks that the renamer
+     should process.  */
+  interesting_blocks = sbitmap_alloc (last_basic_block);
+  sbitmap_zero (interesting_blocks);
 
   /* Initialize dominance frontier.  */
   dfs = (bitmap *) xmalloc (last_basic_block * sizeof (bitmap *));
   FOR_EACH_BB (bb)
     dfs[bb->index] = BITMAP_ALLOC (NULL);
 
-  /* Compute dominance frontiers.  */
+  /* 1- Compute dominance frontiers.  */
+  calculate_dominance_info (CDI_DOMINATORS);
   compute_dominance_frontiers (dfs);
 
-  /* Insert PHI nodes at dominance frontiers of definition blocks.  */
+  /* 2- Find and mark definition sites.  */
+  mark_def_site_blocks (interesting_blocks);
+
+  /* 3- Insert PHI nodes at dominance frontiers of definition blocks.  */
   insert_phi_nodes (dfs, NULL);
 
-  rewrite_blocks (false);
+  /* 4- Rename all the blocks.  */
+  rewrite_blocks (ENTRY_BLOCK_PTR, REWRITE_ALL, interesting_blocks);
 
   /* Free allocated memory.  */
   FOR_EACH_BB (bb)
     BITMAP_FREE (dfs[bb->index]);
   free (dfs);
+  sbitmap_free (interesting_blocks);
 
-  vars_to_rename = old_vars_to_rename;
   timevar_pop (TV_TREE_SSA_OTHER);
 }
 
 
-/* Rewrites all variables into SSA.  */
-
-static void
-rewrite_all_into_ssa (void)
-{
-  init_ssa_operands ();
-  rewrite_into_ssa (true);
-}
-
 struct tree_opt_pass pass_build_ssa = 
 {
   "ssa",                               /* name */
   NULL,                                        /* gate */
-  rewrite_all_into_ssa,                        /* execute */
+  rewrite_into_ssa,                    /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
@@ -1368,19 +1791,1054 @@ struct tree_opt_pass pass_build_ssa =
 };
 
 
-/* Rewrite the def-def chains of virtual operands so that they have
-   the correct reaching definitions.  */
+/* Mark the definition of VAR at STMT and BB as interesting for the
+   renamer.  BLOCKS is the set of blocks that need updating.  */
 
-void
-rewrite_def_def_chains (void)
+static void
+mark_def_interesting (tree var, tree stmt, basic_block bb, bitmap blocks,
+                     bool insert_phi_p)
 {
-  /* Ensure that the dominance information is OK.  */
-  calculate_dominance_info (CDI_DOMINATORS);
-  mark_def_site_blocks ();
-  rewrite_blocks (true);
+  REGISTER_DEFS_IN_THIS_STMT (stmt) = 1;
+  bitmap_set_bit (blocks, bb->index);
+
+  if (insert_phi_p)
+    {
+      bool is_phi_p = TREE_CODE (stmt) == PHI_NODE;
+
+#if defined ENABLE_CHECKING
+      /* If VAR is a virtual, then it had better be a symbol.
+        Virtuals are in FUD-chain form, so we are interested in the
+        definition and use sites of the symbol, not the individual
+        SSA names.  */
+      if (!is_gimple_reg (var))
+       gcc_assert (DECL_P (var));
+#endif
+
+      set_def_block (var, bb, is_phi_p);
+
+      /* If VAR is an SSA name in NEW_SSA_NAMES, this is a definition
+        site for both itself and all the old names replaced by it.  */
+      if (TREE_CODE (var) == SSA_NAME && is_new_name (var))
+       {
+         bitmap_iterator bi;
+         unsigned i;
+         bitmap set = names_replaced_by (var);
+         if (set)
+           EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
+             set_def_block (ssa_name (i), bb, is_phi_p);
+       }
+    }
+}
+
+
+/* Mark the use of VAR at STMT and BB as interesting for the
+   renamer.  INSERT_PHI_P is true if we are going to insert new PHI
+   nodes.  BLOCKS is the set of blocks that need updating.  */
+
+static inline void
+mark_use_interesting (tree var, tree stmt, basic_block bb, bitmap blocks,
+                     bool insert_phi_p)
+{
+  REWRITE_THIS_STMT (stmt) = 1;
+  bitmap_set_bit (blocks, bb->index);
+
+  /* If VAR has not been defined in BB, then it is live-on-entry
+     to BB.  Note that we cannot just use the block holding VAR's
+     definition because if VAR is one of the names in OLD_SSA_NAMES,
+     it will have several definitions (itself and all the names that
+     replace it).  */
+  if (insert_phi_p)
+    {
+      struct def_blocks_d *db_p;
+
+#if defined ENABLE_CHECKING
+      /* If VAR is a virtual, then it had better be a symbol.
+        Virtuals are in FUD-chain form, so we are interested in the
+        definition and use sites of the symbol, not the individual
+        SSA names.  */
+      if (!is_gimple_reg (var))
+       gcc_assert (DECL_P (var));
+#endif
+
+      db_p = get_def_blocks_for (var);
+      if (!bitmap_bit_p (db_p->def_blocks, bb->index))
+       set_livein_block (var, bb);
+    }
 }
 
 
+/* If any of the arguments of PHI is in OLD_SSA_NAMES, mark PHI to
+   be rewritten.  BB is the block where PHI resides, BLOCKS is the
+   region to be renamed and INSERT_PHI_P is true if the updating
+   process should insert new PHI nodes.  */
+
+static void
+prepare_phi_args_for_update (tree phi, basic_block bb, bitmap blocks,
+                             bool insert_phi_p)
+{
+  int i;
+
+  for (i = 0; i < PHI_NUM_ARGS (phi); i++)
+    {
+      tree arg = PHI_ARG_DEF (phi, i);
+
+      if (TREE_CODE (arg) == SSA_NAME && is_old_name (arg))
+       {
+         /* Mark this use of ARG interesting for the renamer.  Notice
+            that we explicitly call mark_use_interesting with
+            INSERT_PHI_P == false.
+
+            This is to avoid marking ARG as live-in in this block BB.
+            If we were to mark ARG live-in to BB, then ARG would be
+            considered live-in through ALL incoming edges to BB which
+            is not what we want.  Since we are updating the SSA form
+            for ARG, we don't really know what other names of ARG are
+            coming in through other edges into BB.
+
+            If we considered ARG live-in at BB, then the PHI
+            placement algorithm may try to insert PHI nodes in blocks
+            that are not only unnecessary but also the renamer would
+            not know how to fill in.  */
+         mark_use_interesting (arg, phi, bb, blocks, false);
+
+         /* As discussed above, we only want to mark ARG live-in
+            through the edge corresponding to its slot inside the PHI
+            argument list.  So, we look for the block BB1 where ARG is
+            flowing through.  If BB1 does not contain a definition of
+            ARG, then consider ARG live-in at BB1.  */
+         if (insert_phi_p)
+           {
+             edge e = PHI_ARG_EDGE (phi, i);
+             basic_block bb1 = e->src;
+             struct def_blocks_d *db = get_def_blocks_for (arg);
+
+             if (!bitmap_bit_p (db->def_blocks, bb1->index))
+               set_livein_block (arg, bb1);
+           }
+       }
+    }
+}
+
+
+/* Do a dominator walk starting at BB processing statements that
+   reference variables in OLD_SSA_NAMES and NEW_SSA_NAMES.
+
+   1- Mark in BLOCKS the defining block of every name N in
+      NEW_SSA_NAMES.
+
+   2- Mark in BLOCKS the defining block of every name O in
+      OLD_SSA_NAMES.
+
+   3- For every statement or PHI node that uses a name O in
+      OLD_SSA_NAMES.  If INSERT_PHI_P is true, mark those uses as live
+      in the corresponding block.  This is later used by the PHI
+      placement algorithm to make PHI pruning decisions.
+
+   If VISIT_DOM_P is true, all the dominator children of BB are also
+   visited.
+
+   FIXME.  This process is slower than necessary.  Once we have
+   immediate uses merged in, we should be able to just visit the
+   immediate uses of all the names that we are about to replace,
+   instead of visiting the whole block.  */
+
+static void
+prepare_block_for_update (basic_block bb, bool insert_phi_p,
+                          bitmap blocks, bool visit_dom_p)
+{
+  basic_block son;
+  block_stmt_iterator si;
+  tree phi;
+
+  /* Process PHI nodes marking interesting those that define or use
+     the names that we are interested in.  */
+  for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+    {
+      tree lhs_sym, lhs = PHI_RESULT (phi);
+
+      REWRITE_THIS_STMT (phi) = 0;
+      REGISTER_DEFS_IN_THIS_STMT (phi) = 0;
+
+      /* Ignore virtual PHIs if we are not updating virtual operands.
+        Note that even if NEED_TO_REPLACE_NAMES_P is false, we need
+        to process real PHIs because we may be rewriting GIMPLE regs
+        into SSA for the first time.  Therefore, we cannot do a
+        similar shortcut for real PHIs.  */
+      if (!need_to_update_vops_p && !is_gimple_reg (lhs))
+       continue;
+
+      lhs_sym = DECL_P (lhs) ? lhs : SSA_NAME_VAR (lhs);
+
+      if (symbol_marked_for_renaming (lhs_sym))
+       {
+         /* If the LHS is a virtual symbol marked for renaming, then
+            we don't need to scan the argument list.  Since virtual
+            operands are in FUD-chain form, all the arguments of this
+            PHI must be the same symbol as the LHS.  So, we just need
+            to mark this site as both an interesting use and an
+            interesting def for the symbol.  */
+         mark_use_interesting (lhs_sym, phi, bb, blocks, insert_phi_p);
+         mark_def_interesting (lhs_sym, phi, bb, blocks, insert_phi_p);
+       }
+      else if (need_to_replace_names_p)
+       {
+         /* If the LHS is in OLD_SSA_NAMES or NEW_SSA_NAMES, this is
+            a definition site for it.  */
+         if (is_old_name (lhs) || is_new_name (lhs))
+           mark_def_interesting (lhs, phi, bb, blocks, insert_phi_p);
+
+         prepare_phi_args_for_update (phi, bb, blocks, insert_phi_p);
+       }
+    }
+
+  /* Process the statements.  */
+  for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+    {
+      tree stmt;
+      ssa_op_iter i;
+      use_operand_p use_p;
+      def_operand_p def_p;
+      
+      stmt = bsi_stmt (si);
+
+      REWRITE_THIS_STMT (stmt) = 0;
+      REGISTER_DEFS_IN_THIS_STMT (stmt) = 0;
+
+      /* Note, even if NEED_TO_REPLACE_NAMES_P is false, we need to
+        scan real uses and defs, as we may be renaming a GIMPLE
+        register for the first time.  */
+      FOR_EACH_SSA_USE_OPERAND (use_p, stmt, i, SSA_OP_USE)
+       {
+         tree use = USE_FROM_PTR (use_p);
+         tree sym = DECL_P (use) ? use : SSA_NAME_VAR (use);
+         if (symbol_marked_for_renaming (sym) || is_old_name (use))
+           mark_use_interesting (use, stmt, bb, blocks, insert_phi_p);
+       }
+
+      FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, i, SSA_OP_DEF)
+       {
+         tree def = DEF_FROM_PTR (def_p);
+         tree sym = DECL_P (def) ? def : SSA_NAME_VAR (def);
+
+         if (symbol_marked_for_renaming (sym)
+             || is_new_name (def)
+             || is_old_name (def))
+           mark_def_interesting (def, stmt, bb, blocks, insert_phi_p);
+       }
+
+      /* If we don't need to update virtual operands, continue to the
+        next statement.  */
+      if (!need_to_update_vops_p)
+       continue;
+
+      /* For every interesting N_i = V_MAY_DEF <N_j> and
+        N_i = V_MUST_DEF <N_j>, mark the statement as interesting.
+        Notice that N_j may in fact be a naked symbol (if this
+        statement is the result of basic block duplication). The
+        rename process will later fill in the appropriate reaching
+        definition for the symbol.  */
+      FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, i, SSA_OP_VIRTUAL_DEFS)
+       {
+         tree def = DEF_FROM_PTR (def_p);
+         tree sym = DECL_P (def) ? def : SSA_NAME_VAR (def);
+
+         if (symbol_marked_for_renaming (sym))
+           {
+             mark_use_interesting (sym, stmt, bb, blocks, insert_phi_p);
+             mark_def_interesting (sym, stmt, bb, blocks, insert_phi_p);
+           }
+       }
+
+      /* Similarly, for V_USE <N_i>.  */
+      FOR_EACH_SSA_USE_OPERAND (use_p, stmt, i, SSA_OP_VUSE)
+       {
+         tree use = USE_FROM_PTR (use_p);
+         tree sym = DECL_P (use) ? use : SSA_NAME_VAR (use);
+
+         if (symbol_marked_for_renaming (sym))
+           mark_use_interesting (sym, stmt, bb, blocks, insert_phi_p);
+       }
+    }
+
+  /* Now visit all the blocks dominated by BB.  */
+  if (visit_dom_p)
+    for (son = first_dom_son (CDI_DOMINATORS, bb);
+        son;
+        son = next_dom_son (CDI_DOMINATORS, son))
+      prepare_block_for_update (son, insert_phi_p, blocks, true);
+}
+
+
+/* Helper for prepare_def_sites.  Mark the definition site for NAME as
+   interesting.  BLOCKS and INSERT_PHI_P are as in prepare_def_sites.  */
+
+static void
+prepare_def_site_for (tree name, bitmap blocks, bool insert_phi_p)
+{
+  tree stmt;
+  basic_block bb;
+
+  gcc_assert (name && is_gimple_reg (name));
+  gcc_assert (names_to_release == NULL
+             || !bitmap_bit_p (names_to_release, SSA_NAME_VERSION (name)));
+
+  stmt = SSA_NAME_DEF_STMT (name);
+  bb = bb_for_stmt (stmt);
+  if (bb)
+    {
+      gcc_assert (bb->index < last_basic_block);
+      mark_def_interesting (name, stmt, bb, blocks, insert_phi_p);
+    }
+}
+
+
+/* Mark definition sites of names in NEW_SSA_NAMES and OLD_SSA_NAMES.
+   Add each definition block to BLOCKS.  INSERT_PHI_P is true if the
+   caller wants to insert PHI nodes for newly created names.  */
+
+static void
+prepare_def_sites (bitmap blocks, bool insert_phi_p)
+{
+  unsigned i;
+  bitmap_iterator bi;
+
+  /* If a name N from NEW_SSA_NAMES is also marked to be released,
+     remove it from NEW_SSA_NAMES so that we don't try to visit its
+     defining basic block (which most likely doesn't exist).  Notice
+     that we cannot do the same with names in OLD_SSA_NAMES because we
+     want to replace existing instances.  */
+  if (names_to_release)
+    EXECUTE_IF_SET_IN_BITMAP (names_to_release, 0, i, bi)
+      RESET_BIT (new_ssa_names, i);
+
+  /* If an old name is in NAMES_TO_RELEASE, we cannot remove it from
+     OLD_SSA_NAMES, but we have to ignore its definition site.  */
+  EXECUTE_IF_SET_IN_SBITMAP (old_ssa_names, 0, i,
+    if (names_to_release == NULL || !bitmap_bit_p (names_to_release, i))
+      prepare_def_site_for (ssa_name (i), blocks, insert_phi_p));
+
+  EXECUTE_IF_SET_IN_SBITMAP (new_ssa_names, 0, i,
+    prepare_def_site_for (ssa_name (i), blocks, insert_phi_p));
+}
+
+
+/* Dump all the names replaced by NAME to FILE.  */
+
+void
+dump_names_replaced_by (FILE *file, tree name)
+{
+  unsigned i;
+  bitmap old_set;
+  bitmap_iterator bi;
+
+  print_generic_expr (file, name, 0);
+  fprintf (file, " -> { ");
+
+  old_set = names_replaced_by (name);
+  EXECUTE_IF_SET_IN_BITMAP (old_set, 0, i, bi)
+    {
+      print_generic_expr (file, ssa_name (i), 0);
+      fprintf (file, " ");
+    }
+
+  fprintf (file, "}\n");
+}
+
+
+/* Dump all the names replaced by NAME to stderr.  */
+
+void
+debug_names_replaced_by (tree name)
+{
+  dump_names_replaced_by (stderr, name);
+}
+
+
+/* Dump the SSA name replacement table to FILE.  */
+
+void
+dump_repl_tbl (FILE *file)
+{
+  unsigned i;
+  bitmap_iterator bi;
+
+  if (!need_ssa_update_p ())
+    return;
+
+  if (new_ssa_names && sbitmap_first_set_bit (new_ssa_names) >= 0)
+    {
+      fprintf (file, "\nSSA replacement table\n");
+      fprintf (file, "N_i -> { O_1 ... O_j } means that N_i replaces "
+                    "O_1, ..., O_j\n\n");
+
+      EXECUTE_IF_SET_IN_SBITMAP (new_ssa_names, 0, i,
+       dump_names_replaced_by (file, ssa_name (i)));
+    }
+
+  if (syms_to_rename && !bitmap_empty_p (syms_to_rename))
+    {
+      fprintf (file, "\n\nSymbols to be put in SSA form\n\n");
+      EXECUTE_IF_SET_IN_BITMAP (syms_to_rename, 0, i, bi)
+       {
+         print_generic_expr (file, referenced_var (i), 0);
+         fprintf (file, " ");
+       }
+    }
+
+  if (old_virtual_ssa_names && !bitmap_empty_p (old_virtual_ssa_names))
+    {
+      fprintf (file, "\n\nVirtual SSA names to be updated\n\n");
+      EXECUTE_IF_SET_IN_BITMAP (old_virtual_ssa_names, 0, i, bi)
+       {
+         print_generic_expr (file, ssa_name (i), 0);
+         fprintf (file, " ");
+       }
+    }
+
+  if (names_to_release && !bitmap_empty_p (names_to_release))
+    {
+      fprintf (file, "\n\nSSA names to release after updating the SSA web\n\n");
+      EXECUTE_IF_SET_IN_BITMAP (names_to_release, 0, i, bi)
+       {
+         print_generic_expr (file, ssa_name (i), 0);
+         fprintf (file, " ");
+       }
+    }
+
+  fprintf (file, "\n\n");
+}
+
+
+/* Dump the SSA name replacement table to stderr.  */
+
+void
+debug_repl_tbl (void)
+{
+  dump_repl_tbl (stderr);
+}
+
+
+/* Initialize data structures used for incremental SSA updates.  */
+
+static void
+init_update_ssa (void)
+{
+  /* Reserve 1/3 more than the current number of names.  The calls to
+     add_new_name_mapping are typically done after creating new SSA
+     names, so we'll need to reallocate these arrays.  */
+  old_ssa_names = sbitmap_alloc (num_ssa_names + NAME_SETS_GROWTH_FACTOR);
+  sbitmap_zero (old_ssa_names);
+
+  new_ssa_names = sbitmap_alloc (num_ssa_names + NAME_SETS_GROWTH_FACTOR);
+  sbitmap_zero (new_ssa_names);
+
+  repl_tbl = htab_create (20, repl_map_hash, repl_map_eq, repl_map_free);
+  need_to_initialize_update_ssa_p = false;
+  need_to_update_vops_p = false;
+  need_to_replace_names_p = false;
+  syms_to_rename = BITMAP_ALLOC (NULL);
+  old_virtual_ssa_names = BITMAP_ALLOC (NULL);
+  names_to_release = NULL;
+}
+
+
+/* Deallocate data structures used for incremental SSA updates.  */
+
+static void
+delete_update_ssa (void)
+{
+  unsigned i;
+  bitmap_iterator bi;
+
+  sbitmap_free (old_ssa_names);
+  old_ssa_names = NULL;
+
+  sbitmap_free (new_ssa_names);
+  new_ssa_names = NULL;
+
+  htab_delete (repl_tbl);
+  repl_tbl = NULL;
+
+  need_to_initialize_update_ssa_p = true;
+  need_to_update_vops_p = false;
+  need_to_replace_names_p = false;
+  BITMAP_FREE (syms_to_rename);
+  BITMAP_FREE (old_virtual_ssa_names);
+
+  if (names_to_release)
+    {
+      EXECUTE_IF_SET_IN_BITMAP (names_to_release, 0, i, bi)
+       release_ssa_name (ssa_name (i));
+      BITMAP_FREE (names_to_release);
+    }
+
+  for (i = 1; i < num_ssa_names; i++)
+    {
+      tree n = ssa_name (i);
+
+      if (n)
+       {
+         free (SSA_NAME_AUX (n));
+         SSA_NAME_AUX (n) = NULL;
+       }
+    }
+
+  /* Unmark all the names we may have protected from being released in
+     insert_updated_phi_nodes_for.  */
+  unmark_all_for_rewrite ();
+}
+
+
+/* Create a new name for OLD_NAME in statement STMT and replace the
+   operand pointed to by DEF_P with the newly created name.  Return
+   the new name and register the replacement mapping <NEW, OLD> in
+   update_ssa's tables.  */
+
+tree
+create_new_def_for (tree old_name, tree stmt, def_operand_p def)
+{
+  tree new_name = duplicate_ssa_name (old_name, stmt);
+
+  SET_DEF (def, new_name);
+
+  if (TREE_CODE (stmt) == PHI_NODE)
+    {
+      edge e;
+      edge_iterator ei;
+      basic_block bb = bb_for_stmt (stmt);
+
+      /* If needed, mark NEW_NAME as occurring in an abnormal PHI node. */
+      FOR_EACH_EDGE (e, ei, bb->preds)
+       if (e->flags & EDGE_ABNORMAL)
+         {
+           SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_name) = 1;
+           break;
+         }
+    }
+
+  register_new_name_mapping (new_name, old_name);
+
+  /* For the benefit of passes that will be updating the SSA form on
+     their own, set the current reaching definition of OLD_NAME to be
+     NEW_NAME.  */
+  set_current_def (old_name, new_name);
+
+  return new_name;
+}
+
+
+/* Register name NEW to be a replacement for name OLD.  This function
+   must be called for every replacement that should be performed by
+   update_ssa.  */
+
+void
+register_new_name_mapping (tree new, tree old)
+{
+  if (need_to_initialize_update_ssa_p)
+    init_update_ssa ();
+
+  add_new_name_mapping (new, old);
+}
+
+
+/* Register symbol SYM to be renamed by update_ssa.  */
+
+void
+mark_sym_for_renaming (tree sym)
+{
+  if (need_to_initialize_update_ssa_p)
+    init_update_ssa ();
+
+  bitmap_set_bit (syms_to_rename, var_ann (sym)->uid);
+
+  if (!is_gimple_reg (sym))
+    need_to_update_vops_p = true;
+}
+
+
+/* Register all the symbols in SET to be renamed by update_ssa.  */
+
+void
+mark_set_for_renaming (bitmap set)
+{
+  bitmap_iterator bi;
+  unsigned i;
+
+  if (need_to_initialize_update_ssa_p)
+    init_update_ssa ();
+
+  bitmap_ior_into (syms_to_rename, set);
+
+  EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
+    if (!is_gimple_reg (referenced_var (i)))
+      {
+       need_to_update_vops_p = true;
+       break;
+      }
+}
+
+
+/* Return true if there is any work to be done by update_ssa.  */
+
+bool
+need_ssa_update_p (void)
+{
+  return syms_to_rename || old_ssa_names || new_ssa_names;
+}
+
+
+/* Return true if name N has been registered in the replacement table.  */
+
+bool
+name_registered_for_update_p (tree n)
+{
+  if (!need_ssa_update_p ())
+    return false;
+
+  return is_new_name (n)
+         || is_old_name (n)
+        || symbol_marked_for_renaming (SSA_NAME_VAR (n));
+}
+
+
+/* Return the set of all the SSA names marked to be replaced.  */
+
+bitmap
+ssa_names_to_replace (void)
+{
+  unsigned i;
+  bitmap ret;
+  
+  ret = BITMAP_ALLOC (NULL);
+  EXECUTE_IF_SET_IN_SBITMAP (old_ssa_names, 0, i,
+    bitmap_set_bit (ret, i));
+
+  bitmap_ior_into (ret, old_virtual_ssa_names);
+
+  return ret;
+}
+
+
+/* Mark NAME to be released after update_ssa has finished.  */
+
+void
+release_ssa_name_after_update_ssa (tree name)
+{
+  gcc_assert (!need_to_initialize_update_ssa_p);
+
+  if (names_to_release == NULL)
+    names_to_release = BITMAP_ALLOC (NULL);
+
+  bitmap_set_bit (names_to_release, SSA_NAME_VERSION (name));
+}
+
+
+/* Insert new PHI nodes to replace VAR.  DFS contains dominance
+   frontier information.  BLOCKS is the set of blocks to be updated.
+
+   This is slightly different than the regular PHI insertion
+   algorithm.  The value of UPDATE_FLAGS controls how PHI nodes for
+   real names (i.e., GIMPLE registers) are inserted:
+   - If UPDATE_FLAGS == TODO_update_ssa, we are only interested in PHI
+     nodes inside the region affected by the block that defines VAR
+     and the blocks that define all its replacements.  All these
+     definition blocks have been gathered by prepare_block_for_update
+     and they are stored in DEF_BLOCKS[VAR]->DEF_BLOCKS.
+
+     First, we compute the entry point to the region (ENTRY).  This is
+     given by the nearest common dominator to all the definition
+     blocks. When computing the iterated dominance frontier (IDF), any
+     block not strictly dominated by ENTRY is ignored.
+
+     We then call the standard PHI insertion algorithm with the pruned
+     IDF.
+
+   - If UPDATE_FLAGS == TODO_update_ssa_full_phi, the IDF for real
+     names is not pruned.  PHI nodes are inserted at every IDF block.  */
+
+static void
+insert_updated_phi_nodes_for (tree var, bitmap *dfs, bitmap blocks,
+                              unsigned update_flags)
+{
+  basic_block entry;
+  struct def_blocks_d *db;
+  bitmap idf, pruned_idf;
+  bitmap_iterator bi;
+  unsigned i;
+
+#if defined ENABLE_CHECKING
+  if (TREE_CODE (var) == SSA_NAME)
+    gcc_assert (is_old_name (var));
+  else
+    gcc_assert (symbol_marked_for_renaming (var));
+#endif
+
+  /* Get all the definition sites for VAR.  */
+  db = find_def_blocks_for (var);
+
+  /* No need to do anything if there were no definitions to VAR.  */
+  if (db == NULL || bitmap_empty_p (db->def_blocks))
+    return;
+
+  /* Compute the initial iterated dominance frontier.  */
+  idf = find_idf (db->def_blocks, dfs);
+  pruned_idf = BITMAP_ALLOC (NULL);
+
+  if (TREE_CODE (var) == SSA_NAME)
+    {
+      if (update_flags == TODO_update_ssa)
+       {
+         /* If doing regular SSA updates for GIMPLE registers, we are
+            only interested in IDF blocks dominated by the nearest
+            common dominator of all the definition blocks.  */
+         entry = nearest_common_dominator_for_set (CDI_DOMINATORS,
+                                                   db->def_blocks);
+
+         if (entry != ENTRY_BLOCK_PTR)
+           EXECUTE_IF_SET_IN_BITMAP (idf, 0, i, bi)
+             if (BASIC_BLOCK (i) != entry
+                 && dominated_by_p (CDI_DOMINATORS, BASIC_BLOCK (i), entry))
+               bitmap_set_bit (pruned_idf, i);
+       }
+      else
+       {
+         /* Otherwise, do not prune the IDF for VAR.  */
+         gcc_assert (update_flags == TODO_update_ssa_full_phi);
+         bitmap_copy (pruned_idf, idf);
+       }
+    }
+  else
+    {
+      /* Otherwise, VAR is a symbol that needs to be put into SSA form
+        for the first time, so we need to compute the full IDF for
+        it.  */
+      bitmap_copy (pruned_idf, idf);
+
+      /* There may already be PHI nodes for VAR in the flowgraph.
+        Some of them are no longer necessary.  PRUNED_IDF is
+        the set of blocks that need PHI nodes for VAR and
+        DB.PHI_BLOCKS is the set of blocks that already contain a PHI
+        node for VAR.  Therefore, the set DB.PHI_BLOCKS - PRUNED_IDF
+        gives us the set of blocks that contain PHI nodes which are
+        no longer needed.  */
+      if (!bitmap_empty_p (db->phi_blocks) && !bitmap_empty_p (pruned_idf))
+       EXECUTE_IF_AND_COMPL_IN_BITMAP (db->phi_blocks, pruned_idf, 0, i, bi)
+         {
+           tree phi, prev;
+           unsigned ver;
+
+           phi = find_phi_node_for (BASIC_BLOCK (i), var, &prev);
+           
+           /* Protect the name on PHI's LHS from being released into
+              the SSA name free list.  Since we have still not
+              updated the SSA form of the program, there may be
+              instances of PHI's LHS in the IL.  */
+           ver = SSA_NAME_VERSION (PHI_RESULT (phi));
+           mark_for_rewrite (PHI_RESULT (phi));
+           release_ssa_name_after_update_ssa (PHI_RESULT (phi));
+           remove_phi_node (phi, prev);
+         }
+    }
+
+  if (!bitmap_empty_p (pruned_idf))
+    {
+      /* Make sure that PRUNED_IDF blocks and all their feeding blocks
+        are included in the region to be updated.  The feeding blocks
+        are important to guarantee that the PHI arguments are renamed
+        properly.  */
+      bitmap_ior_into (blocks, pruned_idf);
+      EXECUTE_IF_SET_IN_BITMAP (pruned_idf, 0, i, bi)
+       {
+         edge e;
+         edge_iterator ei;
+         basic_block bb = BASIC_BLOCK (i);
+
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           if (e->src->index >= 0)
+             bitmap_set_bit (blocks, e->src->index);
+       }
+
+      insert_phi_nodes_for (var, pruned_idf, true);
+    }
+
+  BITMAP_FREE (pruned_idf);
+  BITMAP_FREE (idf);
+}
+
+
+/* Given a set of newly created SSA names (NEW_SSA_NAMES) and a set of
+   existing SSA names (OLD_SSA_NAMES), update the SSA form so that:
+
+   1- The names in OLD_SSA_NAMES dominated by the definitions of
+      NEW_SSA_NAMES are all re-written to be reached by the
+      appropriate definition from NEW_SSA_NAMES.
+
+   2- If needed, new PHI nodes are added to the iterated dominance
+      frontier of the blocks where each of NEW_SSA_NAMES are defined.
+
+   The mapping between OLD_SSA_NAMES and NEW_SSA_NAMES is setup by
+   calling register_new_name_mapping for every pair of names that the
+   caller wants to replace.
+
+   The caller identifies the new names that have been inserted and the
+   names that need to be replaced by calling register_new_name_mapping
+   for every pair <NEW, OLD>.  Note that the function assumes that the
+   new names have already been inserted in the IL.
+
+   For instance, given the following code:
+
+     1 L0:
+     2 x_1 = PHI (0, x_5)
+     3 if (x_1 < 10)
+     4   if (x_1 > 7)
+     5     y_2 = 0
+     6   else
+     7     y_3 = x_1 + x_7
+     8   endif
+     9   x_5 = x_1 + 1
+     10   goto L0;
+     11        endif
+
+   Suppose that we insert new names x_10 and x_11 (lines 4 and 8).
+
+     1 L0:
+     2 x_1 = PHI (0, x_5)
+     3 if (x_1 < 10)
+     4   x_10 = ...
+     5   if (x_1 > 7)
+     6     y_2 = 0
+     7   else
+     8     x_11 = ...
+     9     y_3 = x_1 + x_7
+     10          endif
+     11          x_5 = x_1 + 1
+     12          goto L0;
+     13        endif
+
+   We want to replace all the uses of x_1 with the new definitions of
+   x_10 and x_11.  Note that the only uses that should be replaced are
+   those at lines 5, 9 and 11.  Also, the use of x_7 at line 9 should
+   *not* be replaced (this is why we cannot just mark symbol 'x' for
+   renaming).
+
+   Additionally, we may need to insert a PHI node at line 11 because
+   that is a merge point for x_10 and x_11.  So the use of x_1 at line
+   11 will be replaced with the new PHI node.  The insertion of PHI
+   nodes is optional.  They are not strictly necessary to preserve the
+   SSA form, and depending on what the caller inserted, they may not
+   even be useful for the optimizers.  UPDATE_FLAGS controls various
+   aspects of how update_ssa operates, see the documentation for
+   TODO_update_ssa*.  */
+
+void
+update_ssa (unsigned update_flags)
+{
+  bitmap *dfs, blocks;
+  basic_block bb, start_bb;
+  bitmap_iterator bi;
+  unsigned i;
+  sbitmap tmp;
+  bool insert_phi_p;
+
+  if (!need_ssa_update_p ())
+    return;
+
+  timevar_push (TV_TREE_SSA_INCREMENTAL);
+
+  /* Ensure that the dominance information is up-to-date.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+
+  /* Only one update flag should be set.  */
+  gcc_assert (update_flags == TODO_update_ssa
+              || update_flags == TODO_update_ssa_no_phi
+             || update_flags == TODO_update_ssa_full_phi
+             || update_flags == TODO_update_ssa_only_virtuals);
+
+  /* If we only need to update virtuals, remove all the mappings for
+     real names before proceeding.  */
+  if (update_flags == TODO_update_ssa_only_virtuals)
+    {
+      sbitmap_zero (old_ssa_names);
+      sbitmap_zero (new_ssa_names);
+      htab_empty (repl_tbl);
+      need_to_replace_names_p = false;
+    }
+
+  if (update_flags == TODO_update_ssa
+      || update_flags == TODO_update_ssa_full_phi
+      || update_flags == TODO_update_ssa_only_virtuals)
+    insert_phi_p = true;
+  else
+    insert_phi_p = false;
+
+  if (insert_phi_p)
+    {
+      /* If the caller requested PHI nodes to be added, compute
+        dominance frontiers and initialize live-in information data
+        structures (DEF_BLOCKS).  */
+      dfs = (bitmap *) xmalloc (last_basic_block * sizeof (bitmap *));
+      FOR_EACH_BB (bb)
+       dfs[bb->index] = BITMAP_ALLOC (NULL);
+      compute_dominance_frontiers (dfs);
+
+      /* For each SSA name N, the DEF_BLOCKS table describes where the
+        name is defined, which blocks have PHI nodes for N, and which
+        blocks have uses of N (i.e., N is live-on-entry in those
+        blocks).  */
+      def_blocks = htab_create (num_ssa_names, def_blocks_hash,
+                               def_blocks_eq, def_blocks_free);
+    }
+  else
+    {
+      dfs = NULL;
+      def_blocks = NULL;
+    }
+
+  blocks = BITMAP_ALLOC (NULL);
+
+  /* Determine the CFG region that we are going to update.  First add
+     all the blocks that define each of the names in NEW_SSA_NAMES
+     and OLD_SSA_NAMES.  */
+  prepare_def_sites (blocks, insert_phi_p);
+
+  /* Next, determine the nearest common dominator START_BB for all the
+     blocks in the region.  */
+  if (!bitmap_empty_p (syms_to_rename) || bitmap_empty_p (blocks))
+    {
+      /* If the region to update is seemingly empty, or if we have to
+        rename some symbols from scratch, we need to start the
+        process at the root of the CFG.
+
+        FIXME, it should be possible to determine the nearest block
+        that had a definition for each of the symbols that are marked
+        for updating.  For now this seems more work than it's worth.  */
+      start_bb = ENTRY_BLOCK_PTR;
+    }
+  else
+    start_bb = nearest_common_dominator_for_set (CDI_DOMINATORS, blocks);
+
+  /* Traverse all the blocks dominated by START_BB.  Mark interesting
+     blocks and statements and set local live-in information for the
+     PHI placement heuristics.  */
+  prepare_block_for_update (start_bb, insert_phi_p, blocks, true);
+
+  /* If are going to insert PHI nodes, blocks in the dominance
+     frontier of START_BB may be affected.  Note that we don't need to
+     visit the dominator children of blocks in the dominance frontier
+     of START_BB.  None of the changes inside this region can affect
+     blocks on the outside.  */
+  if (insert_phi_p && start_bb->index >= 0)
+    EXECUTE_IF_SET_IN_BITMAP (dfs[start_bb->index], 0, i, bi)
+      prepare_block_for_update (BASIC_BLOCK (i), insert_phi_p,
+                               blocks, false);
+
+  /* If requested, insert PHI nodes at the iterated dominance frontier
+     of every block making new definitions for names in OLD_SSA_NAMES
+     and for symbols in SYMS_TO_RENAME.  */
+  if (insert_phi_p)
+    {
+      if (sbitmap_first_set_bit (old_ssa_names) >= 0)
+       {
+         /* insert_update_phi_nodes_for will call
+            add_new_name_mapping when inserting new PHI nodes, so the
+            set OLD_SSA_NAMES will grow while we are traversing it
+            (but it will not gain any new members).  Copy
+            OLD_SSA_NAMES to a temporary for traversal.  */
+         sbitmap tmp = sbitmap_alloc (old_ssa_names->n_bits);
+         sbitmap_copy (tmp, old_ssa_names);
+         EXECUTE_IF_SET_IN_SBITMAP (tmp, 0, i,
+           insert_updated_phi_nodes_for (ssa_name (i), dfs, blocks,
+                                         update_flags));
+         sbitmap_free (tmp);
+       }
+
+      EXECUTE_IF_SET_IN_BITMAP (syms_to_rename, 0, i, bi)
+       insert_updated_phi_nodes_for (referenced_var (i), dfs, blocks,
+                                     update_flags);
+
+      /* Insertion of PHI nodes may have added blocks to the region.
+        We need to re-compute START_BB to include the newly added
+        blocks.  */
+      if (start_bb != ENTRY_BLOCK_PTR)
+       start_bb = nearest_common_dominator_for_set (CDI_DOMINATORS, blocks);
+    }
+
+  /* Reset the current definition for name and symbol before renaming
+     the sub-graph.  */
+  if (update_flags == TODO_update_ssa_full_phi)
+    {
+      /* If we are not prunning the IDF for new PHI nodes, set the
+        current name of every GIMPLE register to NULL.  This way, PHI
+        arguments coming from edges with uninitialized values will be
+        renamed to use the symbol's default definition.  */
+      EXECUTE_IF_SET_IN_SBITMAP (old_ssa_names, 0, i,
+       set_current_def (ssa_name (i), NULL_TREE));
+    }
+  else
+    {
+      /* Otherwise, set each old name to be its current reaching
+        definition.  */
+      EXECUTE_IF_SET_IN_SBITMAP (old_ssa_names, 0, i,
+       set_current_def (ssa_name (i), NULL_TREE));
+    }
+
+  EXECUTE_IF_SET_IN_BITMAP (syms_to_rename, 0, i, bi)
+    set_current_def (referenced_var (i), NULL_TREE);
+
+  /* Now start the renaming process at START_BB.  */
+  tmp = sbitmap_alloc (last_basic_block);
+  sbitmap_zero (tmp);
+  EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
+    SET_BIT (tmp, i);
+
+  rewrite_blocks (start_bb, REWRITE_UPDATE, tmp);
+
+  sbitmap_free (tmp);
+
+  /* Debugging dumps.  */
+  if (dump_file)
+    {
+      int c;
+      unsigned i;
+
+      dump_repl_tbl (dump_file);
+
+      fprintf (dump_file, "Incremental SSA update started at block: %d\n\n",
+              start_bb->index);
+
+      c = 0;
+      EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
+       c++;
+      fprintf (dump_file, "Number of blocks in CFG: %d\n", last_basic_block);
+      fprintf (dump_file, "Number of blocks to update: %d (%3.0f%%)\n\n",
+              c, PERCENT (c, last_basic_block));
+
+      if (dump_flags & TDF_DETAILS)
+       {
+         fprintf (dump_file, "Affected blocks: ");
+         EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
+           fprintf (dump_file, "%u ", i);
+         fprintf (dump_file, "\n");
+       }
+
+      fprintf (dump_file, "\n\n");
+    }
+
+  /* Free allocated memory.  */
+  if (insert_phi_p)
+    {
+      FOR_EACH_BB (bb)
+       BITMAP_FREE (dfs[bb->index]);
+      free (dfs);
+    }
+
+  BITMAP_FREE (blocks);
+  delete_update_ssa ();
+
+  timevar_pop (TV_TREE_SSA_INCREMENTAL);
+}
+
 
 /*---------------------------------------------------------------------------
     Functions to fix a program in invalid SSA form into valid SSA
@@ -1605,7 +3063,7 @@ ssa_mark_def_sites (struct dom_walk_data *walk_data,
 
       if (TEST_BIT (gd->names_to_rename, def_uid))
        {
-         set_def_block (def, bb, false, true);
+         set_def_block (def, bb, false);
          bitmap_set_bit (kills, def_uid);
        }
     }
@@ -1634,7 +3092,7 @@ ssa_mark_def_sites_initialize_block (struct dom_walk_data *walk_data,
       if (!TEST_BIT (gd->names_to_rename, def_uid))
        continue;
 
-      set_def_block (def, bb, true, true);
+      set_def_block (def, bb, true);
       bitmap_set_bit (kills, def_uid);
     }
 }
@@ -1714,6 +3172,7 @@ rewrite_ssa_into_ssa (void)
      mark definition sites.  */
   walk_data.walk_stmts_backward = false;
   walk_data.dom_direction = CDI_DOMINATORS;
+  walk_data.interesting_blocks = NULL;
   walk_data.initialize_block_local_data = NULL;
   walk_data.before_dom_children_before_stmts
          = ssa_mark_def_sites_initialize_block;
@@ -1761,6 +3220,7 @@ rewrite_ssa_into_ssa (void)
   /* Setup callbacks for the generic dominator tree walker.  */
   walk_data.walk_stmts_backward = false;
   walk_data.dom_direction = CDI_DOMINATORS;
+  walk_data.interesting_blocks = NULL;
   walk_data.initialize_block_local_data = NULL;
   walk_data.before_dom_children_before_stmts = ssa_rewrite_initialize_block;
   walk_data.before_dom_children_walk_stmts = ssa_rewrite_stmt;
index 0835a45..f2bd75d 100644 (file)
@@ -371,9 +371,6 @@ linear_transform_loops (struct loops *loops)
       free_data_refs (datarefs);
     }
   scev_reset ();
-  rewrite_into_ssa (false);
+  update_ssa (TODO_update_ssa);
   rewrite_into_loop_closed_ssa (NULL);
-#ifdef ENABLE_CHECKING
-  verify_loop_closed_ssa ();
-#endif
 }
index e643915..34ed979 100644 (file)
@@ -52,7 +52,6 @@ Boston, MA 02111-1307, USA.  */
 
 /* Global variables used to communicate with passes.  */
 int dump_flags;
-bitmap vars_to_rename;
 bool in_gimple_form;
 
 /* The root of the compilation pass tree, once constructed.  */
@@ -355,8 +354,9 @@ init_tree_optimization_passes (void)
   NEXT_PASS (pass_early_warn_uninitialized);
   NEXT_PASS (pass_dce);
   NEXT_PASS (pass_dominator);
-  NEXT_PASS (pass_redundant_phi);
+  NEXT_PASS (pass_copy_prop);
   NEXT_PASS (pass_dce);
+  NEXT_PASS (pass_vrp);
   NEXT_PASS (pass_merge_phi);
   NEXT_PASS (pass_forwprop);
   NEXT_PASS (pass_phiopt);
@@ -371,14 +371,14 @@ init_tree_optimization_passes (void)
   NEXT_PASS (pass_may_alias);
   NEXT_PASS (pass_rename_ssa_copies);
   NEXT_PASS (pass_dominator);
-  NEXT_PASS (pass_redundant_phi);
+  NEXT_PASS (pass_copy_prop);
   NEXT_PASS (pass_dce);
   NEXT_PASS (pass_dse);
   NEXT_PASS (pass_may_alias);
   NEXT_PASS (pass_forwprop);
   NEXT_PASS (pass_phiopt);
-  NEXT_PASS (pass_ccp);
-  NEXT_PASS (pass_redundant_phi);
+  NEXT_PASS (pass_store_ccp);
+  NEXT_PASS (pass_store_copy_prop);
   NEXT_PASS (pass_fold_builtins);
   /* FIXME: May alias should a TODO but for 4.0.0,
      we add may_alias right after fold builtins
@@ -389,7 +389,7 @@ init_tree_optimization_passes (void)
   NEXT_PASS (pass_sink_code);
   NEXT_PASS (pass_loop);
   NEXT_PASS (pass_dominator);
-  NEXT_PASS (pass_redundant_phi);
+  NEXT_PASS (pass_copy_prop);
   /* FIXME: If DCE is not run before checking for uninitialized uses,
      we may get false warnings (e.g., testsuite/gcc.dg/uninit-5.c).
      However, this also causes us to misdiagnose cases that should be
@@ -415,6 +415,7 @@ init_tree_optimization_passes (void)
 
   p = &pass_loop.sub;
   NEXT_PASS (pass_loop_init);
+  NEXT_PASS (pass_copy_prop);
   NEXT_PASS (pass_lim);
   NEXT_PASS (pass_unswitch);
   NEXT_PASS (pass_record_bounds);
@@ -443,15 +444,15 @@ execute_todo (struct tree_opt_pass *pass, unsigned int flags, bool use_required)
   int properties 
     = use_required ? pass->properties_required : pass->properties_provided;
 
-  if (flags & TODO_rename_vars)
-    {
-      rewrite_into_ssa (false);
-      bitmap_clear (vars_to_rename);
-    }
-  if (flags & TODO_fix_def_def_chains)
+#if defined ENABLE_CHECKING
+  if (need_ssa_update_p ())
+    gcc_assert (flags & TODO_update_ssa_any);
+#endif
+
+  if (flags & TODO_update_ssa_any)
     {
-      rewrite_def_def_chains ();
-      bitmap_clear (vars_to_rename);
+      unsigned update_flags = flags & TODO_update_ssa_any;
+      update_ssa (update_flags);
     }
 
   if (flags & TODO_cleanup_cfg)
@@ -482,15 +483,16 @@ execute_todo (struct tree_opt_pass *pass, unsigned int flags, bool use_required)
       ggc_collect ();
     }
 
-#ifdef ENABLE_CHECKING
+#if defined ENABLE_CHECKING
   if ((pass->properties_required & PROP_ssa)
       && !(pass->properties_destroyed & PROP_ssa))
-    verify_ssa  (true);
-
+    verify_ssa (true);
   if (flags & TODO_verify_flow)
     verify_flow_info ();
   if (flags & TODO_verify_stmts)
     verify_stmts ();
+  if (flags & TODO_verify_loops)
+    verify_loop_closed_ssa ();
 #endif
 }
 
@@ -687,8 +689,6 @@ tree_rest_of_compilation (tree fndecl)
   bitmap_obstack_initialize (NULL);
   bitmap_obstack_initialize (&reg_obstack); /* FIXME, only at RTL generation*/
   
-  vars_to_rename = BITMAP_ALLOC (NULL);
-  
   /* Perform all tree transforms and optimizations.  */
   execute_pass_list (all_passes);
   
index da5b899..f2e4cb2 100644 (file)
@@ -28,8 +28,6 @@ extern FILE *dump_file;
 extern int dump_flags;
 extern const char *dump_file_name;
 
-extern struct bitmap_head_def *vars_to_rename;
-
 /* Return the dump_file_info for the given phase.  */
 extern struct dump_file_info *get_dump_file_info (enum tree_dump_index);
 
@@ -101,19 +99,60 @@ struct dump_file_info
   (PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh)
 
 /* To-do flags.  */
-#define TODO_dump_func         (1 << 0)        /* pass doesn't dump itself */
-#define TODO_rename_vars       (1 << 1)        /* rewrite new vars to ssa */
-#define TODO_ggc_collect       (1 << 2)        /* run the collector */
-#define TODO_verify_ssa                (1 << 3)
-#define TODO_verify_flow       (1 << 4)
-#define TODO_verify_stmts      (1 << 5)
-#define TODO_fix_def_def_chains (1 << 6)        /* rewrite def-def chains  */
-#define TODO_cleanup_cfg        (1 << 7)        /* cleanup the cfg.  */
+#define TODO_dump_func                 (1 << 0)
+#define TODO_ggc_collect               (1 << 1)
+#define TODO_verify_ssa                        (1 << 2) 
+#define TODO_verify_flow               (1 << 3)
+#define TODO_verify_stmts              (1 << 4)
+#define TODO_cleanup_cfg               (1 << 5)
+#define TODO_verify_loops              (1 << 6)
+
+/* To-do flags for calls to update_ssa.  */
+
+/* Update the SSA form inserting PHI nodes for newly exposed symbols
+   and virtual names marked for updating.  When updating real names,
+   only insert PHI nodes for a real name O_j in blocks reached by all
+   the new and old definitions for O_j.  If the iterated dominance
+   frontier for O_j is not pruned, we may end up inserting PHI nodes
+   in blocks that have one or more edges with no incoming definition
+   for O_j.  This would lead to uninitialized warnings for O_j's
+   symbol.  */
+#define TODO_update_ssa                        (1 << 7)
+
+/* Update the SSA form without inserting any new PHI nodes at all.
+   This is used by passes that have either inserted all the PHI nodes
+   themselves or passes that need only to patch use-def and def-def
+   chains for virtuals (e.g., DCE).  */
+#define TODO_update_ssa_no_phi         (1 << 8)
+
+/* Insert PHI nodes everywhere they are needed.  No prunning of the
+   IDF is done.  This is used by passes that need the PHI nodes for
+   O_j even if it means that some arguments will come from the default
+   definition of O_j's symbol (e.g., pass_linear_transform).
+   
+   WARNING: If you need to use this flag, chances are that your pass
+   may be doing something wrong.  Inserting PHI nodes for an old name
+   where not all edges carry a new replacement may lead to silent
+   codegen errors or spurious uninitialized warnings.  */
+#define TODO_update_ssa_full_phi       (1 << 9)
+
+/* Passes that update the SSA form on their own may want to delegate
+   the updating of virtual names to the generic updater.  Since FUD
+   chains are easier to maintain, this simplifies the work they need
+   to do.  NOTE: If this flag is used, any OLD->NEW mappings for real
+   names are explicitly destroyed and only the symbols marked for
+   renaming are processed.  */
+#define TODO_update_ssa_only_virtuals  (1 << 10)
+
+#define TODO_update_ssa_any            \
+    (TODO_update_ssa                   \
+     | TODO_update_ssa_no_phi          \
+     | TODO_update_ssa_full_phi                \
+     | TODO_update_ssa_only_virtuals)
 
 #define TODO_verify_all \
   (TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts)
 
-
 extern struct tree_opt_pass pass_mudflap_1;
 extern struct tree_opt_pass pass_mudflap_2;
 extern struct tree_opt_pass pass_remove_useless_stmts;
@@ -167,6 +206,10 @@ extern struct tree_opt_pass pass_rest_of_compilation;
 extern struct tree_opt_pass pass_sink_code;
 extern struct tree_opt_pass pass_fre;
 extern struct tree_opt_pass pass_linear_transform;
+extern struct tree_opt_pass pass_copy_prop;
+extern struct tree_opt_pass pass_store_ccp;
+extern struct tree_opt_pass pass_store_copy_prop;
+extern struct tree_opt_pass pass_vrp;
 extern struct tree_opt_pass pass_create_structure_vars;
 
 #endif /* GCC_TREE_PASS_H */
index 963ef0a..929480f 100644 (file)
@@ -197,10 +197,8 @@ ideal_phi_node_len (int len)
   return new_len;
 }
 
-/* Return a PHI node for variable VAR defined in statement STMT.
-   STMT may be an empty statement for artificial references (e.g., default
-   definitions created when a variable is used without a preceding
-   definition).  */
+
+/* Return a PHI node with LEN argument slots for variable VAR.  */
 
 static tree
 make_phi_node (tree var, int len)
@@ -468,58 +466,30 @@ remove_phi_node (tree phi, tree prev)
 }
 
 
-/* Remove all the PHI nodes for variables in the VARS bitmap.  */
+/* Find the first PHI node P in basic block BB for symbol SYM.  If
+   PREV_P is given, the PHI node preceding P is stored in *PREV_P.  */
 
-void
-remove_all_phi_nodes_for (bitmap vars)
+tree
+find_phi_node_for (basic_block bb, tree sym, tree *prev_p)
 {
-  basic_block bb;
-
-  FOR_EACH_BB (bb)
-    {
-      /* Build a new PHI list for BB without variables in VARS.  */
-      tree phi, new_phi_list, next;
-      tree *lastp = &new_phi_list;
+  tree phi;
 
-      for (phi = phi_nodes (bb); phi; phi = next)
-       {
-         tree var = SSA_NAME_VAR (PHI_RESULT (phi));
-
-         next = PHI_CHAIN (phi);
-         /* Only add PHI nodes for variables not in VARS.  */
-         if (!bitmap_bit_p (vars, var_ann (var)->uid))
-           {
-             /* If we're not removing this PHI node, then it must have
-                been rewritten by a previous call into the SSA rewriter.
-                Note that fact in PHI_REWRITTEN.  */
-             PHI_REWRITTEN (phi) = 1;
-
-             *lastp = phi;
-             lastp = &PHI_CHAIN (phi);
-           }
-         else
-           {
-             /* If we are deleting the PHI node, then we should release the
-                SSA_NAME node so that it can be reused.  */
-             release_phi_node (phi);
-             release_ssa_name (PHI_RESULT (phi));
-           }
-       }
+  if (prev_p)
+    *prev_p = NULL_TREE;
 
-      /* Make sure the last node in the new list has no successors.  */
-      *lastp = NULL;
-      bb_ann (bb)->phi_nodes = new_phi_list;
+  for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+    {
+      if (SSA_NAME_VAR (PHI_RESULT (phi)) == sym)
+       return phi;
 
-#if defined ENABLE_CHECKING
-      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-       {
-         tree var = SSA_NAME_VAR (PHI_RESULT (phi));
-         gcc_assert (!bitmap_bit_p (vars, var_ann (var)->uid));
-       }
-#endif
+      if (prev_p)
+       *prev_p = phi;
     }
+
+  return NULL_TREE;
 }
 
+
 /* Reverse the order of PHI nodes in the chain PHI.
    Return the new head of the chain (old last PHI node).  */
 
@@ -537,4 +507,3 @@ phi_reverse (tree phi)
 }
 
 #include "gt-tree-phinodes.h"
-
index 06c9f13..598cc90 100644 (file)
@@ -1430,6 +1430,14 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       pp_printf (buffer, "VH.%d", VALUE_HANDLE_ID (node));
       break;
 
+    case ASSERT_EXPR:
+      pp_string (buffer, "ASSERT_EXPR <");
+      dump_generic_node (buffer, ASSERT_EXPR_VAR (node), spc, flags, false);
+      pp_string (buffer, ", ");
+      dump_generic_node (buffer, ASSERT_EXPR_COND (node), spc, flags, false);
+      pp_string (buffer, ">");
+      break;
+
     case SCEV_KNOWN:
       pp_string (buffer, "scev_known");
       break;
index 576fce0..ffead49 100644 (file)
@@ -1065,8 +1065,8 @@ follow_ssa_edge_in_rhs (struct loop *loop,
      - an INTEGER_CST,
      - a PLUS_EXPR, 
      - a MINUS_EXPR,
-     - other cases are not yet handled. 
-  */
+     - an ASSERT_EXPR,
+     - other cases are not yet handled.  */
   switch (TREE_CODE (rhs))
     {
     case NOP_EXPR:
@@ -1247,6 +1247,20 @@ follow_ssa_edge_in_rhs (struct loop *loop,
       
       break;
 
+    case ASSERT_EXPR:
+      {
+       /* This assignment is of the form: "a_1 = ASSERT_EXPR <a_2, ...>"
+          It must be handled as a copy assignment of the form a_1 = a_2.  */
+       tree op0 = ASSERT_EXPR_VAR (rhs);
+       if (TREE_CODE (op0) == SSA_NAME)
+         res = follow_ssa_edge (loop, SSA_NAME_DEF_STMT (op0),
+                                halting_phi, evolution_of_loop);
+       else
+         res = false;
+       break;
+      }
+
+
     default:
       res = false;
       break;
@@ -1701,6 +1715,11 @@ interpret_rhs_modify_expr (struct loop *loop,
     case SSA_NAME:
       res = chrec_convert (type, analyze_scalar_evolution (loop, opnd1));
       break;
+
+    case ASSERT_EXPR:
+      opnd10 = ASSERT_EXPR_VAR (opnd1);
+      res = chrec_convert (type, analyze_scalar_evolution (loop, opnd10));
+      break;
       
     case NOP_EXPR:
     case CONVERT_EXPR:
index b933fbc..1ca629f 100644 (file)
@@ -1428,6 +1428,8 @@ decide_instantiations (void)
     }
   bitmap_clear (&done_head);
 
+  mark_set_for_renaming (sra_candidates);
+
   if (dump_file)
     fputc ('\n', dump_file);
 }
@@ -1439,7 +1441,7 @@ decide_instantiations (void)
    renaming. This becomes necessary when we modify all of a non-scalar.  */
 
 static void
-mark_all_v_defs (tree stmt)
+mark_all_v_defs_1 (tree stmt)
 {
   tree sym;
   ssa_op_iter iter;
@@ -1450,10 +1452,28 @@ mark_all_v_defs (tree stmt)
     {
       if (TREE_CODE (sym) == SSA_NAME)
        sym = SSA_NAME_VAR (sym);
-      bitmap_set_bit (vars_to_rename, var_ann (sym)->uid);
+      mark_sym_for_renaming (sym);
+    }
+}
+
+
+/* Mark all the variables in virtual operands in all the statements in
+   LIST for renaming.  */
+
+static void
+mark_all_v_defs (tree list)
+{
+  if (TREE_CODE (list) != STATEMENT_LIST)
+    mark_all_v_defs_1 (list);
+  else
+    {
+      tree_stmt_iterator i;
+      for (i = tsi_start (list); !tsi_end_p (i); tsi_next (&i))
+       mark_all_v_defs_1 (tsi_stmt (i));
     }
 }
 
+
 /* Build a single level component reference to ELT rooted at BASE.  */
 
 static tree
@@ -1706,7 +1726,7 @@ generate_element_init (struct sra_elt *elt, tree init, tree *list_p)
 
       new = num_referenced_vars;
       for (j = old; j < new; ++j)
-       bitmap_set_bit (vars_to_rename, j);
+       mark_sym_for_renaming (referenced_var (j));
     }
 
   return ret;
@@ -1820,7 +1840,7 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
       generate_copy_inout (elt, is_output, generate_element_ref (elt), &list);
       if (list == NULL)
        return;
-      mark_all_v_defs (expr_first (list));
+      mark_all_v_defs (list);
       if (is_output)
        sra_insert_after (bsi, list);
       else
@@ -1865,7 +1885,7 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
                           generate_element_ref (rhs_elt), &list);
       if (list)
        {
-         mark_all_v_defs (expr_first (list));
+         mark_all_v_defs (list);
          sra_insert_before (bsi, list);
        }
 
@@ -1873,7 +1893,10 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
       generate_copy_inout (lhs_elt, true,
                           generate_element_ref (lhs_elt), &list);
       if (list)
-       sra_insert_after (bsi, list);
+       {
+         mark_all_v_defs (list);
+         sra_insert_after (bsi, list);
+       }
     }
   else
     {
@@ -1887,6 +1910,7 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
       list = NULL;
       generate_element_copy (lhs_elt, rhs_elt, &list);
       gcc_assert (list);
+      mark_all_v_defs (list);
       sra_replace (bsi, list);
     }
 }
@@ -1936,7 +1960,7 @@ scalarize_init (struct sra_elt *lhs_elt, tree rhs, block_stmt_iterator *bsi)
         exposes constants to later optimizations.  */
       if (list)
        {
-         mark_all_v_defs (expr_first (list));
+         mark_all_v_defs (list);
          sra_insert_after (bsi, list);
        }
     }
@@ -1946,6 +1970,7 @@ scalarize_init (struct sra_elt *lhs_elt, tree rhs, block_stmt_iterator *bsi)
         replaces the original structure assignment.  */
       gcc_assert (list);
       mark_all_v_defs (bsi_stmt (*bsi));
+      mark_all_v_defs (list);
       sra_replace (bsi, list);
     }
 }
@@ -1996,6 +2021,7 @@ scalarize_ldst (struct sra_elt *elt, tree other,
 
       mark_all_v_defs (stmt);
       generate_copy_inout (elt, is_output, other, &list);
+      mark_all_v_defs (list);
       gcc_assert (list);
 
       /* Preserve EH semantics.  */
@@ -2051,7 +2077,10 @@ scalarize_parms (void)
     }
 
   if (list)
-    insert_edge_copies (list, ENTRY_BLOCK_PTR);
+    {
+      insert_edge_copies (list, ENTRY_BLOCK_PTR);
+      mark_all_v_defs (list);
+    }
 }
 
 /* Entry point to phase 4.  Update the function to match replacements.  */
@@ -2154,7 +2183,7 @@ struct tree_opt_pass pass_sra =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_rename_vars
+  TODO_dump_func | TODO_update_ssa
     | TODO_ggc_collect | TODO_verify_ssa,  /* todo_flags_finish */
   0                                    /* letter */
 };
index 17bf8c5..de39ed1 100644 (file)
@@ -371,7 +371,7 @@ struct tree_opt_pass pass_may_alias =
   PROP_alias,                          /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_rename_vars
+  TODO_dump_func | TODO_update_ssa
     | TODO_ggc_collect | TODO_verify_ssa
     | TODO_verify_stmts,               /* todo_flags_finish */
   0                                    /* letter */
@@ -407,7 +407,7 @@ count_ptr_derefs (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
    *NUM_DEREFS_P respectively.  *IS_STORE_P is set to 'true' if at
    least one of those dereferences is a store operation.  */
 
-static void
+void
 count_uses_and_derefs (tree ptr, tree stmt, unsigned *num_uses_p,
                       unsigned *num_derefs_p, bool *is_store)
 {
@@ -770,7 +770,7 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
          /* Mark variables in V_MAY_DEF operands as being written to.  */
          FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS)
            {
-             tree var = SSA_NAME_VAR (op);
+             tree var = DECL_P (op) ? op : SSA_NAME_VAR (op);
              var_ann_t ann = var_ann (var);
              bitmap_set_bit (ai->written_vars, ann->uid);
            }
@@ -855,7 +855,7 @@ create_name_tags (struct alias_info *ai)
             needs to be removed from the IL, so we mark it for
             renaming.  */
          if (old_name_tag && old_name_tag != pi->name_mem_tag)
-           bitmap_set_bit (vars_to_rename, var_ann (old_name_tag)->uid);
+           mark_sym_for_renaming (old_name_tag);
        }
       else if (pi->pt_malloc)
        {
@@ -875,7 +875,7 @@ create_name_tags (struct alias_info *ai)
          |= TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (ptr)));
 
       /* Mark the new name tag for renaming.  */
-      bitmap_set_bit (vars_to_rename, var_ann (pi->name_mem_tag)->uid);
+      mark_sym_for_renaming (pi->name_mem_tag);
     }
 }
 
@@ -1000,7 +1000,11 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
                         || bitmap_bit_p (ai->written_vars, v_ann->uid);
          if (!tag_stored_p && !var_stored_p)
            continue;
-            
+
+         if ((unmodifiable_var_p (tag) && !unmodifiable_var_p (var))
+             || (unmodifiable_var_p (var) && !unmodifiable_var_p (tag)))
+           continue;
+
          if (may_alias_p (p_map->var, p_map->set, var, v_map->set))
            {
              subvar_t svars;
@@ -1449,9 +1453,10 @@ setup_pointers_and_addressables (struct alias_info *ai)
              && !is_global_var (var))
            {
              bool okay_to_mark = true;
+
              /* Since VAR is now a regular GIMPLE register, we will need
                 to rename VAR into SSA afterwards.  */
-             bitmap_set_bit (vars_to_rename, v_ann->uid);
+             mark_sym_for_renaming (var);
 
              if (var_can_have_subvars (var)
                  && (svars = get_subvars_for_var (var)))
@@ -1463,15 +1468,15 @@ setup_pointers_and_addressables (struct alias_info *ai)
                      var_ann_t svann = var_ann (sv->var);
                      if (bitmap_bit_p (ai->addresses_needed, svann->uid))
                        okay_to_mark = false;
-                     bitmap_set_bit (vars_to_rename, svann->uid);
+                     mark_sym_for_renaming (sv->var);
                    }
                }
+
              /* The address of VAR is not needed, remove the
                 addressable bit, so that it can be optimized as a
                 regular variable.  */
              if (okay_to_mark)
                mark_non_addressable (var);
-
            }
          else
            {
@@ -1496,7 +1501,7 @@ setup_pointers_and_addressables (struct alias_info *ai)
       if (may_be_aliased (var))
        {
          create_alias_map_for (var, ai);
-         bitmap_set_bit (vars_to_rename, var_ann (var)->uid);    
+         mark_sym_for_renaming (var);
        }
 
       /* Add pointer variables that have been dereferenced to the POINTERS
@@ -1519,7 +1524,13 @@ setup_pointers_and_addressables (struct alias_info *ai)
                 afterwards. Note that we cannot do this inside
                 get_tmt_for because aliasing may run multiple times
                 and we only create type tags the first time.  */
-             bitmap_set_bit (vars_to_rename, t_ann->uid);
+             mark_sym_for_renaming (tag);
+
+             /* Similarly, if pointer VAR used to have another type
+                tag, we will need to process it in the renamer to
+                remove the stale virtual operands.  */
+             if (v_ann->type_mem_tag)
+               mark_sym_for_renaming (v_ann->type_mem_tag);
 
              /* Associate the tag with pointer VAR.  */
              v_ann->type_mem_tag = tag;
@@ -1555,7 +1566,7 @@ setup_pointers_and_addressables (struct alias_info *ai)
              tree tag = ann->type_mem_tag;
              if (tag)
                {
-                 bitmap_set_bit (vars_to_rename, var_ann (tag)->uid);
+                 mark_sym_for_renaming (tag);
                  ann->type_mem_tag = NULL_TREE;
                }
            }
@@ -1661,11 +1672,11 @@ maybe_create_global_var (struct alias_info *ai)
            {
              subvar_t sv;
              for (sv = svars; sv; sv = sv->next)
-               bitmap_set_bit (vars_to_rename, var_ann (sv->var)->uid);
+               mark_sym_for_renaming (sv->var);
            }
        }
       
-      bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
+      mark_sym_for_renaming (var);
     }
 }
 
@@ -1802,7 +1813,7 @@ set_pt_anything (tree ptr)
      disassociated from PTR.  */
   if (pi->name_mem_tag)
     {
-      bitmap_set_bit (vars_to_rename, var_ann (pi->name_mem_tag)->uid);
+      mark_sym_for_renaming (pi->name_mem_tag);
       pi->name_mem_tag = NULL_TREE;
     }
 }
@@ -2358,7 +2369,7 @@ create_global_var (void)
   TREE_ADDRESSABLE (global_var) = 0;
 
   add_referenced_tmp_var (global_var);
-  bitmap_set_bit (vars_to_rename, var_ann (global_var)->uid);
+  mark_sym_for_renaming (global_var);
 }
 
 
@@ -2673,6 +2684,83 @@ may_be_aliased (tree var)
   return true;
 }
 
+
+/* Add VAR to the list of may-aliases of PTR's type tag.  If PTR
+   doesn't already have a type tag, create one.  */
+
+void
+add_type_alias (tree ptr, tree var)
+{
+  varray_type aliases;
+  tree tag;
+  var_ann_t ann = var_ann (ptr);
+
+  if (ann->type_mem_tag == NULL_TREE)
+    {
+      size_t i;
+      tree q = NULL_TREE;
+      tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
+      HOST_WIDE_INT tag_set = get_alias_set (tag_type);
+
+      /* PTR doesn't have a type tag, create a new one and add VAR to
+        the new tag's alias set.
+
+        FIXME, This is slower than necessary.  We need to determine
+        whether there is another pointer Q with the same alias set as
+        PTR.  This could be sped up by having type tags associated
+        with types.  */
+      for (i = 0; i < num_referenced_vars; i++)
+       {
+         q = referenced_var (i);
+
+         if (POINTER_TYPE_P (TREE_TYPE (q))
+             && tag_set == get_alias_set (TREE_TYPE (TREE_TYPE (q))))
+           {
+             /* Found another pointer Q with the same alias set as
+                the PTR's pointed-to type.  If Q has a type tag, use
+                it.  Otherwise, create a new memory tag for PTR.  */
+             var_ann_t ann1 = var_ann (q);
+             if (ann1->type_mem_tag)
+               ann->type_mem_tag = ann1->type_mem_tag;
+             else
+               ann->type_mem_tag = create_memory_tag (tag_type, true);
+             goto found_tag;
+           }
+       }
+
+      /* Couldn't find any other pointer with a type tag we could use.
+        Create a new memory tag for PTR.  */
+      ann->type_mem_tag = create_memory_tag (tag_type, true);
+    }
+
+found_tag:
+  /* If VAR is not already PTR's type tag, add it to the may-alias set
+     for PTR's type tag.  */
+  gcc_assert (var_ann (var)->type_mem_tag == NOT_A_TAG);
+  tag = ann->type_mem_tag;
+  add_may_alias (tag, var);
+
+  /* TAG and its set of aliases need to be marked for renaming.  */
+  mark_sym_for_renaming (tag);
+  if ((aliases = var_ann (tag)->may_aliases) != NULL)
+    {
+      size_t i;
+      for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++)
+       mark_sym_for_renaming (VARRAY_TREE (aliases, i));
+    }
+
+  /* If we had grouped aliases, VAR may have aliases of its own.  Mark
+     them for renaming as well.  Other statements referencing the
+     aliases of VAR will need to be updated.  */
+  if ((aliases = var_ann (var)->may_aliases) != NULL)
+    {
+      size_t i;
+      for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++)
+       mark_sym_for_renaming (VARRAY_TREE (aliases, i));
+    }
+}
+
+
 /* This structure is simply used during pushing fields onto the fieldstack
    to track the offset of the field, since bitpos_of_field gives it relative
    to its immediate containing type, and we want it relative to the ultimate
@@ -3168,4 +3256,3 @@ struct tree_opt_pass pass_create_structure_vars =
   TODO_dump_func,       /* todo_flags_finish */
   0                     /* letter */
 };
-
index 26e1a2e..443d8dc 100644 (file)
@@ -21,7 +21,161 @@ along with GCC; see the file COPYING.  If not, write to the Free
 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 02111-1307, USA.  */
 
-/* Conditional constant propagation.
+/* Conditional constant propagation (CCP) is based on the SSA
+   propagation engine (tree-ssa-propagate.c).  Constant assignments of
+   the form VAR = CST are propagated from the assignments into uses of
+   VAR, which in turn may generate new constants.  The simulation uses
+   a four level lattice to keep track of constant values associated
+   with SSA names.  Given an SSA name V_i, it may take one of the
+   following values:
+
+       UNINITIALIZED   ->  This is the default starting value.  V_i
+                           has not been processed yet.
+
+       UNDEFINED       ->  V_i is a local variable whose definition
+                           has not been processed yet.  Therefore we
+                           don't yet know if its value is a constant
+                           or not.
+
+       CONSTANT        ->  V_i has been found to hold a constant
+                           value C.
+
+       VARYING         ->  V_i cannot take a constant value, or if it
+                           does, it is not possible to determine it
+                           at compile time.
+
+   The core of SSA-CCP is in ccp_visit_stmt and ccp_visit_phi_node:
+
+   1- In ccp_visit_stmt, we are interested in assignments whose RHS
+      evaluates into a constant and conditional jumps whose predicate
+      evaluates into a boolean true or false.  When an assignment of
+      the form V_i = CONST is found, V_i's lattice value is set to
+      CONSTANT and CONST is associated with it.  This causes the
+      propagation engine to add all the SSA edges coming out the
+      assignment into the worklists, so that statements that use V_i
+      can be visited.
+
+      If the statement is a conditional with a constant predicate, we
+      mark the outgoing edges as executable or not executable
+      depending on the predicate's value.  This is then used when
+      visiting PHI nodes to know when a PHI argument can be ignored.
+      
+
+   2- In ccp_visit_phi_node, if all the PHI arguments evaluate to the
+      same constant C, then the LHS of the PHI is set to C.  This
+      evaluation is known as the "meet operation".  Since one of the
+      goals of this evaluation is to optimistically return constant
+      values as often as possible, it uses two main short cuts:
+
+      - If an argument is flowing in through a non-executable edge, it
+       is ignored.  This is useful in cases like this:
+
+                       if (PRED)
+                         a_9 = 3;
+                       else
+                         a_10 = 100;
+                       a_11 = PHI (a_9, a_10)
+
+       If PRED is known to always evaluate to false, then we can
+       assume that a_11 will always take its value from a_10, meaning
+       that instead of consider it VARYING (a_9 and a_10 have
+       different values), we can consider it CONSTANT 100.
+
+      - If an argument has an UNDEFINED value, then it does not affect
+       the outcome of the meet operation.  If a variable V_i has an
+       UNDEFINED value, it means that either its defining statement
+       hasn't been visited yet or V_i has no defining statement, in
+       which case the original symbol 'V' is being used
+       uninitialized.  Since 'V' is a local variable, the compiler
+       may assume any initial value for it.
+
+
+   After propagation, every variable V_i that ends up with a lattice
+   value of CONSTANT will have the associated constant value in the
+   array CONST_VAL[i].VALUE.  That is fed into substitute_and_fold for
+   final substitution and folding.
+
+
+   Constant propagation in stores and loads (STORE-CCP)
+   ----------------------------------------------------
+
+   While CCP has all the logic to propagate constants in GIMPLE
+   registers, it is missing the ability to associate constants with
+   stores and loads (i.e., pointer dereferences, structures and
+   global/aliased variables).  We don't keep loads and stores in
+   SSA, but we do build a factored use-def web for them (in the
+   virtual operands).
+
+   For instance, consider the following code fragment:
+
+         struct A a;
+         const int B = 42;
+
+         void foo (int i)
+         {
+           if (i > 10)
+             a.a = 42;
+           else
+             {
+               a.b = 21;
+               a.a = a.b + 21;
+             }
+
+           if (a.a != B)
+             never_executed ();
+         }
+
+   We should be able to deduce that the predicate 'a.a != B' is always
+   false.  To achieve this, we associate constant values to the SSA
+   names in the V_MAY_DEF and V_MUST_DEF operands for each store.
+   Additionally, since we also glob partial loads/stores with the base
+   symbol, we also keep track of the memory reference where the
+   constant value was stored (in the MEM_REF field of PROP_VALUE_T).
+   For instance,
+
+        # a_5 = V_MAY_DEF <a_4>
+        a.a = 2;
+
+        # VUSE <a_5>
+        x_3 = a.b;
+
+   In the example above, CCP will associate value '2' with 'a_5', but
+   it would be wrong to replace the load from 'a.b' with '2', because
+   '2' had been stored into a.a.
+
+   To support STORE-CCP, it is necessary to add a new value to the
+   constant propagation lattice.  When evaluating a load for a memory
+   reference we can no longer assume a value of UNDEFINED if we
+   haven't seen a preceding store to the same memory location.
+   Consider, for instance global variables:
+
+       int A;
+
+       foo (int i)
+       {
+         if (i_3 > 10)
+           A_4 = 3;
+          # A_5 = PHI (A_4, A_2);
+
+         # VUSE <A_5>
+         A.0_6 = A;
+
+         return A.0_6;
+       }
+
+   The value of A_2 cannot be assumed to be UNDEFINED, as it may have
+   been defined outside of foo.  If we were to assume it UNDEFINED, we
+   would erroneously optimize the above into 'return 3;'.  Therefore,
+   when doing STORE-CCP, we introduce a fifth lattice value
+   (UNKNOWN_VAL), which overrides any other value when computing the
+   meet operation in PHI nodes.
+
+   Though STORE-CCP is not too expensive, it does have to do more work
+   than regular CCP, so it is only enabled at -O2.  Both regular CCP
+   and STORE-CCP use the exact same algorithm.  The only distinction
+   is that when doing STORE-CCP, the boolean variable DO_STORE_CCP is
+   set to true.  This affects the evaluation of statements and PHI
+   nodes.
 
    References:
 
@@ -65,27 +219,29 @@ typedef enum
   UNKNOWN_VAL,
   CONSTANT,
   VARYING
-} latticevalue;
+} ccp_lattice_t;
 
-/* Main structure for CCP.  Contains the lattice value and, if it's a
-    constant, the constant value.  */
-typedef struct
-{
-  latticevalue lattice_val;
-  tree const_val;
-} value;
+/* Array of propagated constant values.  After propagation,
+   CONST_VAL[I].VALUE holds the constant value for SSA_NAME(I).  If
+   the constant is held in an SSA name representing a memory store
+   (i.e., a V_MAY_DEF or V_MUST_DEF), CONST_VAL[I].MEM_REF will
+   contain the actual memory reference used to store (i.e., the LHS of
+   the assignment doing the store).  */
+prop_value_t *const_val;
 
-/* This is used to track the current value of each variable.  */
-static value *value_vector;
+/* True if we are also propagating constants in stores and loads.  */
+static bool do_store_ccp;
 
-
-/* Dump lattice value VAL to file OUTF prefixed by PREFIX.  */
+/* Dump constant propagation value VAL to file OUTF prefixed by PREFIX.  */
 
 static void
-dump_lattice_value (FILE *outf, const char *prefix, value val)
+dump_lattice_value (FILE *outf, const char *prefix, prop_value_t val)
 {
   switch (val.lattice_val)
     {
+    case UNINITIALIZED:
+      fprintf (outf, "%sUNINITIALIZED", prefix);
+      break;
     case UNDEFINED:
       fprintf (outf, "%sUNDEFINED", prefix);
       break;
@@ -97,7 +253,7 @@ dump_lattice_value (FILE *outf, const char *prefix, value val)
       break;
     case CONSTANT:
       fprintf (outf, "%sCONSTANT ", prefix);
-      print_generic_expr (outf, val.const_val, dump_flags);
+      print_generic_expr (outf, val.value, dump_flags);
       break;
     default:
       gcc_unreachable ();
@@ -105,169 +261,173 @@ dump_lattice_value (FILE *outf, const char *prefix, value val)
 }
 
 
-/* Return a default value for variable VAR using the following rules:
+/* Print lattice value VAL to stderr.  */
+
+void debug_lattice_value (prop_value_t val);
+
+void
+debug_lattice_value (prop_value_t val)
+{
+  dump_lattice_value (stderr, "", val);
+  fprintf (stderr, "\n");
+}
 
-   1- Function arguments are considered VARYING.
-   
-   2- Global and static variables that are declared constant are
-      considered CONSTANT.
 
-   3- Any other virtually defined variable is considered UNKNOWN_VAL.
+/* Compute a default value for variable VAR and store it in the
+   CONST_VAL array.  The following rules are used to get default
+   values:
 
-   4- Any other value is considered UNDEFINED.  This is useful when
+   1- Global and static variables that are declared constant are
+      considered CONSTANT.
+
+   2- Any other value is considered UNDEFINED.  This is useful when
       considering PHI nodes.  PHI arguments that are undefined do not
       change the constant value of the PHI node, which allows for more
-      constants to be propagated.  */
+      constants to be propagated.
 
-static value
-get_default_value (tree var)
-{
-  value val;
-  tree sym;
+   3- If SSA_NAME_VALUE is set and it is a constant, its value is
+      used.
 
-  if (TREE_CODE (var) == SSA_NAME)
-    sym = SSA_NAME_VAR (var);
-  else
-    {
-      gcc_assert (DECL_P (var));
-      sym = var;
-    }
+   4- Variables defined by statements other than assignments and PHI
+      nodes are considered VARYING.
 
-  val.lattice_val = UNDEFINED;
-  val.const_val = NULL_TREE;
+   5- Variables that are not GIMPLE registers are considered
+      UNKNOWN_VAL, which is really a stronger version of UNDEFINED.
+      It's used to avoid the short circuit evaluation implied by
+      UNDEFINED in ccp_lattice_meet.  */
 
-  if (TREE_CODE (var) == SSA_NAME
-      && SSA_NAME_VALUE (var)
-      && is_gimple_min_invariant (SSA_NAME_VALUE (var)))
-    {
-      val.lattice_val = CONSTANT;
-      val.const_val = SSA_NAME_VALUE (var);
-    }
-  else if (TREE_CODE (sym) == PARM_DECL || TREE_THIS_VOLATILE (sym))
+static prop_value_t
+get_default_value (tree var)
+{
+  tree sym = SSA_NAME_VAR (var);
+  prop_value_t val = { UNINITIALIZED, NULL_TREE, NULL_TREE };
+
+  if (!do_store_ccp && !is_gimple_reg (var))
     {
-      /* Function arguments and volatile variables are considered VARYING.  */
+      /* Short circuit for regular CCP.  We are not interested in any
+        non-register when DO_STORE_CCP is false.  */
       val.lattice_val = VARYING;
     }
-  else if (TREE_STATIC (sym))
+  else if (SSA_NAME_VALUE (var)
+          && is_gimple_min_invariant (SSA_NAME_VALUE (var)))
     {
-      /* Globals and static variables are considered UNKNOWN_VAL,
-         unless they are declared 'const'.  */
-      if (TREE_READONLY (sym)
-         && DECL_INITIAL (sym)
-         && is_gimple_min_invariant (DECL_INITIAL (sym)))
-       {
-         val.lattice_val = CONSTANT;
-         val.const_val = DECL_INITIAL (sym);
-       }
-      else
-        {
-          val.const_val = NULL_TREE;
-         val.lattice_val = UNKNOWN_VAL;
-       }
+      val.lattice_val = CONSTANT;
+      val.value = SSA_NAME_VALUE (var);
     }
-  else if (!is_gimple_reg (sym))
+  else if (TREE_STATIC (sym)
+          && TREE_READONLY (sym)
+          && DECL_INITIAL (sym)
+          && is_gimple_min_invariant (DECL_INITIAL (sym)))
     {
-      val.const_val = NULL_TREE;
-      val.lattice_val = UNKNOWN_VAL;
+      /* Globals and static variables declared 'const' take their
+        initial value.  */
+      val.lattice_val = CONSTANT;
+      val.value = DECL_INITIAL (sym);
+      val.mem_ref = sym;
     }
   else
     {
-      enum tree_code code;
       tree stmt = SSA_NAME_DEF_STMT (var);
 
-      if (!IS_EMPTY_STMT (stmt))
-        {
-         code = TREE_CODE (stmt);
-         if (code != MODIFY_EXPR && code != PHI_NODE)
+      if (IS_EMPTY_STMT (stmt))
+       {
+         /* Variables defined by an empty statement are those used
+            before being initialized.  If VAR is a local variable, we
+            can assume initially that it is UNDEFINED.  If we are
+            doing STORE-CCP, function arguments and non-register
+            variables are initially UNKNOWN_VAL, because we cannot
+            discard the value incoming from outside of this function
+            (see ccp_lattice_meet for details).  */
+         if (is_gimple_reg (sym) && TREE_CODE (sym) != PARM_DECL)
+           val.lattice_val = UNDEFINED;
+         else if (do_store_ccp)
+           val.lattice_val = UNKNOWN_VAL;
+         else
            val.lattice_val = VARYING;
        }
+      else if (TREE_CODE (stmt) == MODIFY_EXPR
+              || TREE_CODE (stmt) == PHI_NODE)
+       {
+         /* Any other variable defined by an assignment or a PHI node
+            is considered UNDEFINED (or UNKNOWN_VAL if VAR is not a
+            GIMPLE register).  */
+         val.lattice_val = is_gimple_reg (sym) ? UNDEFINED : UNKNOWN_VAL;
+       }
+      else
+       {
+         /* Otherwise, VAR will never take on a constant value.  */
+         val.lattice_val = VARYING;
+       }
     }
 
   return val;
 }
 
-/* Get the constant value associated with variable VAR.  */
-
-static value *
-get_value (tree var)
-{
-  value *val;
 
-  gcc_assert (TREE_CODE (var) == SSA_NAME);
+/* Get the constant value associated with variable VAR.  If
+   MAY_USE_DEFAULT_P is true, call get_default_value on variables that
+   have the lattice value UNINITIALIZED.  */
 
-  val = &value_vector[SSA_NAME_VERSION (var)];
-  if (val->lattice_val == UNINITIALIZED)
+static prop_value_t *
+get_value (tree var, bool may_use_default_p)
+{
+  prop_value_t *val = &const_val[SSA_NAME_VERSION (var)];
+  if (may_use_default_p && val->lattice_val == UNINITIALIZED)
     *val = get_default_value (var);
 
   return val;
 }
 
 
-/* Set the lattice value for variable VAR to VAL.  Return true if VAL
-   is different from VAR's previous value.  */
+/* Set the value for variable VAR to NEW_VAL.  Return true if the new
+   value is different from VAR's previous value.  */
 
 static bool
-set_lattice_value (tree var, value val)
+set_lattice_value (tree var, prop_value_t new_val)
 {
-  value *old = get_value (var);
-
-  if (val.lattice_val == UNDEFINED)
-    {
-      /* CONSTANT->UNDEFINED is never a valid state transition.  */
-      gcc_assert (old->lattice_val != CONSTANT);
-       
-      /* UNKNOWN_VAL->UNDEFINED is never a valid state transition.  */
-      gcc_assert (old->lattice_val != UNKNOWN_VAL);
-
-      /* VARYING->UNDEFINED is generally not a valid state transition,
-        except for values which are initialized to VARYING.  */
-      gcc_assert (old->lattice_val != VARYING
-                 || get_default_value (var).lattice_val == VARYING);
-    }
-  else if (val.lattice_val == CONSTANT)
-    /* VARYING -> CONSTANT is an invalid state transition, except
-       for objects which start off in a VARYING state.  */
-    gcc_assert (old->lattice_val != VARYING
-               || get_default_value (var).lattice_val == VARYING);
-
-  /* If the constant for VAR has changed, then this VAR is really varying.  */
-  if (old->lattice_val == CONSTANT
-      && val.lattice_val == CONSTANT
-      && !simple_cst_equal (old->const_val, val.const_val))
-    {
-      val.lattice_val = VARYING;
-      val.const_val = NULL_TREE;
-    }
-
-  if (old->lattice_val != val.lattice_val)
+  prop_value_t *old_val = get_value (var, false);
+
+  /* Lattice transitions must always be monotonically increasing in
+     value.  We allow two exceptions:
+     
+     1- If *OLD_VAL and NEW_VAL are the same, return false to
+       inform the caller that this was a non-transition.
+
+     2- If we are doing store-ccp (i.e., DOING_STORE_CCP is true),
+       allow CONSTANT->UNKNOWN_VAL.  The UNKNOWN_VAL state is a
+       special type of UNDEFINED state which prevents the short
+       circuit evaluation of PHI arguments (see ccp_visit_phi_node
+       and ccp_lattice_meet).  */
+  gcc_assert (old_val->lattice_val <= new_val.lattice_val
+              || (old_val->lattice_val == new_val.lattice_val
+                 && old_val->value == new_val.value
+                 && old_val->mem_ref == new_val.mem_ref)
+             || (do_store_ccp
+                 && old_val->lattice_val == CONSTANT
+                 && new_val.lattice_val == UNKNOWN_VAL));
+
+  if (old_val->lattice_val != new_val.lattice_val)
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
-         dump_lattice_value (dump_file, "Lattice value changed to ", val);
-         fprintf (dump_file, ".  Adding definition to SSA edges.\n");
+         dump_lattice_value (dump_file, "Lattice value changed to ", new_val);
+         fprintf (dump_file, ".  %sdding SSA edges to worklist.\n",
+                  new_val.lattice_val != UNDEFINED ? "A" : "Not a");
        }
 
-      *old = val;
-      return true;
+      *old_val = new_val;
+
+      /* Transitions UNINITIALIZED -> UNDEFINED are never interesting
+        for propagation purposes.  In these cases return false to
+        avoid doing useless work.  */
+      return (new_val.lattice_val != UNDEFINED);
     }
 
   return false;
 }
 
 
-/* Set the lattice value for the variable VAR to VARYING.  */
-
-static void
-def_to_varying (tree var)
-{
-  value val;
-  val.lattice_val = VARYING;
-  val.const_val = NULL_TREE;
-  set_lattice_value (var, val);
-}
-
-
-/* Return the likely latticevalue for STMT.
+/* Return the likely CCP lattice value for STMT.
 
    If STMT has no operands, then return CONSTANT.
 
@@ -277,57 +437,71 @@ def_to_varying (tree var)
 
    Else return VARYING.  */
 
-static latticevalue
+static ccp_lattice_t
 likely_value (tree stmt)
 {
-  vuse_optype vuses;
-  int found_constant = 0;
+  bool found_constant;
   stmt_ann_t ann;
   tree use;
   ssa_op_iter iter;
 
-  /* If the statement makes aliased loads or has volatile operands, it
-     won't fold to a constant value.  */
   ann = stmt_ann (stmt);
-  if (ann->makes_aliased_loads || ann->has_volatile_ops)
+
+  /* If the statement has volatile operands, it won't fold to a
+     constant value.  */
+  if (ann->has_volatile_ops)
+    return VARYING;
+
+  /* If we are not doing store-ccp, statements with loads
+     and/or stores will never fold into a constant.  */
+  if (!do_store_ccp
+      && (ann->makes_aliased_stores
+         || ann->makes_aliased_loads
+         || NUM_VUSES (VUSE_OPS (ann)) > 0
+         || NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) > 0
+         || NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) > 0))
     return VARYING;
 
-  /* A CALL_EXPR is assumed to be varying.  This may be overly conservative,
-     in the presence of const and pure calls.  */
+
+  /* A CALL_EXPR is assumed to be varying.  NOTE: This may be overly
+     conservative, in the presence of const and pure calls.  */
   if (get_call_expr_in (stmt) != NULL_TREE)
     return VARYING;
 
+  /* Anything other than assignments and conditional jumps are not
+     interesting for CCP.  */
+  if (TREE_CODE (stmt) != MODIFY_EXPR
+      && TREE_CODE (stmt) != COND_EXPR
+      && TREE_CODE (stmt) != SWITCH_EXPR)
+    return VARYING;
+
   get_stmt_operands (stmt);
 
-  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
+  found_constant = false;
+  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE|SSA_OP_VUSE)
     {
-      value *val = get_value (use);
+      prop_value_t *val = get_value (use, true);
 
-      if (val->lattice_val == UNDEFINED)
-       return UNDEFINED;
+      if (val->lattice_val == VARYING)
+       return VARYING;
 
-      if (val->lattice_val == CONSTANT)
-       found_constant = 1;
-    }
-    
-  vuses = VUSE_OPS (ann);
-  
-  if (NUM_VUSES (vuses))
-    {
-      tree vuse = VUSE_OP (vuses, 0);
-      value *val = get_value (vuse);
-      
       if (val->lattice_val == UNKNOWN_VAL)
-        return UNKNOWN_VAL;
-       
-      /* There should be no VUSE operands that are UNDEFINED.  */
-      gcc_assert (val->lattice_val != UNDEFINED);
-       
+       {
+         /* UNKNOWN_VAL is invalid when not doing STORE-CCP.  */
+         gcc_assert (do_store_ccp);
+         return UNKNOWN_VAL;
+       }
+
       if (val->lattice_val == CONSTANT)
-       found_constant = 1;
+       found_constant = true;
     }
 
-  return ((found_constant || (!USE_OPS (ann) && !vuses)) ? CONSTANT : VARYING);
+  if (found_constant
+      || NUM_USES (USE_OPS (ann)) == 0
+      || NUM_VUSES (VUSE_OPS (ann)) == 0)
+    return CONSTANT;
+
+  return UNDEFINED;
 }
 
 
@@ -337,53 +511,41 @@ static void
 ccp_initialize (void)
 {
   basic_block bb;
-  sbitmap is_may_def;
 
-  value_vector = (value *) xmalloc (num_ssa_names * sizeof (value));
-  memset (value_vector, 0, num_ssa_names * sizeof (value));
-
-  /* Set of SSA_NAMEs that are defined by a V_MAY_DEF.  */
-  is_may_def = sbitmap_alloc (num_ssa_names);
-  sbitmap_zero (is_may_def);
+  const_val = xmalloc (num_ssa_names * sizeof (*const_val));
+  memset (const_val, 0, num_ssa_names * sizeof (*const_val));
 
   /* Initialize simulation flags for PHI nodes and statements.  */
   FOR_EACH_BB (bb)
     {
       block_stmt_iterator i;
 
-      /* Mark all V_MAY_DEF operands VARYING.  */
       for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
         {
          bool is_varying = false;
          tree stmt = bsi_stmt (i);
-         ssa_op_iter iter;
-         tree def;
 
          get_stmt_operands (stmt);
 
-         /* Get the default value for each DEF and V_MUST_DEF.  */
-         FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, 
-                                    (SSA_OP_DEF | SSA_OP_VMUSTDEF))
-           {
-             if (get_value (def)->lattice_val == VARYING)
-               is_varying = true;
-           }
+         if (likely_value (stmt) == VARYING)
 
-         /* Mark all V_MAY_DEF operands VARYING.  */
-         FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_VMAYDEF)
            {
-             get_value (def)->lattice_val = VARYING;
-             SET_BIT (is_may_def, SSA_NAME_VERSION (def));
+             tree def;
+             ssa_op_iter iter;
+
+             /* If the statement will not produce a constant, mark
+                all its outputs VARYING.  */
+             FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
+               get_value (def, false)->lattice_val = VARYING;
+
+             /* Never mark conditional jumps with DONT_SIMULATE_AGAIN,
+                otherwise the propagator will never add the outgoing
+                control edges.  */
+             if (TREE_CODE (stmt) != COND_EXPR
+                 && TREE_CODE (stmt) != SWITCH_EXPR)
+               is_varying = true;
            }
 
-         /* Statements other than MODIFY_EXPR, COND_EXPR and
-            SWITCH_EXPR are not interesting for constant propagation.
-            Mark them VARYING.  */
-         if (TREE_CODE (stmt) != MODIFY_EXPR
-             && TREE_CODE (stmt) != COND_EXPR
-             && TREE_CODE (stmt) != SWITCH_EXPR)
-           is_varying = true;
-
          DONT_SIMULATE_AGAIN (stmt) = is_varying;
        }
     }
@@ -391,301 +553,148 @@ ccp_initialize (void)
   /* Now process PHI nodes.  */
   FOR_EACH_BB (bb)
     {
-      tree phi, var;
-      int x;
+      tree phi;
 
       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
        {
-         value *val = get_value (PHI_RESULT (phi));
+         int i;
+         tree arg;
+         prop_value_t *val = get_value (PHI_RESULT (phi), false);
 
-         for (x = 0; x < PHI_NUM_ARGS (phi); x++)
+         for (i = 0; i < PHI_NUM_ARGS (phi); i++)
            {
-             var = PHI_ARG_DEF (phi, x);
+             arg = PHI_ARG_DEF (phi, i);
 
-             /* If one argument has a V_MAY_DEF, the result is
-                VARYING.  */
-             if (TREE_CODE (var) == SSA_NAME)
+             if (TREE_CODE (arg) == SSA_NAME
+                 && get_value (arg, false)->lattice_val == VARYING)
                {
-                 if (TEST_BIT (is_may_def, SSA_NAME_VERSION (var)))
-                   {
-                     val->lattice_val = VARYING;
-                     SET_BIT (is_may_def, SSA_NAME_VERSION (PHI_RESULT (phi)));
-                     break;
-                   }
+                 val->lattice_val = VARYING;
+                 break;
                }
            }
 
          DONT_SIMULATE_AGAIN (phi) = (val->lattice_val == VARYING);
        }
     }
-
-  sbitmap_free (is_may_def);
 }
 
 
-/* Replace USE references in statement STMT with their immediate reaching
-   definition.  Return true if at least one reference was replaced.  If
-   REPLACED_ADDRESSES_P is given, it will be set to true if an address
-   constant was replaced.  */
-
-static bool
-replace_uses_in (tree stmt, bool *replaced_addresses_p)
-{
-  bool replaced = false;
-  use_operand_p use;
-  ssa_op_iter iter;
+/* Do final substitution of propagated values, cleanup the flowgraph and
+   free allocated storage.  */
 
-  if (replaced_addresses_p)
-    *replaced_addresses_p = false;
-
-  get_stmt_operands (stmt);
-
-  FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE)
-    {
-      tree tuse = USE_FROM_PTR (use);
-      value *val = get_value (tuse);
-
-      if (val->lattice_val != CONSTANT)
-       continue;
-
-      if (TREE_CODE (stmt) == ASM_EXPR
-         && !may_propagate_copy_into_asm (tuse))
-       continue;
-
-      SET_USE (use, val->const_val);
-
-      replaced = true;
-      if (POINTER_TYPE_P (TREE_TYPE (tuse)) && replaced_addresses_p)
-       *replaced_addresses_p = true;
-    }
-
-  return replaced;
-}
-
-
-/* Replace the VUSE references in statement STMT with its immediate reaching
-   definition.  Return true if the reference was replaced.  If
-   REPLACED_ADDRESSES_P is given, it will be set to true if an address
-   constant was replaced.  */
-
-static bool
-replace_vuse_in (tree stmt, bool *replaced_addresses_p)
+static void
+ccp_finalize (void)
 {
-  bool replaced = false;
-  vuse_optype vuses;
-  use_operand_p vuse;
-  value *val;
-
-  if (replaced_addresses_p)
-    *replaced_addresses_p = false;
-
-  get_stmt_operands (stmt);
-
-  vuses = STMT_VUSE_OPS (stmt);
-
-  if (NUM_VUSES (vuses) != 1)
-    return false;
-
-  vuse = VUSE_OP_PTR (vuses, 0);
-  val = get_value (USE_FROM_PTR (vuse));
-
-  if (val->lattice_val == CONSTANT
-      && TREE_CODE (stmt) == MODIFY_EXPR
-      && DECL_P (TREE_OPERAND (stmt, 1))
-      && TREE_OPERAND (stmt, 1) == SSA_NAME_VAR (USE_FROM_PTR (vuse)))
-    {
-      TREE_OPERAND (stmt, 1) = val->const_val;
-      replaced = true;
-      if (POINTER_TYPE_P (TREE_TYPE (USE_FROM_PTR (vuse))) 
-          && replaced_addresses_p)
-        *replaced_addresses_p = true;
-    }
+  /* Perform substitutions based on the known constant values.  */
+  substitute_and_fold (const_val);
 
-  return replaced;
+  free (const_val);
 }
 
 
-/* Perform final substitution and folding.  After this pass the program
-   should still be in SSA form.  */
+/* Compute the meet operator between *VAL1 and *VAL2.  Store the result
+   in VAL1.
+
+               any  M UNDEFINED   = any
+               any  M UNKNOWN_VAL = UNKNOWN_VAL
+               any  M VARYING     = VARYING
+               Ci   M Cj          = Ci         if (i == j)
+               Ci   M Cj          = VARYING    if (i != j)
+
+   Lattice values UNKNOWN_VAL and UNDEFINED are similar but have
+   different semantics at PHI nodes.  Both values imply that we don't
+   know whether the variable is constant or not.  However, UNKNOWN_VAL
+   values override all others.  For instance, suppose that A is a
+   global variable:
+
+               +------+
+               |      |
+               |     / \
+               |    /   \
+               |   |  A_1 = 4
+               |    \   /
+               |     \ /    
+               | A_3 = PHI (A_2, A_1)
+               | ... = A_3
+               |    |
+               +----+
+
+   If the edge into A_2 is not executable, the first visit to A_3 will
+   yield the constant 4.  But the second visit to A_3 will be with A_2
+   in state UNKNOWN_VAL.  We can no longer conclude that A_3 is 4
+   because A_2 may have been set in another function.  If we had used
+   the lattice value UNDEFINED, we would have had wrongly concluded
+   that A_3 is 4.  */
+   
 
 static void
-substitute_and_fold (void)
+ccp_lattice_meet (prop_value_t *val1, prop_value_t *val2)
 {
-  basic_block bb;
-  unsigned int i;
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file,
-            "\nSubstituing constants and folding statements\n\n");
-
-  /* Substitute constants in every statement of every basic block.  */
-  FOR_EACH_BB (bb)
+  if (val1->lattice_val == UNDEFINED)
     {
-      block_stmt_iterator i;
-      tree phi;
-
-      /* Propagate our known constants into PHI nodes.  */
-      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-       {
-         int i;
-
-         for (i = 0; i < PHI_NUM_ARGS (phi); i++)
-           {
-             value *new_val;
-             use_operand_p orig_p = PHI_ARG_DEF_PTR (phi, i);
-             tree orig = USE_FROM_PTR (orig_p);
-
-             if (! SSA_VAR_P (orig))
-               break;
-
-             new_val = get_value (orig);
-             if (new_val->lattice_val == CONSTANT
-                 && may_propagate_copy (orig, new_val->const_val))
-               SET_USE (orig_p, new_val->const_val);
-           }
-       }
-
-      for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
-       {
-          bool replaced_address;
-         tree stmt = bsi_stmt (i);
-
-         /* Skip statements that have been folded already.  */
-         if (stmt_modified_p (stmt) || !is_exec_stmt (stmt))
-           continue;
-
-         /* Replace the statement with its folded version and mark it
-            folded.  */
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "Line %d: replaced ", get_lineno (stmt));
-             print_generic_stmt (dump_file, stmt, TDF_SLIM);
-           }
-
-         if (replace_uses_in (stmt, &replaced_address)
-             || replace_vuse_in (stmt, &replaced_address))
-           {
-             bool changed = fold_stmt (bsi_stmt_ptr (i));
-             stmt = bsi_stmt(i);
-
-             /* 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);
-
-              /* If we cleaned up EH information from the statement,
-                 remove EH edges.  */
-             if (maybe_clean_eh_stmt (stmt))
-               tree_purge_dead_eh_edges (bb);
-
-             update_stmt (stmt);
-           }
-
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, " with ");
-             print_generic_stmt (dump_file, stmt, TDF_SLIM);
-             fprintf (dump_file, "\n");
-           }
-       }
+      /* UNDEFINED M any = any   */
+      *val1 = *val2;
     }
-
-  /* And transfer what we learned from VALUE_VECTOR into the
-     SSA_NAMEs themselves.  This probably isn't terribly important
-     since we probably constant propagated the values to their
-     use sites above.  */
-  for (i = 0; i < num_ssa_names; i++)
+  else if (val2->lattice_val == UNDEFINED)
     {
-      tree name = ssa_name (i);
-      value *value;
-
-      if (!name)
-       continue;
-
-      value = get_value (name);
-      if (value->lattice_val == CONSTANT
-          && is_gimple_reg (name)
-         && is_gimple_min_invariant (value->const_val))
-       SSA_NAME_VALUE (name) = value->const_val;
+      /* any M UNDEFINED = any
+         Nothing to do.  VAL1 already contains the value we want.  */
+      ;
     }
-}
-
-
-/* Free allocated storage.  */
-
-static void
-ccp_finalize (void)
-{
-  /* Perform substitutions based on the known constant values.  */
-  substitute_and_fold ();
-
-  free (value_vector);
-}
-
-
-
-/* Compute the meet operator between VAL1 and VAL2:
-
-               any  M UNDEFINED     = any
-               any  M VARYING       = VARYING
-               any  M UNKNOWN_VAL   = UNKNOWN_VAL
-               Ci   M Cj            = Ci       if (i == j)
-               Ci   M Cj            = VARYING  if (i != j)  */
-static value
-ccp_lattice_meet (value val1, value val2)
-{
-  value result;
-
-  /* any M UNDEFINED = any.  */
-  if (val1.lattice_val == UNDEFINED)
-    return val2;
-  else if (val2.lattice_val == UNDEFINED)
-    return val1;
-
-  /* any M VARYING = VARYING.  */
-  if (val1.lattice_val == VARYING || val2.lattice_val == VARYING)
+  else if (val1->lattice_val == UNKNOWN_VAL
+           || val2->lattice_val == UNKNOWN_VAL)
     {
-      result.lattice_val = VARYING;
-      result.const_val = NULL_TREE;
-      return result;
-    }
+      /* UNKNOWN_VAL values are invalid if we are not doing STORE-CCP.  */
+      gcc_assert (do_store_ccp);
 
-  /* any M UNKNOWN_VAL = UNKNOWN_VAL.  */
-  if (val1.lattice_val == UNKNOWN_VAL 
-      || val2.lattice_val == UNKNOWN_VAL)
+      /* any M UNKNOWN_VAL = UNKNOWN_VAL.  */
+      val1->lattice_val = UNKNOWN_VAL;
+      val1->value = NULL_TREE;
+      val1->mem_ref = NULL_TREE;
+    }
+  else if (val1->lattice_val == VARYING
+           || val2->lattice_val == VARYING)
     {
-      result.lattice_val = UNKNOWN_VAL;
-      result.const_val = NULL_TREE;
-      return result;
+      /* any M VARYING = VARYING.  */
+      val1->lattice_val = VARYING;
+      val1->value = NULL_TREE;
+      val1->mem_ref = NULL_TREE;
     }
-
-  /* Ci M Cj = Ci      if (i == j)
-     Ci M Cj = VARYING if (i != j)  */
-  if (simple_cst_equal (val1.const_val, val2.const_val) == 1)
+  else if (val1->lattice_val == CONSTANT
+          && val2->lattice_val == CONSTANT
+          && simple_cst_equal (val1->value, val2->value) == 1
+          && (!do_store_ccp
+              || simple_cst_equal (val1->mem_ref, val2->mem_ref) == 1))
     {
-      result.lattice_val = CONSTANT;
-      result.const_val = val1.const_val;
+      /* Ci M Cj = Ci          if (i == j)
+        Ci M Cj = VARYING      if (i != j)
+
+         If these two values come from memory stores, make sure that
+        they come from the same memory reference.  */
+      val1->lattice_val = CONSTANT;
+      val1->value = val1->value;
+      val1->mem_ref = val1->mem_ref;
     }
   else
     {
-      result.lattice_val = VARYING;
-      result.const_val = NULL_TREE;
+      /* Any other combination is VARYING.  */
+      val1->lattice_val = VARYING;
+      val1->value = NULL_TREE;
+      val1->mem_ref = NULL_TREE;
     }
-
-  return result;
 }
 
 
 /* Loop through the PHI_NODE's parameters for BLOCK and compare their
    lattice values to determine PHI_NODE's lattice value.  The value of a
-   PHI node is determined calling ccp_lattice_meet() with all the arguments
+   PHI node is determined calling ccp_lattice_meet with all the arguments
    of the PHI node that are incoming via executable edges.  */
 
 static enum ssa_prop_result
 ccp_visit_phi_node (tree phi)
 {
-  value new_val, *old_val;
   int i;
+  prop_value_t *old_val, new_val;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -693,11 +702,11 @@ ccp_visit_phi_node (tree phi)
       print_generic_expr (dump_file, phi, dump_flags);
     }
 
-  old_val = get_value (PHI_RESULT (phi));
+  old_val = get_value (PHI_RESULT (phi), false);
   switch (old_val->lattice_val)
     {
     case VARYING:
-      return SSA_PROP_NOT_INTERESTING;
+      return SSA_PROP_VARYING;
 
     case CONSTANT:
       new_val = *old_val;
@@ -710,14 +719,15 @@ ccp_visit_phi_node (tree phi)
         UNDEFINED.  If the PHI node's old value was UNKNOWN_VAL and
         the new value is UNDEFINED, then we prevent the invalid
         transition by not calling set_lattice_value.  */
-      new_val.lattice_val = UNDEFINED;
-      new_val.const_val = NULL_TREE;
-      break;
+      gcc_assert (do_store_ccp);
+
+      /* FALLTHRU  */
 
     case UNDEFINED:
     case UNINITIALIZED:
       new_val.lattice_val = UNDEFINED;
-      new_val.const_val = NULL_TREE;
+      new_val.value = NULL_TREE;
+      new_val.mem_ref = NULL_TREE;
       break;
 
     default:
@@ -726,7 +736,8 @@ ccp_visit_phi_node (tree phi)
 
   for (i = 0; i < PHI_NUM_ARGS (phi); i++)
     {
-      /* Compute the meet operator over all the PHI arguments.  */
+      /* Compute the meet operator over all the PHI arguments flowing
+        through executable edges.  */
       edge e = PHI_ARG_EDGE (phi, i);
 
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -741,25 +752,25 @@ ccp_visit_phi_node (tree phi)
         the existing value of the PHI node and the current PHI argument.  */
       if (e->flags & EDGE_EXECUTABLE)
        {
-         tree rdef = PHI_ARG_DEF (phi, i);
-         value *rdef_val, val;
+         tree arg = PHI_ARG_DEF (phi, i);
+         prop_value_t arg_val;
 
-         if (is_gimple_min_invariant (rdef))
+         if (is_gimple_min_invariant (arg))
            {
-             val.lattice_val = CONSTANT;
-             val.const_val = rdef;
-             rdef_val = &val;
+             arg_val.lattice_val = CONSTANT;
+             arg_val.value = arg;
+             arg_val.mem_ref = NULL_TREE;
            }
          else
-           rdef_val = get_value (rdef);
+           arg_val = *(get_value (arg, true));
 
-         new_val = ccp_lattice_meet (new_val, *rdef_val);
+         ccp_lattice_meet (&new_val, &arg_val);
 
          if (dump_file && (dump_flags & TDF_DETAILS))
            {
              fprintf (dump_file, "\t");
-             print_generic_expr (dump_file, rdef, dump_flags);
-             dump_lattice_value (dump_file, "\tValue: ", *rdef_val);
+             print_generic_expr (dump_file, arg, dump_flags);
+             dump_lattice_value (dump_file, "\tValue: ", arg_val);
              fprintf (dump_file, "\n");
            }
 
@@ -775,7 +786,8 @@ ccp_visit_phi_node (tree phi)
     }
 
   /* Check for an invalid change from UNKNOWN_VAL to UNDEFINED.  */
-  if (old_val->lattice_val == UNKNOWN_VAL
+  if (do_store_ccp
+      && old_val->lattice_val == UNKNOWN_VAL
       && new_val.lattice_val == UNDEFINED)
     return SSA_PROP_NOT_INTERESTING;
 
@@ -808,18 +820,23 @@ ccp_fold (tree stmt)
   enum tree_code code = TREE_CODE (rhs);
   enum tree_code_class kind = TREE_CODE_CLASS (code);
   tree retval = NULL_TREE;
-  vuse_optype vuses;
-  
-  vuses = STMT_VUSE_OPS (stmt);
 
-  /* If the RHS is just a variable, then that variable must now have
-     a constant value that we can return directly.  */
   if (TREE_CODE (rhs) == SSA_NAME)
-    return get_value (rhs)->const_val;
-  else if (DECL_P (rhs) 
-           && NUM_VUSES (vuses) == 1
-           && rhs == SSA_NAME_VAR (VUSE_OP (vuses, 0)))
-    return get_value (VUSE_OP (vuses, 0))->const_val;
+    {
+      /* If the RHS is an SSA_NAME, return its known constant value,
+        if any.  */
+      return get_value (rhs, true)->value;
+    }
+  else if (do_store_ccp && stmt_makes_single_load (stmt))
+    {
+      /* If the RHS is a memory load, see if the VUSEs associated with
+        it are a valid constant for that memory load.  */
+      prop_value_t *val = get_value_loaded_by (stmt, const_val);
+      if (val && simple_cst_equal (val->mem_ref, rhs) == 1)
+       return val->value;
+      else
+       return NULL_TREE;
+    }
 
   /* Unary operators.  Note that we know the single operand must
      be a constant.  So this should almost always return a
@@ -832,9 +849,9 @@ ccp_fold (tree stmt)
       /* Simplify the operand down to a constant.  */
       if (TREE_CODE (op0) == SSA_NAME)
        {
-         value *val = get_value (op0);
+         prop_value_t *val = get_value (op0, true);
          if (val->lattice_val == CONSTANT)
-           op0 = get_value (op0)->const_val;
+           op0 = get_value (op0, true)->value;
        }
 
       retval = fold_unary_to_constant (code, TREE_TYPE (rhs), op0);
@@ -876,16 +893,16 @@ ccp_fold (tree stmt)
       /* Simplify the operands down to constants when appropriate.  */
       if (TREE_CODE (op0) == SSA_NAME)
        {
-         value *val = get_value (op0);
+         prop_value_t *val = get_value (op0, true);
          if (val->lattice_val == CONSTANT)
-           op0 = val->const_val;
+           op0 = val->value;
        }
 
       if (TREE_CODE (op1) == SSA_NAME)
        {
-         value *val = get_value (op1);
+         prop_value_t *val = get_value (op1, true);
          if (val->lattice_val == CONSTANT)
-           op1 = val->const_val;
+           op1 = val->value;
        }
 
       retval = fold_binary_to_constant (code, TREE_TYPE (rhs), op0, op1);
@@ -934,7 +951,7 @@ ccp_fold (tree stmt)
            orig[i] = USE_OP (uses, i);
 
          /* Substitute operands with their values and try to fold.  */
-         replace_uses_in (stmt, NULL);
+         replace_uses_in (stmt, NULL, const_val);
          fndecl = get_callee_fndecl (rhs);
          arglist = TREE_OPERAND (rhs, 1);
          retval = fold_builtin (fndecl, arglist, false);
@@ -959,12 +976,14 @@ ccp_fold (tree stmt)
 
 /* Evaluate statement STMT.  */
 
-static value
+static prop_value_t
 evaluate_stmt (tree stmt)
 {
-  value val;
+  prop_value_t val;
   tree simplified;
-  latticevalue likelyvalue = likely_value (stmt);
+  ccp_lattice_t likelyvalue = likely_value (stmt);
+
+  val.mem_ref = NULL_TREE;
 
   /* If the statement is likely to have a CONSTANT result, then try
      to fold the statement to determine the constant value.  */
@@ -983,18 +1002,15 @@ evaluate_stmt (tree stmt)
     {
       /* The statement produced a constant value.  */
       val.lattice_val = CONSTANT;
-      val.const_val = simplified;
+      val.value = simplified;
     }
   else
     {
       /* The statement produced a nonconstant value.  If the statement
-         had undefined or virtual operands, then the result of the 
-        statement should be undefined or virtual respectively.  
-        Else the result of the statement is VARYING.  */
-      val.lattice_val = (likelyvalue == UNDEFINED ? UNDEFINED : VARYING);
-      val.lattice_val = (likelyvalue == UNKNOWN_VAL 
-                           ? UNKNOWN_VAL : val.lattice_val);
-      val.const_val = NULL_TREE;
+        had UNDEFINED operands, then the result of the statement
+        should be UNDEFINED.  Otherwise, the statement is VARYING.  */
+      val.lattice_val = (likelyvalue == UNDEFINED) ? UNDEFINED : VARYING;
+      val.value = NULL_TREE;
     }
 
   return val;
@@ -1002,48 +1018,38 @@ evaluate_stmt (tree stmt)
 
 
 /* Visit the assignment statement STMT.  Set the value of its LHS to the
-   value computed by the RHS and store LHS in *OUTPUT_P.  */
+   value computed by the RHS and store LHS in *OUTPUT_P.  If STMT
+   creates virtual definitions, set the value of each new name to that
+   of the RHS (if we can derive a constant out of the RHS).  */
 
 static enum ssa_prop_result
 visit_assignment (tree stmt, tree *output_p)
 {
-  value val;
+  prop_value_t val;
   tree lhs, rhs;
-  vuse_optype vuses;
-  v_must_def_optype v_must_defs;
+  enum ssa_prop_result retval;
 
   lhs = TREE_OPERAND (stmt, 0);
   rhs = TREE_OPERAND (stmt, 1);
-  vuses = STMT_VUSE_OPS (stmt);
-  v_must_defs = STMT_V_MUST_DEF_OPS (stmt);
-
-  gcc_assert (NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) == 0);
-  gcc_assert (NUM_V_MUST_DEFS (v_must_defs) == 1
-             || TREE_CODE (lhs) == SSA_NAME);
-
-  /* We require the SSA version number of the lhs for the value_vector.
-     Make sure we have it.  */
-  if (TREE_CODE (lhs) != SSA_NAME)
-    {
-      /* If we make it here, then stmt only has one definition:
-         a V_MUST_DEF.  */
-      lhs = V_MUST_DEF_RESULT (v_must_defs, 0);
-    }
 
   if (TREE_CODE (rhs) == SSA_NAME)
     {
       /* For a simple copy operation, we copy the lattice values.  */
-      value *nval = get_value (rhs);
+      prop_value_t *nval = get_value (rhs, true);
       val = *nval;
     }
-  else if (DECL_P (rhs) 
-           && NUM_VUSES (vuses) == 1
-           && rhs == SSA_NAME_VAR (VUSE_OP (vuses, 0)))
+  else if (do_store_ccp && stmt_makes_single_load (stmt))
     {
-      /* Same as above, but the rhs is not a gimple register and yet
-        has a known VUSE.  */
-      value *nval = get_value (VUSE_OP (vuses, 0));
-      val = *nval;
+      /* Same as above, but the RHS is not a gimple register and yet
+         has a known VUSE.  If STMT is loading from the same memory
+        location that created the SSA_NAMEs for the virtual operands,
+        we can propagate the value on the RHS.  */
+      prop_value_t *nval = get_value_loaded_by (stmt, const_val);
+
+      if (nval && simple_cst_equal (nval->mem_ref, rhs) == 1)
+       val = *nval;
+      else
+       val = evaluate_stmt (stmt);
     }
   else
     /* Evaluate the statement.  */
@@ -1063,15 +1069,15 @@ visit_assignment (tree stmt, tree *output_p)
       {
        tree w = fold (build1 (VIEW_CONVERT_EXPR,
                               TREE_TYPE (TREE_OPERAND (orig_lhs, 0)),
-                              val.const_val));
+                              val.value));
 
        orig_lhs = TREE_OPERAND (orig_lhs, 1);
        if (w && is_gimple_min_invariant (w))
-         val.const_val = w;
+         val.value = w;
        else
          {
            val.lattice_val = VARYING;
-           val.const_val = NULL;
+           val.value = NULL;
          }
       }
 
@@ -1079,36 +1085,73 @@ visit_assignment (tree stmt, tree *output_p)
        && TREE_CODE (orig_lhs) == COMPONENT_REF
        && DECL_BIT_FIELD (TREE_OPERAND (orig_lhs, 1)))
       {
-       tree w = widen_bitfield (val.const_val, TREE_OPERAND (orig_lhs, 1),
+       tree w = widen_bitfield (val.value, TREE_OPERAND (orig_lhs, 1),
                                 orig_lhs);
 
        if (w && is_gimple_min_invariant (w))
-         val.const_val = w;
+         val.value = w;
        else
          {
            val.lattice_val = VARYING;
-           val.const_val = NULL;
+           val.value = NULL_TREE;
+           val.mem_ref = NULL_TREE;
          }
       }
   }
 
-  /* If LHS is not a gimple register, then it cannot take on an
-     UNDEFINED value.  */
-  if (!is_gimple_reg (SSA_NAME_VAR (lhs)) 
-      && val.lattice_val == UNDEFINED)
-    val.lattice_val = UNKNOWN_VAL;      
+  retval = SSA_PROP_NOT_INTERESTING;
 
   /* Set the lattice value of the statement's output.  */
-  if (set_lattice_value (lhs, val))
+  if (TREE_CODE (lhs) == SSA_NAME)
     {
-      *output_p = lhs;
-      if (val.lattice_val == VARYING)
-       return SSA_PROP_VARYING;
-      else
-       return SSA_PROP_INTERESTING;
+      /* If STMT is an assignment to an SSA_NAME, we only have one
+        value to set.  */
+      if (set_lattice_value (lhs, val))
+       {
+         *output_p = lhs;
+         if (val.lattice_val == VARYING)
+           retval = SSA_PROP_VARYING;
+         else
+           retval = SSA_PROP_INTERESTING;
+       }
     }
-  else
-    return SSA_PROP_NOT_INTERESTING;
+  else if (do_store_ccp && stmt_makes_single_store (stmt))
+    {
+      /* Otherwise, set the names in V_MAY_DEF/V_MUST_DEF operands
+        to the new constant value and mark the LHS as the memory
+        reference associated with VAL.  */
+      ssa_op_iter i;
+      tree vdef;
+      bool changed;
+
+      /* Stores cannot take on an UNDEFINED value.  */
+      if (val.lattice_val == UNDEFINED)
+       val.lattice_val = UNKNOWN_VAL;      
+
+      /* Mark VAL as stored in the LHS of this assignment.  */
+      val.mem_ref = lhs;
+
+      /* Set the value of every VDEF to VAL.  */
+      changed = false;
+      FOR_EACH_SSA_TREE_OPERAND (vdef, stmt, i, SSA_OP_VIRTUAL_DEFS)
+       changed |= set_lattice_value (vdef, val);
+      
+      /* Note that for propagation purposes, we are only interested in
+        visiting statements that load the exact same memory reference
+        stored here.  Those statements will have the exact same list
+        of virtual uses, so it is enough to set the output of this
+        statement to be its first virtual definition.  */
+      *output_p = first_vdef (stmt);
+      if (changed)
+       {
+         if (val.lattice_val == VARYING)
+           retval = SSA_PROP_VARYING;
+         else 
+           retval = SSA_PROP_INTERESTING;
+       }
+    }
+
+  return retval;
 }
 
 
@@ -1119,7 +1162,7 @@ visit_assignment (tree stmt, tree *output_p)
 static enum ssa_prop_result
 visit_cond_stmt (tree stmt, edge *taken_edge_p)
 {
-  value val;
+  prop_value_t val;
   basic_block block;
 
   block = bb_for_stmt (stmt);
@@ -1129,7 +1172,7 @@ visit_cond_stmt (tree stmt, edge *taken_edge_p)
      to the worklist.  If no single edge can be determined statically,
      return SSA_PROP_VARYING to feed all the outgoing edges to the
      propagation engine.  */
-  *taken_edge_p = val.const_val ? find_taken_edge (block, val.const_val) : 0;
+  *taken_edge_p = val.value ? find_taken_edge (block, val.value) : 0;
   if (*taken_edge_p)
     return SSA_PROP_INTERESTING;
   else
@@ -1157,8 +1200,8 @@ ccp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p)
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      fprintf (dump_file, "\nVisiting statement: ");
-      print_generic_stmt (dump_file, stmt, TDF_SLIM);
+      fprintf (dump_file, "\nVisiting statement:\n");
+      print_generic_stmt (dump_file, stmt, dump_flags);
       fprintf (dump_file, "\n");
     }
 
@@ -1166,10 +1209,7 @@ ccp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p)
 
   v_must_defs = V_MUST_DEF_OPS (ann);
   v_may_defs = V_MAY_DEF_OPS (ann);
-  if (TREE_CODE (stmt) == MODIFY_EXPR
-      && NUM_V_MAY_DEFS (v_may_defs) == 0
-      && (NUM_V_MUST_DEFS (v_must_defs) == 1
-          || TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME))
+  if (TREE_CODE (stmt) == MODIFY_EXPR)
     {
       /* If the statement is an assignment that produces a single
         output value, evaluate its RHS to see if the lattice value of
@@ -1191,30 +1231,35 @@ ccp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p)
   /* Definitions made by statements other than assignments to
      SSA_NAMEs represent unknown modifications to their outputs.
      Mark them VARYING.  */
-  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
-    def_to_varying (def);
-
-  /* Mark all V_MAY_DEF operands VARYING.  */
-  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_VMAYDEF)
-    def_to_varying (def);
+  FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
+    {
+      prop_value_t v = { VARYING, NULL_TREE, NULL_TREE };
+      set_lattice_value (def, v);
+    }
 
   return SSA_PROP_VARYING;
 }
 
 
-/* Main entry point for SSA Conditional Constant Propagation.
-
-   [ DESCRIBE MAIN ALGORITHM HERE ]  */
+/* Main entry point for SSA Conditional Constant Propagation.  */
 
 static void
-execute_ssa_ccp (void)
+execute_ssa_ccp (bool store_ccp)
 {
+  do_store_ccp = store_ccp;
   ccp_initialize ();
   ssa_propagate (ccp_visit_stmt, ccp_visit_phi_node);
   ccp_finalize ();
 }
 
 
+static void
+do_ssa_ccp (void)
+{
+  execute_ssa_ccp (false);
+}
+
+
 static bool
 gate_ccp (void)
 {
@@ -1226,7 +1271,7 @@ struct tree_opt_pass pass_ccp =
 {
   "ccp",                               /* name */
   gate_ccp,                            /* gate */
-  execute_ssa_ccp,                     /* execute */
+  do_ssa_ccp,                          /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
@@ -1235,13 +1280,50 @@ struct tree_opt_pass pass_ccp =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_cleanup_cfg | TODO_dump_func | TODO_rename_vars
+  TODO_cleanup_cfg | TODO_dump_func | TODO_update_ssa
     | TODO_ggc_collect | TODO_verify_ssa
     | TODO_verify_stmts,               /* todo_flags_finish */
   0                                    /* letter */
 };
 
 
+static void
+do_ssa_store_ccp (void)
+{
+  /* If STORE-CCP is not enabled, we just run regular CCP.  */
+  execute_ssa_ccp (flag_tree_store_ccp != 0);
+}
+
+static bool
+gate_store_ccp (void)
+{
+  /* STORE-CCP is enabled only with -ftree-store-ccp, but when
+     -fno-tree-store-ccp is specified, we should run regular CCP.
+     That's why the pass is enabled with either flag.  */
+  return flag_tree_store_ccp != 0 || flag_tree_ccp != 0;
+}
+
+
+struct tree_opt_pass pass_store_ccp = 
+{
+  "store_ccp",                         /* name */
+  gate_store_ccp,                      /* gate */
+  do_ssa_store_ccp,                    /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_TREE_STORE_CCP,                   /* tv_id */
+  PROP_cfg | PROP_ssa | PROP_alias,    /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_dump_func | TODO_update_ssa
+    | TODO_ggc_collect | TODO_verify_ssa
+    | TODO_cleanup_cfg
+    | TODO_verify_stmts,               /* todo_flags_finish */
+  0                                    /* letter */
+};
+
 /* Given a constant value VAL for bitfield FIELD, and a destination
    variable VAR, return VAL appropriately widened to fit into VAR.  If
    FIELD is wider than HOST_WIDE_INT, NULL is returned.  */
@@ -2132,7 +2214,7 @@ convert_to_gimple_builtin (block_stmt_iterator *si_p, tree expr)
   for (ti = tsi_start (stmts); !tsi_end_p (ti); tsi_next (&ti))
     {
       find_new_referenced_vars (tsi_stmt_ptr (ti));
-      mark_new_vars_to_rename (tsi_stmt (ti), vars_to_rename);
+      mark_new_vars_to_rename (tsi_stmt (ti));
     }
 
   if (EXPR_HAS_LOCATION (stmt))
@@ -2233,6 +2315,6 @@ struct tree_opt_pass pass_fold_builtins =
   0,                                   /* todo_flags_start */
   TODO_dump_func
     | TODO_verify_ssa
-    | TODO_rename_vars,                        /* todo_flags_finish */
+    | TODO_update_ssa,                 /* todo_flags_finish */
   0                                    /* letter */
 };
index 8350047..baca99c 100644 (file)
@@ -1,4 +1,4 @@
-/* Const/copy propagation and SSA_NAME replacement support routines.
+/* Copy propagation and SSA_NAME replacement support routines.
    Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -37,11 +37,13 @@ Boston, MA 02111-1307, USA.  */
 #include "tree-dump.h"
 #include "tree-flow.h"
 #include "tree-pass.h"
+#include "tree-ssa-propagate.h"
 #include "langhooks.h"
 
-/* This file provides a handful of interfaces for performing const/copy
-   propagation and simple expression replacement which keep variable
-   annotations up-to-date.
+/* This file implements the copy propagation pass and provides a
+   handful of interfaces for performing const/copy propagation and
+   simple expression replacement which keep variable annotations
+   up-to-date.
 
    We require that for any copy operation where the RHS and LHS have
    a non-null memory tag the memory tag be the same.   It is OK
@@ -54,7 +56,6 @@ Boston, MA 02111-1307, USA.  */
    replacements of one SSA_NAME with a different SSA_NAME to use the
    APIs defined in this file.  */
 
-
 /* Return true if we may propagate ORIG into DEST, false otherwise.  */
 
 bool
@@ -103,8 +104,10 @@ may_propagate_copy (tree dest, tree orig)
      I think that GIMPLE should emit the appropriate type-casts.  For the
      time being, blocking copy-propagation in these cases is the safe thing
      to do.  */
-  if (TREE_CODE (dest) == SSA_NAME && TREE_CODE (orig) == SSA_NAME
-      && POINTER_TYPE_P (type_d) && POINTER_TYPE_P (type_o))
+  if (TREE_CODE (dest) == SSA_NAME
+      && TREE_CODE (orig) == SSA_NAME
+      && POINTER_TYPE_P (type_d)
+      && POINTER_TYPE_P (type_o))
     {
       tree mt_dest = var_ann (SSA_NAME_VAR (dest))->type_mem_tag;
       tree mt_orig = var_ann (SSA_NAME_VAR (orig))->type_mem_tag;
@@ -123,17 +126,9 @@ may_propagate_copy (tree dest, tree orig)
     {
       /* If both operands are SSA_NAMEs referring to virtual operands, then
         we can always propagate.  */
-      if (TREE_CODE (orig) == SSA_NAME)
-       {
-         if (!is_gimple_reg (orig))
-           return true;
-
-#ifdef ENABLE_CHECKING
-         /* If we have one real and one virtual operand, then something has
-            gone terribly wrong.  */
-         gcc_assert (!is_gimple_reg (orig));
-#endif
-       }
+      if (TREE_CODE (orig) == SSA_NAME
+         && !is_gimple_reg (orig))
+       return true;
 
       /* We have a "copy" from something like a constant into a virtual
         operand.  Reject these.  */
@@ -202,30 +197,33 @@ merge_alias_info (tree orig, tree new)
   else
     gcc_assert (new_ann->type_mem_tag == orig_ann->type_mem_tag);
 
-#if defined ENABLE_CHECKING
-  {
-    struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig);
-    struct ptr_info_def *new_ptr_info = SSA_NAME_PTR_INFO (new);
-
-    if (orig_ptr_info
-       && new_ptr_info
-       && orig_ptr_info->name_mem_tag
-       && new_ptr_info->name_mem_tag
-       && orig_ptr_info->pt_vars
-       && new_ptr_info->pt_vars)
+  /* Synchronize the name tags.  If NEW did not have a name tag, get
+     it from ORIG.  This happens when NEW is a compiler generated
+     temporary which still hasn't had its points-to information filled
+     in.  */
+  if (SSA_NAME_PTR_INFO (orig))
     {
-      /* Note that pointer NEW may actually have a different set of
-        pointed-to variables.  However, since NEW is being
-        copy-propagated into ORIG, it must always be true that the
-        pointed-to set for pointer NEW is the same, or a subset, of
-        the pointed-to set for pointer ORIG.  If this isn't the case,
-        we shouldn't have been able to do the propagation of NEW into
-        ORIG.  */
-      gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
-                                     orig_ptr_info->pt_vars));
+      struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig);
+      struct ptr_info_def *new_ptr_info = SSA_NAME_PTR_INFO (new);
+
+      if (new_ptr_info == NULL)
+       duplicate_ssa_name_ptr_info (new, orig_ptr_info);
+      else if (orig_ptr_info->name_mem_tag
+              && new_ptr_info->name_mem_tag
+              && orig_ptr_info->pt_vars
+              && new_ptr_info->pt_vars)
+       {
+         /* Note that pointer NEW may actually have a different set
+            of pointed-to variables.  However, since NEW is being
+            copy-propagated into ORIG, it must always be true that
+            the pointed-to set for pointer NEW is the same, or a
+            subset, of the pointed-to set for pointer ORIG.  If this
+            isn't the case, we shouldn't have been able to do the
+            propagation of NEW into ORIG.  */
+         gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
+               orig_ptr_info->pt_vars));
+       }
     }
-  }
-#endif
 }   
 
 
@@ -310,3 +308,776 @@ replace_exp (use_operand_p op_p, tree val)
 {
   replace_exp_1 (op_p, val, false);
 }
+
+
+/*---------------------------------------------------------------------------
+                               Copy propagation
+---------------------------------------------------------------------------*/
+/* During propagation, we keep chains of variables that are copies of
+   one another.  If variable X_i is a copy of X_j and X_j is a copy of
+   X_k, COPY_OF will contain:
+
+       COPY_OF[i].VALUE = X_j
+       COPY_OF[j].VALUE = X_k
+       COPY_OF[k].VALUE = X_k
+
+   After propagation, the copy-of value for each variable X_i is
+   converted into the final value by walking the copy-of chains and
+   updating COPY_OF[i].VALUE to be the last element of the chain.  */
+static prop_value_t *copy_of;
+
+/* Used in set_copy_of_val to determine if the last link of a copy-of
+   chain has changed.  */
+static tree *cached_last_copy_of;
+
+/* True if we are doing copy propagation on loads and stores.  */
+static bool do_store_copy_prop;
+
+
+/* Return true if this statement may generate a useful copy.  */
+
+static bool
+stmt_may_generate_copy (tree stmt)
+{
+  tree lhs, rhs;
+  stmt_ann_t ann;
+
+  if (TREE_CODE (stmt) == PHI_NODE)
+    return !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (stmt));
+
+  if (TREE_CODE (stmt) != MODIFY_EXPR)
+    return false;
+
+  lhs = TREE_OPERAND (stmt, 0);
+  rhs = TREE_OPERAND (stmt, 1);
+  ann = stmt_ann (stmt);
+
+  /* If the statement has volatile operands, it won't generate a
+     useful copy.  */
+  if (ann->has_volatile_ops)
+    return false;
+
+  /* If we are not doing store copy-prop, statements with loads and/or
+     stores will never generate a useful copy.  */
+  if (!do_store_copy_prop
+      && (NUM_VUSES (VUSE_OPS (ann)) > 0
+         || NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) > 0
+         || NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) > 0))
+    return false;
+
+  /* Otherwise, the only statements that generate useful copies are
+     assignments whose RHS is just an SSA name that doesn't flow
+     through abnormal edges.  */
+  return TREE_CODE (rhs) == SSA_NAME && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs);
+}
+
+
+/* Return the copy-of value for VAR.  */
+
+static inline prop_value_t *
+get_copy_of_val (tree var)
+{
+  prop_value_t *val = &copy_of[SSA_NAME_VERSION (var)];
+
+  if (val->value == NULL_TREE
+      && !stmt_may_generate_copy (SSA_NAME_DEF_STMT (var)))
+    {
+      /* If the variable will never generate a useful copy relation,
+        make it its own copy.  */
+      val->value = var;
+      val->mem_ref = NULL_TREE;
+    }
+
+  return val;
+}
+
+
+/* Return last link in the copy-of chain for VAR.  */
+
+static tree
+get_last_copy_of (tree var)
+{
+  tree last;
+  int i;
+
+  /* Traverse COPY_OF starting at VAR until we get to the last
+     link in the chain.  Since it is possible to have cycles in PHI
+     nodes, the copy-of chain may also contain cycles.
+     
+     To avoid infinite loops and to avoid traversing lengthy copy-of
+     chains, we artificially limit the maximum number of chains we are
+     willing to traverse.
+
+     The value 5 was taken from a compiler and runtime library
+     bootstrap and a mixture of C and C++ code from various sources.
+     More than 82% of all copy-of chains were shorter than 5 links.  */
+#define LIMIT  5
+
+  last = var;
+  for (i = 0; i < LIMIT; i++)
+    {
+      tree copy = copy_of[SSA_NAME_VERSION (last)].value;
+      if (copy == NULL_TREE || copy == last)
+       break;
+      last = copy;
+    }
+
+  /* If we have reached the limit, then we are either in a copy-of
+     cycle or the copy-of chain is too long.  In this case, just
+     return VAR so that it is not considered a copy of anything.  */
+  return (i < LIMIT ? last : var);
+}
+
+
+/* Set FIRST to be the first variable in the copy-of chain for DEST.
+   If DEST's copy-of value or its copy-of chain have changed, return
+   true.
+
+   MEM_REF is the memory reference where FIRST is stored.  This is
+   used when DEST is a non-register and we are copy propagating loads
+   and stores.  */
+
+static inline bool
+set_copy_of_val (tree dest, tree first, tree mem_ref)
+{
+  unsigned int dest_ver = SSA_NAME_VERSION (dest);
+  tree old_first, old_last, new_last;
+  
+  /* Set FIRST to be the first link in COPY_OF[DEST].  If that
+     changed, return true.  */
+  old_first = copy_of[dest_ver].value;
+  copy_of[dest_ver].value = first;
+  copy_of[dest_ver].mem_ref = mem_ref;
+
+  if (old_first != first)
+    return true;
+
+  /* If FIRST and OLD_FIRST are the same, we need to check whether the
+     copy-of chain starting at FIRST ends in a different variable.  If
+     the copy-of chain starting at FIRST ends up in a different
+     variable than the last cached value we had for DEST, then return
+     true because DEST is now a copy of a different variable.
+
+     This test is necessary because even though the first link in the
+     copy-of chain may not have changed, if any of the variables in
+     the copy-of chain changed its final value, DEST will now be the
+     copy of a different variable, so we have to do another round of
+     propagation for everything that depends on DEST.  */
+  old_last = cached_last_copy_of[dest_ver];
+  new_last = get_last_copy_of (dest);
+  cached_last_copy_of[dest_ver] = new_last;
+
+  return (old_last != new_last);
+}
+
+
+/* Dump the copy-of value for variable VAR to DUMP_FILE.  */
+
+static void
+dump_copy_of (FILE *dump_file, tree var)
+{
+  tree val;
+
+  print_generic_expr (dump_file, var, dump_flags);
+
+  if (TREE_CODE (var) != SSA_NAME)
+    return;
+
+  fprintf (dump_file, " copy-of chain: ");
+
+  val = var;
+  print_generic_expr (dump_file, val, 0);
+  fprintf (dump_file, " ");
+  while (copy_of[SSA_NAME_VERSION (val)].value
+         && copy_of[SSA_NAME_VERSION (val)].value != val)
+    {
+      fprintf (dump_file, "-> ");
+      val = copy_of[SSA_NAME_VERSION (val)].value;
+      print_generic_expr (dump_file, val, 0);
+      fprintf (dump_file, " ");
+    }
+
+  val = get_copy_of_val (var)->value;
+  if (val == NULL_TREE)
+    fprintf (dump_file, "[UNDEFINED]");
+  else if (val != var)
+    fprintf (dump_file, "[COPY]");
+  else
+    fprintf (dump_file, "[NOT A COPY]");
+}
+
+
+/* Evaluate the RHS of STMT.  If it produces a valid copy, set the LHS
+   value and store the LHS into *RESULT_P.  If STMT generates more
+   than one name (i.e., STMT is an aliased store), it is enough to
+   store the first name in the V_MAY_DEF list into *RESULT_P.  After
+   all, the names generated will be VUSEd in the same statements.  */
+
+static enum ssa_prop_result
+copy_prop_visit_assignment (tree stmt, tree *result_p)
+{
+  tree lhs, rhs;
+  prop_value_t *rhs_val;
+
+  lhs = TREE_OPERAND (stmt, 0);
+  rhs = TREE_OPERAND (stmt, 1);
+
+  gcc_assert (TREE_CODE (rhs) == SSA_NAME);
+
+  rhs_val = get_copy_of_val (rhs);
+
+  if (TREE_CODE (lhs) == SSA_NAME)
+    {
+      /* Straight copy between two SSA names.  First, make sure that
+        we can propagate the RHS into uses of LHS.  */
+      if (!may_propagate_copy (lhs, rhs))
+       return SSA_PROP_VARYING;
+
+      /* Avoid copy propagation from an inner into an outer loop.
+        Otherwise, this may move loop variant variables outside of
+        their loops and prevent coalescing opportunities.  If the
+        value was loop invariant, it will be hoisted by LICM and
+        exposed for copy propagation.  */
+      if (loop_depth_of_name (rhs) > loop_depth_of_name (lhs))
+       return SSA_PROP_VARYING;
+
+      /* Notice that in the case of assignments, we make the LHS be a
+        copy of RHS's value, not of RHS itself.  This avoids keeping
+        unnecessary copy-of chains (assignments cannot be in a cycle
+        like PHI nodes), speeding up the propagation process.
+        This is different from what we do in copy_prop_visit_phi_node. 
+        In those cases, we are interested in the copy-of chains.  */
+      *result_p = lhs;
+      if (set_copy_of_val (*result_p, rhs_val->value, rhs_val->mem_ref))
+       return SSA_PROP_INTERESTING;
+      else
+       return SSA_PROP_NOT_INTERESTING;
+    }
+  else if (stmt_makes_single_store (stmt))
+    {
+      /* Otherwise, set the names in V_MAY_DEF/V_MUST_DEF operands
+        to be a copy of RHS.  */
+      ssa_op_iter i;
+      tree vdef;
+      bool changed;
+
+      /* This should only be executed when doing store copy-prop.  */
+      gcc_assert (do_store_copy_prop);
+
+      /* Set the value of every VDEF to RHS_VAL.  */
+      changed = false;
+      FOR_EACH_SSA_TREE_OPERAND (vdef, stmt, i, SSA_OP_VIRTUAL_DEFS)
+       changed |= set_copy_of_val (vdef, rhs_val->value, lhs);
+      
+      /* Note that for propagation purposes, we are only interested in
+        visiting statements that load the exact same memory reference
+        stored here.  Those statements will have the exact same list
+        of virtual uses, so it is enough to set the output of this
+        statement to be its first virtual definition.  */
+      *result_p = first_vdef (stmt);
+
+      if (changed)
+       return SSA_PROP_INTERESTING;
+      else
+       return SSA_PROP_NOT_INTERESTING;
+    }
+
+
+  return SSA_PROP_VARYING;
+}
+
+
+/* Visit the COND_EXPR STMT.  Return SSA_PROP_INTERESTING
+   if it can determine which edge will be taken.  Otherwise, return
+   SSA_PROP_VARYING.  */
+
+static enum ssa_prop_result
+copy_prop_visit_cond_stmt (tree stmt, edge *taken_edge_p)
+{
+  enum ssa_prop_result retval;
+  tree cond;
+  use_optype uses;
+
+  cond = COND_EXPR_COND (stmt);
+  uses = STMT_USE_OPS (stmt);
+  retval = SSA_PROP_VARYING;
+
+  /* The only conditionals that we may be able to compute statically
+     are predicates involving at least one SSA_NAME.  */
+  if (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
+      && NUM_USES (uses) >= 1)
+    {
+      unsigned i;
+      tree *orig;
+
+      /* Save the original operands.  */
+      orig = xmalloc (sizeof (tree) * NUM_USES (uses));
+      for (i = 0; i < NUM_USES (uses); i++)
+       {
+         orig[i] = USE_OP (uses, i);
+         SET_USE_OP (uses, i, get_last_copy_of (USE_OP (uses, i)));
+       }
+
+      /* See if we can determine the predicate's value.  */
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Trying to determine truth value of ");
+         fprintf (dump_file, "predicate ");
+         print_generic_stmt (dump_file, cond, 0);
+       }
+
+      *taken_edge_p = find_taken_edge (bb_for_stmt (stmt), cond);
+      if (*taken_edge_p)
+       retval = SSA_PROP_INTERESTING;
+
+      /* Restore the original operands.  */
+      for (i = 0; i < NUM_USES (uses); i++)
+       SET_USE_OP (uses, i, orig[i]);
+      free (orig);
+    }
+
+  if (dump_file && (dump_flags & TDF_DETAILS) && *taken_edge_p)
+    fprintf (dump_file, "\nConditional will always take edge %d->%d\n",
+            (*taken_edge_p)->src->index, (*taken_edge_p)->dest->index);
+
+  return retval;
+}
+
+
+/* Evaluate statement STMT.  If the statement produces a new output
+   value, return SSA_PROP_INTERESTING and store the SSA_NAME holding
+   the new value in *RESULT_P.
+
+   If STMT is a conditional branch and we can determine its truth
+   value, set *TAKEN_EDGE_P accordingly.
+
+   If the new value produced by STMT is varying, return
+   SSA_PROP_VARYING.  */
+
+static enum ssa_prop_result
+copy_prop_visit_stmt (tree stmt, edge *taken_edge_p, tree *result_p)
+{
+  stmt_ann_t ann;
+  enum ssa_prop_result retval;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "\nVisiting statement:\n");
+      print_generic_stmt (dump_file, stmt, dump_flags);
+      fprintf (dump_file, "\n");
+    }
+
+  ann = stmt_ann (stmt);
+
+  if (TREE_CODE (stmt) == MODIFY_EXPR
+      && TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME
+      && (do_store_copy_prop
+         || TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME))
+    {
+      /* If the statement is a copy assignment, evaluate its RHS to
+        see if the lattice value of its output has changed.  */
+      retval = copy_prop_visit_assignment (stmt, result_p);
+    }
+  else if (TREE_CODE (stmt) == COND_EXPR)
+    {
+      /* See if we can determine which edge goes out of a conditional
+        jump.  */
+      retval = copy_prop_visit_cond_stmt (stmt, taken_edge_p);
+    }
+  else
+    retval = SSA_PROP_VARYING;
+
+  if (retval == SSA_PROP_VARYING)
+    {
+      tree def;
+      ssa_op_iter i;
+
+      /* Any other kind of statement is not interesting for constant
+        propagation and, therefore, not worth simulating.  */
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, "No interesting values produced.\n");
+
+      /* The assignment is not a copy operation.  Don't visit this
+        statement again and mark all the definitions in the statement
+        to be copies of nothing.  */
+      FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_ALL_DEFS)
+       set_copy_of_val (def, def, NULL_TREE);
+    }
+
+  return retval;
+}
+
+
+/* Visit PHI node PHI.  If all the arguments produce the same value,
+   set it to be the value of the LHS of PHI.  */
+
+static enum ssa_prop_result
+copy_prop_visit_phi_node (tree phi)
+{
+  enum ssa_prop_result retval;
+  int i;
+  tree lhs;
+  prop_value_t phi_val = { 0, NULL_TREE, NULL_TREE };
+
+  lhs = PHI_RESULT (phi);
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "\nVisiting PHI node: ");
+      print_generic_expr (dump_file, phi, dump_flags);
+      fprintf (dump_file, "\n\n");
+    }
+
+  for (i = 0; i < PHI_NUM_ARGS (phi); i++)
+    {
+      prop_value_t *arg_val;
+      tree arg = PHI_ARG_DEF (phi, i);
+      edge e = PHI_ARG_EDGE (phi, i);
+
+      /* We don't care about values flowing through non-executable
+        edges.  */
+      if (!(e->flags & EDGE_EXECUTABLE))
+       continue;
+
+      /* Constants in the argument list never generate a useful copy.
+        Similarly, names that flow through abnormal edges cannot be
+        used to derive copies.  */
+      if (TREE_CODE (arg) != SSA_NAME || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (arg))
+       {
+         phi_val.value = lhs;
+         break;
+       }
+
+      /* Avoid copy propagation from an inner into an outer loop.
+        Otherwise, this may move loop variant variables outside of
+        their loops and prevent coalescing opportunities.  If the
+        value was loop invariant, it will be hoisted by LICM and
+        exposed for copy propagation.  */
+      if (loop_depth_of_name (arg) > loop_depth_of_name (lhs))
+       {
+         phi_val.value = lhs;
+         break;
+       }
+
+      /* If the LHS appears in the argument list, ignore it.  It is
+        irrelevant as a copy.  */
+      if (arg == lhs || get_last_copy_of (arg) == lhs)
+       continue;
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "\tArgument #%d: ", i);
+         dump_copy_of (dump_file, arg);
+         fprintf (dump_file, "\n");
+       }
+
+      arg_val = get_copy_of_val (arg);
+
+      /* If the LHS didn't have a value yet, make it a copy of the
+        first argument we find.  Notice that while we make the LHS be
+        a copy of the argument itself, we take the memory reference
+        from the argument's value so that we can compare it to the
+        memory reference of all the other arguments.  */
+      if (phi_val.value == NULL_TREE)
+       {
+         phi_val.value = arg;
+         phi_val.mem_ref = arg_val->mem_ref;
+         continue;
+       }
+
+      /* If PHI_VAL and ARG don't have a common copy-of chain, then
+        this PHI node cannot be a copy operation.  Also, if we are
+        copy propagating stores and these two arguments came from
+        different memory references, they cannot be considered
+        copies.  */
+      if (get_last_copy_of (phi_val.value) != get_last_copy_of (arg)
+         || (do_store_copy_prop
+             && phi_val.mem_ref
+             && arg_val->mem_ref
+             && simple_cst_equal (phi_val.mem_ref, arg_val->mem_ref) != 1))
+       {
+         phi_val.value = lhs;
+         break;
+       }
+    }
+
+  if (phi_val.value && set_copy_of_val (lhs, phi_val.value, phi_val.mem_ref))
+    retval = (phi_val.value != lhs) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING;
+  else
+    retval = SSA_PROP_NOT_INTERESTING;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "\nPHI node ");
+      dump_copy_of (dump_file, lhs);
+      fprintf (dump_file, "\nTelling the propagator to ");
+      if (retval == SSA_PROP_INTERESTING)
+       fprintf (dump_file, "add SSA edges out of this PHI and continue.");
+      else if (retval == SSA_PROP_VARYING)
+       fprintf (dump_file, "add SSA edges out of this PHI and never visit again.");
+      else
+       fprintf (dump_file, "do nothing with SSA edges and keep iterating.");
+      fprintf (dump_file, "\n\n");
+    }
+
+  return retval;
+}
+
+
+/* Initialize structures used for copy propagation.  */
+
+static void
+init_copy_prop (void)
+{
+  basic_block bb;
+
+  copy_of = xmalloc (num_ssa_names * sizeof (*copy_of));
+  memset (copy_of, 0, num_ssa_names * sizeof (*copy_of));
+
+  cached_last_copy_of = xmalloc (num_ssa_names * sizeof (*cached_last_copy_of));
+  memset (cached_last_copy_of, 0, num_ssa_names * sizeof (*cached_last_copy_of));
+
+  FOR_EACH_BB (bb)
+    {
+      block_stmt_iterator si;
+      tree phi;
+
+      for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+       {
+         tree stmt = bsi_stmt (si);
+
+         /* The only statements that we care about are those that may
+            generate useful copies.  We also need to mark conditional
+            jumps so that their outgoing edges are added to the work
+            lists of the propagator.  */
+         if (stmt_ends_bb_p (stmt))
+           DONT_SIMULATE_AGAIN (stmt) = false;
+         else if (stmt_may_generate_copy (stmt))
+           DONT_SIMULATE_AGAIN (stmt) = false;
+         else
+           {
+             tree def;
+             ssa_op_iter iter;
+
+             /* No need to simulate this statement anymore.  */
+             DONT_SIMULATE_AGAIN (stmt) = true;
+
+             /* Mark all the outputs of this statement as not being
+                the copy of anything.  */
+             FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
+               set_copy_of_val (def, def, NULL_TREE);
+           }
+       }
+
+      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+       DONT_SIMULATE_AGAIN (phi) = false;
+    }
+}
+
+
+/* Deallocate memory used in copy propagation and do final
+   substitution.  */
+
+static void
+fini_copy_prop (void)
+{
+  size_t i;
+  
+  /* Set the final copy-of value for each variable by traversing the
+     copy-of chains.  */
+  for (i = 1; i < num_ssa_names; i++)
+    {
+      tree var = ssa_name (i);
+      if (var && copy_of[i].value && copy_of[i].value != var)
+       copy_of[i].value = get_last_copy_of (var);
+    }
+
+  substitute_and_fold (copy_of);
+
+  free (copy_of);
+}
+
+
+/* Main entry point to the copy propagator.  The algorithm propagates
+   the value COPY-OF using ssa_propagate.  For every variable X_i,
+   COPY-OF(X_i) indicates which variable is X_i created from.  The
+   following example shows how the algorithm proceeds at a high level:
+
+           1   a_24 = x_1
+           2   a_2 = PHI <a_24, x_1>
+           3   a_5 = PHI <a_2>
+           4   x_1 = PHI <x_298, a_5, a_2>
+
+   The end result should be that a_2, a_5, a_24 and x_1 are a copy of
+   x_298.  Propagation proceeds as follows.
+
+   Visit #1: a_24 is copy-of x_1.  Value changed.
+   Visit #2: a_2 is copy-of x_1.  Value changed.
+   Visit #3: a_5 is copy-of x_1.  Value changed.
+   Visit #4: x_1 is copy-of x_298.  Value changed.
+   Visit #1: a_24 is copy-of x_298.  Value changed.
+   Visit #2: a_2 is copy-of x_298.  Value changed.
+   Visit #3: a_5 is copy-of x_298.  Value changed.
+   Visit #4: x_1 is copy-of x_298.  Stable state reached.
+   
+   When visiting PHI nodes, we only consider arguments that flow
+   through edges marked executable by the propagation engine.  So,
+   when visiting statement #2 for the first time, we will only look at
+   the first argument (a_24) and optimistically assume that its value
+   is the copy of a_24 (x_1).
+
+   The problem with this approach is that it may fail to discover copy
+   relations in PHI cycles.  Instead of propagating copy-of
+   values, we actually propagate copy-of chains.  For instance:
+
+               A_3 = B_1;
+               C_9 = A_3;
+               D_4 = C_9;
+               X_i = D_4;
+
+   In this code fragment, COPY-OF (X_i) = { D_4, C_9, A_3, B_1 }.
+   Obviously, we are only really interested in the last value of the
+   chain, however the propagator needs to access the copy-of chain
+   when visiting PHI nodes.
+
+   To represent the copy-of chain, we use the array COPY_CHAINS, which
+   holds the first link in the copy-of chain for every variable.
+   If variable X_i is a copy of X_j, which in turn is a copy of X_k,
+   the array will contain:
+
+               COPY_CHAINS[i] = X_j
+               COPY_CHAINS[j] = X_k
+               COPY_CHAINS[k] = X_k
+
+   Keeping copy-of chains instead of copy-of values directly becomes
+   important when visiting PHI nodes.  Suppose that we had the
+   following PHI cycle, such that x_52 is already considered a copy of
+   x_53:
+
+           1   x_54 = PHI <x_53, x_52>
+           2   x_53 = PHI <x_898, x_54>
+   
+   Visit #1: x_54 is copy-of x_53 (because x_52 is copy-of x_53)
+   Visit #2: x_53 is copy-of x_898 (because x_54 is a copy of x_53,
+                                   so it is considered irrelevant
+                                   as a copy).
+   Visit #1: x_54 is copy-of nothing (x_53 is a copy-of x_898 and
+                                     x_52 is a copy of x_53, so
+                                     they don't match)
+   Visit #2: x_53 is copy-of nothing
+
+   This problem is avoided by keeping a chain of copies, instead of
+   the final copy-of value.  Propagation will now only keep the first
+   element of a variable's copy-of chain.  When visiting PHI nodes,
+   arguments are considered equal if their copy-of chains end in the
+   same variable.  So, as long as their copy-of chains overlap, we
+   know that they will be a copy of the same variable, regardless of
+   which variable that may be).
+   
+   Propagation would then proceed as follows (the notation a -> b
+   means that a is a copy-of b):
+
+   Visit #1: x_54 = PHI <x_53, x_52>
+               x_53 -> x_53
+               x_52 -> x_53
+               Result: x_54 -> x_53.  Value changed.  Add SSA edges.
+
+   Visit #1: x_53 = PHI <x_898, x_54>
+               x_898 -> x_898
+               x_54 -> x_53
+               Result: x_53 -> x_898.  Value changed.  Add SSA edges.
+
+   Visit #2: x_54 = PHI <x_53, x_52>
+               x_53 -> x_898
+               x_52 -> x_53 -> x_898
+               Result: x_54 -> x_898.  Value changed.  Add SSA edges.
+
+   Visit #2: x_53 = PHI <x_898, x_54>
+               x_898 -> x_898
+               x_54 -> x_898
+               Result: x_53 -> x_898.  Value didn't change.  Stable state
+
+   Once the propagator stabilizes, we end up with the desired result
+   x_53 and x_54 are both copies of x_898.  */
+
+static void
+execute_copy_prop (bool store_copy_prop)
+{
+  do_store_copy_prop = store_copy_prop;
+  init_copy_prop ();
+  ssa_propagate (copy_prop_visit_stmt, copy_prop_visit_phi_node);
+  fini_copy_prop ();
+}
+
+
+static bool
+gate_copy_prop (void)
+{
+  return flag_tree_copy_prop != 0;
+}
+
+static void
+do_copy_prop (void)
+{
+  execute_copy_prop (false);
+}
+
+struct tree_opt_pass pass_copy_prop =
+{
+  "copyprop",                          /* name */
+  gate_copy_prop,                      /* gate */
+  do_copy_prop,                                /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_TREE_COPY_PROP,                   /* tv_id */
+  PROP_ssa | PROP_alias | PROP_cfg,    /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_cleanup_cfg
+    | TODO_dump_func
+    | TODO_ggc_collect
+    | TODO_verify_ssa
+    | TODO_update_ssa,                 /* todo_flags_finish */
+  0                                    /* letter */
+};
+
+
+static bool
+gate_store_copy_prop (void)
+{
+  /* STORE-COPY-PROP is enabled only with -ftree-store-copy-prop, but
+     when -fno-tree-store-copy-prop is specified, we should run
+     regular COPY-PROP. That's why the pass is enabled with either
+     flag.  */
+  return flag_tree_store_copy_prop != 0 || flag_tree_copy_prop != 0;
+}
+
+static void
+store_copy_prop (void)
+{
+  /* If STORE-COPY-PROP is not enabled, we just run regular COPY-PROP.  */
+  execute_copy_prop (flag_tree_store_copy_prop != 0);
+}
+
+struct tree_opt_pass pass_store_copy_prop =
+{
+  "store_copyprop",                    /* name */
+  gate_store_copy_prop,                        /* gate */
+  store_copy_prop,                     /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_TREE_STORE_COPY_PROP,             /* tv_id */
+  PROP_ssa | PROP_alias | PROP_cfg,    /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_dump_func
+    | TODO_cleanup_cfg
+    | TODO_ggc_collect
+    | TODO_verify_ssa
+    | TODO_update_ssa,                 /* todo_flags_finish */
+  0                                    /* letter */
+};
index dc388ee..582de35 100644 (file)
@@ -779,8 +779,7 @@ remove_dead_stmt (block_stmt_iterator *i, basic_block bb)
                            SSA_OP_VIRTUAL_DEFS | SSA_OP_VIRTUAL_KILLS)
     {
       tree def = DEF_FROM_PTR (def_p);
-      bitmap_set_bit (vars_to_rename,
-                     var_ann (SSA_NAME_VAR (def))->uid);
+      mark_sym_for_renaming (SSA_NAME_VAR (def));
     }
   bsi_remove (i);  
   release_defs (t); 
@@ -942,7 +941,11 @@ struct tree_opt_pass pass_dce =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_fix_def_def_chains | TODO_cleanup_cfg | TODO_ggc_collect | TODO_verify_ssa,    /* todo_flags_finish */
+  TODO_dump_func 
+    | TODO_update_ssa_no_phi 
+    | TODO_cleanup_cfg
+    | TODO_ggc_collect
+    | TODO_verify_ssa,                 /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -959,8 +962,12 @@ struct tree_opt_pass pass_cd_dce =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_fix_def_def_chains | TODO_cleanup_cfg | TODO_ggc_collect | TODO_verify_ssa | TODO_verify_flow,
-                                       /* todo_flags_finish */
+  TODO_dump_func
+    | TODO_update_ssa_no_phi
+    | TODO_cleanup_cfg
+    | TODO_ggc_collect
+    | TODO_verify_ssa
+    | TODO_verify_flow,                        /* todo_flags_finish */
   0                                    /* letter */
 };
 
index ebb0aa3..1d4f9b0 100644 (file)
@@ -174,6 +174,8 @@ struct opt_stats_d
   long num_stmts;
   long num_exprs_considered;
   long num_re;
+  long num_const_prop;
+  long num_copy_prop;
 };
 
 static struct opt_stats_d opt_stats;
@@ -299,6 +301,7 @@ static edge single_incoming_edge_ignoring_loop_edges (basic_block);
 static void restore_nonzero_vars_to_original_value (void);
 static inline bool unsafe_associative_fp_binop (tree);
 
+
 /* Local version of fold that doesn't introduce cruft.  */
 
 static tree
@@ -403,6 +406,7 @@ tree_ssa_dominator_optimize (void)
      structure.  */
   walk_data.global_data = NULL;
   walk_data.block_local_data_size = 0;
+  walk_data.interesting_blocks = NULL;
 
   /* Now initialize the dominator walker.  */
   init_walk_dominator_tree (&walk_data);
@@ -442,11 +446,7 @@ tree_ssa_dominator_optimize (void)
         interactions between rewriting of _DECL nodes into SSA form
         and rewriting SSA_NAME nodes into SSA form after block
         duplication and CFG manipulation.  */
-      if (!bitmap_empty_p (vars_to_rename))
-       {
-         rewrite_into_ssa (false);
-         bitmap_clear (vars_to_rename);
-       }
+      update_ssa (TODO_update_ssa);
 
       free_all_edge_infos ();
 
@@ -572,7 +572,8 @@ struct tree_opt_pass pass_dominator =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_rename_vars
+  TODO_dump_func
+    | TODO_update_ssa
     | TODO_verify_ssa,                 /* todo_flags_finish */
   0                                    /* letter */
 };
@@ -1200,7 +1201,7 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb)
        break;
 
       VEC_pop (tree_on_heap, stmts_to_rescan);
-      mark_new_vars_to_rename (stmt, vars_to_rename);
+      mark_new_vars_to_rename (stmt);
     }
 }
 
@@ -1386,6 +1387,10 @@ dump_dominator_optimization_stats (FILE *file)
   fprintf (file, "    Redundant expressions eliminated:         %6ld (%.0f%%)\n",
           opt_stats.num_re, PERCENT (opt_stats.num_re,
                                      n_exprs));
+  fprintf (file, "    Constants propagated:                     %6ld\n",
+          opt_stats.num_const_prop);
+  fprintf (file, "    Copies propagated:                        %6ld\n",
+          opt_stats.num_copy_prop);
 
   fprintf (file, "\nHash table statistics:\n");
 
@@ -1600,7 +1605,7 @@ record_const_or_copy_1 (tree x, tree y, tree prev_x)
    will be relatively correct, and as more passes are taught to keep loop info
    up to date, the result will become more and more accurate.  */
 
-static int
+int
 loop_depth_of_name (tree x)
 {
   tree defstmt;
@@ -2229,9 +2234,9 @@ simplify_cond_and_lookup_avail_expr (tree stmt,
                     Similarly the high value for the merged range is the
                     minimum of the previous high value and the high value of
                     this record.  */
-                 low = (tree_int_cst_compare (low, tmp_low) == 1
+                 low = (low && tree_int_cst_compare (low, tmp_low) == 1
                         ? low : tmp_low);
-                 high = (tree_int_cst_compare (high, tmp_high) == -1
+                 high = (high && tree_int_cst_compare (high, tmp_high) == -1
                          ? high : tmp_high);
                }
 
@@ -2424,12 +2429,11 @@ cprop_into_successor_phis (basic_block bb, bitmap nonzero_vars)
             ORIG_P with its value in our constant/copy table.  */
          new = SSA_NAME_VALUE (orig);
          if (new
+             && new != orig
              && (TREE_CODE (new) == SSA_NAME
                  || is_gimple_min_invariant (new))
              && may_propagate_copy (orig, new))
-           {
-             propagate_value (orig_p, new);
-           }
+           propagate_value (orig_p, new);
        }
     }
 }
@@ -2624,7 +2628,6 @@ static void
 propagate_to_outgoing_edges (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
                             basic_block bb)
 {
-  
   record_edge_info (bb);
   cprop_into_successor_phis (bb, nonzero_vars);
 }
@@ -2756,24 +2759,7 @@ record_equivalences_from_stmt (tree stmt,
              || is_gimple_min_invariant (rhs)))
        SSA_NAME_VALUE (lhs) = rhs;
 
-      /* alloca never returns zero and the address of a non-weak symbol
-        is never zero.  NOP_EXPRs and CONVERT_EXPRs can be completely
-        stripped as they do not affect this equivalence.  */
-      while (TREE_CODE (rhs) == NOP_EXPR
-            || TREE_CODE (rhs) == CONVERT_EXPR)
-        rhs = TREE_OPERAND (rhs, 0);
-
-      if (alloca_call_p (rhs)
-          || (TREE_CODE (rhs) == ADDR_EXPR
-             && DECL_P (TREE_OPERAND (rhs, 0))
-             && ! DECL_WEAK (TREE_OPERAND (rhs, 0))))
-       record_var_is_nonzero (lhs);
-
-      /* IOR of any value with a nonzero value will result in a nonzero
-        value.  Even if we do not know the exact result recording that
-        the result is nonzero is worth the effort.  */
-      if (TREE_CODE (rhs) == BIT_IOR_EXPR
-         && integer_nonzerop (TREE_OPERAND (rhs, 1)))
+      if (expr_computes_nonzero (rhs))
        record_var_is_nonzero (lhs);
     }
 
@@ -2875,7 +2861,7 @@ cprop_operand (tree stmt, use_operand_p op_p)
      copy of some other variable, use the value or copy stored in
      CONST_AND_COPIES.  */
   val = SSA_NAME_VALUE (op);
-  if (val && TREE_CODE (val) != VALUE_HANDLE)
+  if (val && val != op && TREE_CODE (val) != VALUE_HANDLE)
     {
       tree op_type, val_type;
 
@@ -2885,8 +2871,9 @@ cprop_operand (tree stmt, use_operand_p op_p)
         statement.  Also only allow the new value to be an SSA_NAME
         for propagation into virtual operands.  */
       if (!is_gimple_reg (op)
-         && (get_virtual_var (val) != get_virtual_var (op)
-             || TREE_CODE (val) != SSA_NAME))
+         && (TREE_CODE (val) != SSA_NAME
+             || is_gimple_reg (val)
+             || get_virtual_var (val) != get_virtual_var (op)))
        return false;
 
       /* Do not replace hard register operands in asm statements.  */
@@ -2952,6 +2939,11 @@ cprop_operand (tree stmt, use_operand_p op_p)
              && is_gimple_min_invariant (val)))
        may_have_exposed_new_symbols = true;
 
+      if (TREE_CODE (val) != SSA_NAME)
+       opt_stats.num_const_prop++;
+      else
+       opt_stats.num_copy_prop++;
+
       propagate_value (op_p, val);
 
       /* And note that we modified this statement.  This is now
index d31c434..4d929e1 100644 (file)
@@ -251,6 +251,9 @@ dse_optimize_stmt (struct dom_walk_data *walk_data,
          && operand_equal_p (TREE_OPERAND (stmt, 0),
                              TREE_OPERAND (use_stmt, 0), 0))
        {
+         tree def;
+         ssa_op_iter iter;
+
          /* Make sure we propagate the ABNORMAL bit setting.  */
          if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (USE_FROM_PTR (first_use_p)))
            SSA_NAME_OCCURS_IN_ABNORMAL_PHI (usevar) = 1;
@@ -267,6 +270,12 @@ dse_optimize_stmt (struct dom_walk_data *walk_data,
          /* Remove the dead store.  */
          bsi_remove (&bsi);
 
+         /* The virtual defs for the dead statement will need to be
+            updated.  Since these names are going to disappear,
+            FUD chains for uses downstream need to be updated.  */
+         FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_VIRTUAL_DEFS)
+           mark_sym_for_renaming (SSA_NAME_VAR (def));
+
          /* And release any SSA_NAMEs set in this statement back to the
             SSA_NAME manager.  */
          release_defs (stmt);
@@ -347,6 +356,7 @@ tree_ssa_dse (void)
   walk_data.after_dom_children_before_stmts = NULL;
   walk_data.after_dom_children_walk_stmts = NULL;
   walk_data.after_dom_children_after_stmts = dse_finalize_block;
+  walk_data.interesting_blocks = NULL;
 
   walk_data.block_local_data_size = sizeof (struct dse_block_local_data);
 
@@ -384,12 +394,15 @@ struct tree_opt_pass pass_dse = {
   NULL,                                /* next */
   0,                           /* static_pass_number */
   TV_TREE_DSE,                 /* tv_id */
-  PROP_cfg | PROP_ssa
+  PROP_cfg
+    | PROP_ssa
     | PROP_alias,              /* properties_required */
   0,                           /* properties_provided */
   0,                           /* properties_destroyed */
   0,                           /* todo_flags_start */
-  TODO_dump_func | TODO_ggc_collect    /* todo_flags_finish */
-  | TODO_verify_ssa,
-  0                                    /* letter */
+  TODO_dump_func
+    | TODO_ggc_collect
+    | TODO_update_ssa
+    | TODO_verify_ssa,         /* todo_flags_finish */
+  0                            /* letter */
 };
index fb5f7f6..c465e2e 100644 (file)
@@ -237,10 +237,6 @@ copy_loop_headers (void)
   free (bbs);
   free (copied_bbs);
 
-#ifdef ENABLE_CHECKING
-  verify_loop_closed_ssa ();
-#endif
-
   loop_optimizer_finalize (loops, NULL);
 }
 
index 7823e17..a0c4582 100644 (file)
@@ -720,15 +720,14 @@ move_computations (void)
   fini_walk_dominator_tree (&walk_data);
 
   loop_commit_inserts ();
-  rewrite_into_ssa (false);
-  if (!bitmap_empty_p (vars_to_rename))
-    {
-      /* The rewrite of ssa names may cause violation of loop closed ssa
-        form invariants.  TODO -- avoid these rewrites completely.
-        Information in virtual phi nodes is sufficient for it.  */
-      rewrite_into_loop_closed_ssa (NULL);
-    }
-  bitmap_clear (vars_to_rename);
+
+  if (need_ssa_update_p ())
+    update_ssa (TODO_update_ssa);
+
+  /* The movement of LI code may cause violation of loop closed SSA
+     form invariants.  TODO -- avoid these rewrites completely.
+     Information in virtual phi nodes is sufficient for it.  */
+  rewrite_into_loop_closed_ssa (NULL);
 }
 
 /* Checks whether the statement defining variable *INDEX can be hoisted
@@ -1096,10 +1095,7 @@ rewrite_mem_refs (tree tmp_var, struct mem_ref *mem_refs)
   for (; mem_refs; mem_refs = mem_refs->next)
     {
       FOR_EACH_SSA_TREE_OPERAND (var, mem_refs->stmt, iter, SSA_OP_ALL_VIRTUALS)
-       {
-         var = SSA_NAME_VAR (var);
-         bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
-       }
+       mark_sym_for_renaming (SSA_NAME_VAR (var));
 
       *mem_refs->ref = tmp_var;
       update_stmt (mem_refs->stmt);
index 508f781..6dbb451 100644 (file)
@@ -4810,7 +4810,7 @@ unshare_and_remove_ssa_names (tree ref)
 static void
 rewrite_address_base (block_stmt_iterator *bsi, tree *op, tree with)
 {
-  tree bvar, var, new_var, new_name, copy, name;
+  tree bvar, var, new_name, copy, name;
   tree orig;
 
   var = bvar = get_base_address (*op);
@@ -4832,24 +4832,27 @@ rewrite_address_base (block_stmt_iterator *bsi, tree *op, tree with)
   else
     goto do_rewrite;
     
-  if (var_ann (var)->type_mem_tag)
-    var = var_ann (var)->type_mem_tag;
-
   /* We need to add a memory tag for the variable.  But we do not want
      to add it to the temporary used for the computations, since this leads
      to problems in redundancy elimination when there are common parts
      in two computations referring to the different arrays.  So we copy
      the variable to a new temporary.  */
   copy = build2 (MODIFY_EXPR, void_type_node, NULL_TREE, with);
+
   if (name)
     new_name = duplicate_ssa_name (name, copy);
   else
     {
-      new_var = create_tmp_var (TREE_TYPE (with), "ruatmp");
-      add_referenced_tmp_var (new_var);
-      var_ann (new_var)->type_mem_tag = var;
-      new_name = make_ssa_name (new_var, copy);
+      tree tag = var_ann (var)->type_mem_tag;
+      tree new_ptr = create_tmp_var (TREE_TYPE (with), "ruatmp");
+      add_referenced_tmp_var (new_ptr);
+      if (tag)
+       var_ann (new_ptr)->type_mem_tag = tag;
+      else
+       add_type_alias (new_ptr, var);
+      new_name = make_ssa_name (new_ptr, copy);
     }
+
   TREE_OPERAND (copy, 0) = new_name;
   update_stmt (copy);
   bsi_insert_before (bsi, copy, BSI_SAME_STMT);
@@ -4870,6 +4873,10 @@ do_rewrite:
 
   /* Record the original reference, for purposes of alias analysis.  */
   REF_ORIGINAL (*op) = orig;
+
+  /* Virtual operands in the original statement may have to be renamed
+     because of the replacement.  */
+  mark_new_vars_to_rename (bsi_stmt (*bsi));
 }
 
 /* Rewrites USE (address that is an iv) using candidate CAND.  */
@@ -5377,11 +5384,6 @@ tree_ssa_iv_optimize (struct loops *loops)
   while (loop->inner)
     loop = loop->inner;
 
-#ifdef ENABLE_CHECKING
-  verify_loop_closed_ssa ();
-  verify_stmts ();
-#endif
-
   /* Scan the loops, inner ones first.  */
   while (loop != loops->tree_root)
     {
@@ -5400,10 +5402,27 @@ tree_ssa_iv_optimize (struct loops *loops)
        loop = loop->outer;
     }
 
-#ifdef ENABLE_CHECKING
-  verify_loop_closed_ssa ();
-  verify_stmts ();
-#endif
+  /* FIXME.  IV opts introduces new aliases and call-clobbered
+     variables, which need to be renamed.  However, when we call the
+     renamer, not all statements will be scanned for operands.  In
+     particular, the newly introduced aliases may appear in statements
+     that are considered "unmodified", so the renamer will not get a
+     chance to rename those operands.
+
+     Work around this problem by forcing an operand re-scan on every
+     statement.  This will not be necessary once the new operand
+     scanner is implemented.  */
+  if (need_ssa_update_p ())
+    {
+      basic_block bb;
+      block_stmt_iterator si;
+      FOR_EACH_BB (bb)
+       for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+         update_stmt (bsi_stmt (si));
+
+      update_ssa (TODO_update_ssa);
+    }
 
+  rewrite_into_loop_closed_ssa (NULL);
   tree_ssa_iv_optimize_finalize (loops, &data);
 }
index cbc1e69..fbb45ad 100644 (file)
@@ -157,7 +157,10 @@ add_exit_phis_var (tree var, bitmap livein, bitmap exits)
   basic_block def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (var));
   bitmap_iterator bi;
 
-  bitmap_clear_bit (livein, def_bb->index);
+  if (is_gimple_reg (var))
+    bitmap_clear_bit (livein, def_bb->index);
+  else
+    bitmap_set_bit (livein, def_bb->index);
 
   def = BITMAP_ALLOC (NULL);
   bitmap_set_bit (def, def_bb->index);
index 5012470..03c3249 100644 (file)
@@ -53,17 +53,8 @@ tree_loop_optimizer_init (FILE *dump)
   if (!loops)
     return NULL;
 
-  /* Creation of preheaders may create redundant phi nodes if the loop is
-     entered by more than one edge, but the initial value of the induction
-     variable is the same on all of them.  */
-  kill_redundant_phi_nodes ();
-  rewrite_into_ssa (false);
-  bitmap_clear (vars_to_rename);
-
+  update_ssa (TODO_update_ssa);
   rewrite_into_loop_closed_ssa (NULL);
-#ifdef ENABLE_CHECKING
-  verify_loop_closed_ssa ();
-#endif
 
   return loops;
 }
@@ -121,7 +112,7 @@ struct tree_opt_pass pass_loop_init =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_loops,  /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -155,7 +146,7 @@ struct tree_opt_pass pass_lim =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_loops,  /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -189,7 +180,7 @@ struct tree_opt_pass pass_unswitch =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_loops,  /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -201,7 +192,6 @@ tree_vectorize (void)
   if (!current_loops)
     return;
 
-  bitmap_clear (vars_to_rename);
   vectorize_loops (current_loops);
 }
 
@@ -224,7 +214,7 @@ struct tree_opt_pass pass_vectorize =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
+  TODO_dump_func | TODO_update_ssa,    /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -259,7 +249,7 @@ struct tree_opt_pass pass_linear_transform =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_loops,  /* todo_flags_finish */
   0                                    /* letter */    
 };
 
@@ -293,7 +283,7 @@ struct tree_opt_pass pass_iv_canon =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_loops,  /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -356,7 +346,7 @@ struct tree_opt_pass pass_complete_unroll =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_loops,  /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -390,7 +380,7 @@ struct tree_opt_pass pass_iv_optimize =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_loops,  /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -402,10 +392,6 @@ tree_ssa_loop_done (void)
   if (!current_loops)
     return;
 
-#ifdef ENABLE_CHECKING
-  verify_loop_closed_ssa ();
-#endif
-
   free_numbers_of_iterations_estimates (current_loops);
   scev_finalize ();
   loop_optimizer_finalize (current_loops,
@@ -429,4 +415,3 @@ struct tree_opt_pass pass_loop_done =
   TODO_cleanup_cfg | TODO_dump_func,   /* todo_flags_finish */
   0                                    /* letter */
 };
-