backport: copy-prop, incremental SSA updating of FUD chains and newly exposed symbols.
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. 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. From-SVN: r97884
This commit is contained in:
parent
45f9480e29
commit
0bca51f080
273
gcc/ChangeLog
273
gcc/ChangeLog
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
@subsection Examining @code{SSA_NAME} nodes
|
||||
@cindex examining SSA_NAMEs
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"} } */
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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" } } */
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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" } } */
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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" } } */
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
2128
gcc/tree-into-ssa.c
2128
gcc/tree-into-ssa.c
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
#if defined ENABLE_CHECKING
|
||||
if (need_ssa_update_p ())
|
||||
gcc_assert (flags & TODO_update_ssa_any);
|
||||
#endif
|
||||
|
||||
if (flags & TODO_update_ssa_any)
|
||||
{
|
||||
rewrite_into_ssa (false);
|
||||
bitmap_clear (vars_to_rename);
|
||||
}
|
||||
if (flags & TODO_fix_def_def_chains)
|
||||
{
|
||||
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 (®_obstack); /* FIXME, only at RTL generation*/
|
||||
|
||||
vars_to_rename = BITMAP_ALLOC (NULL);
|
||||
|
||||
/* Perform all tree transforms and optimizations. */
|
||||
execute_pass_list (all_passes);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
tree phi;
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
if (prev_p)
|
||||
*prev_p = NULL_TREE;
|
||||
|
||||
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
|
||||
{
|
||||
/* Build a new PHI list for BB without variables in VARS. */
|
||||
tree phi, new_phi_list, next;
|
||||
tree *lastp = &new_phi_list;
|
||||
if (SSA_NAME_VAR (PHI_RESULT (phi)) == sym)
|
||||
return 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));
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the last node in the new list has no successors. */
|
||||
*lastp = NULL;
|
||||
bb_ann (bb)->phi_nodes = new_phi_list;
|
||||
|
||||
#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"
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
1174
gcc/tree-ssa-ccp.c
1174
gcc/tree-ssa-ccp.c
File diff suppressed because it is too large
Load Diff
|
@ -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 = ©_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 */
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -1452,6 +1452,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
|
|||
case TRUTH_XOR_EXPR:
|
||||
case COMPOUND_EXPR:
|
||||
case OBJ_TYPE_REF:
|
||||
case ASSERT_EXPR:
|
||||
do_binary:
|
||||
{
|
||||
tree op0 = TREE_OPERAND (expr, 0);
|
||||
|
@ -1735,7 +1736,7 @@ get_call_expr_operands (tree stmt, tree expr)
|
|||
&& !bitmap_empty_p (call_clobbered_vars)
|
||||
&& !(call_flags & ECF_NOVOPS))
|
||||
{
|
||||
/* A 'pure' or a 'const' functions never call clobber anything.
|
||||
/* A 'pure' or a 'const' function never call-clobbers anything.
|
||||
A 'noreturn' function might, but since we don't return anyway
|
||||
there is no point in recording that. */
|
||||
if (TREE_SIDE_EFFECTS (expr)
|
||||
|
@ -1798,6 +1799,24 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
|
|||
if (TREE_THIS_VOLATILE (sym) && s_ann)
|
||||
s_ann->has_volatile_ops = true;
|
||||
|
||||
/* If the variable cannot be modified and this is a V_MAY_DEF change
|
||||
it into a VUSE. This happens when read-only variables are marked
|
||||
call-clobbered and/or aliased to writeable variables. So we only
|
||||
check that this only happens on stores, and not writes to GIMPLE
|
||||
registers.
|
||||
|
||||
FIXME: The C++ FE is emitting assignments in the IL stream for
|
||||
read-only globals. This is wrong, but for the time being disable
|
||||
this transformation on V_MUST_DEF operands (otherwise, we
|
||||
mis-optimize SPEC2000's eon). */
|
||||
if ((flags & opf_is_def)
|
||||
&& !(flags & opf_kill_def)
|
||||
&& unmodifiable_var_p (var))
|
||||
{
|
||||
gcc_assert (!is_real_op);
|
||||
flags &= ~opf_is_def;
|
||||
}
|
||||
|
||||
if (is_real_op)
|
||||
{
|
||||
/* The variable is a GIMPLE register. Add it to real operands. */
|
||||
|
@ -1858,17 +1877,35 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
|
|||
|
||||
if (flags & opf_is_def)
|
||||
{
|
||||
bool added_may_defs_p = false;
|
||||
|
||||
/* If the variable is also an alias tag, add a virtual
|
||||
operand for it, otherwise we will miss representing
|
||||
references to the members of the variable's alias set.
|
||||
This fixes the bug in gcc.c-torture/execute/20020503-1.c. */
|
||||
if (v_ann->is_alias_tag)
|
||||
append_v_may_def (var);
|
||||
{
|
||||
added_may_defs_p = true;
|
||||
append_v_may_def (var);
|
||||
}
|
||||
|
||||
for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++)
|
||||
append_v_may_def (VARRAY_TREE (aliases, i));
|
||||
{
|
||||
/* While VAR may be modifiable, some of its aliases
|
||||
may not be. If that's the case, we don't really
|
||||
need to add them a V_MAY_DEF for them. */
|
||||
tree alias = VARRAY_TREE (aliases, i);
|
||||
|
||||
if (s_ann)
|
||||
if (unmodifiable_var_p (alias))
|
||||
append_vuse (alias);
|
||||
else
|
||||
{
|
||||
append_v_may_def (alias);
|
||||
added_may_defs_p = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_ann && added_may_defs_p)
|
||||
s_ann->makes_aliased_stores = 1;
|
||||
}
|
||||
else
|
||||
|
@ -2000,8 +2037,7 @@ add_call_clobber_ops (tree stmt)
|
|||
EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
|
||||
{
|
||||
tree var = referenced_var (i);
|
||||
if (TREE_READONLY (var)
|
||||
&& (TREE_STATIC (var) || DECL_EXTERNAL (var)))
|
||||
if (unmodifiable_var_p (var))
|
||||
add_stmt_operand (&var, &empty_ann, opf_none);
|
||||
else
|
||||
add_stmt_operand (&var, &empty_ann, opf_is_def);
|
||||
|
|
|
@ -964,8 +964,12 @@ struct tree_opt_pass pass_phiopt =
|
|||
0, /* properties_provided */
|
||||
0, /* properties_destroyed */
|
||||
0, /* todo_flags_start */
|
||||
TODO_cleanup_cfg | TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */
|
||||
| TODO_verify_ssa | TODO_rename_vars
|
||||
| TODO_verify_flow | TODO_verify_stmts,
|
||||
TODO_cleanup_cfg
|
||||
| TODO_dump_func
|
||||
| TODO_ggc_collect
|
||||
| TODO_verify_ssa
|
||||
| TODO_update_ssa
|
||||
| TODO_verify_flow
|
||||
| TODO_verify_stmts, /* todo_flags_finish */
|
||||
0 /* letter */
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Generic SSA value propagation engine.
|
||||
Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
Contributed by Diego Novillo <dnovillo@redhat.com>
|
||||
|
||||
This file is part of GCC.
|
||||
|
@ -459,6 +459,7 @@ ssa_prop_init (void)
|
|||
edge e;
|
||||
edge_iterator ei;
|
||||
basic_block bb;
|
||||
size_t i;
|
||||
|
||||
/* Worklists of SSA edges. */
|
||||
interesting_ssa_edges = VEC_alloc (tree, 20);
|
||||
|
@ -475,7 +476,12 @@ ssa_prop_init (void)
|
|||
|
||||
VARRAY_BB_INIT (cfg_blocks, 20, "cfg_blocks");
|
||||
|
||||
/* Initially assume that every edge in the CFG is not executable
|
||||
/* Initialize the values for every SSA_NAME. */
|
||||
for (i = 1; i < num_ssa_names; i++)
|
||||
if (ssa_name (i))
|
||||
SSA_NAME_VALUE (ssa_name (i)) = NULL_TREE;
|
||||
|
||||
/* Initially assume that every edge in the CFG is not executable.
|
||||
(including the edges coming out of ENTRY_BLOCK_PTR). */
|
||||
FOR_ALL_BB (bb)
|
||||
{
|
||||
|
@ -666,4 +672,409 @@ ssa_propagate (ssa_prop_visit_stmt_fn visit_stmt,
|
|||
ssa_prop_fini ();
|
||||
}
|
||||
|
||||
|
||||
/* Return the first V_MAY_DEF or V_MUST_DEF operand for STMT. */
|
||||
|
||||
tree
|
||||
first_vdef (tree stmt)
|
||||
{
|
||||
if (NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) > 0)
|
||||
return V_MAY_DEF_RESULT (STMT_V_MAY_DEF_OPS (stmt), 0);
|
||||
else if (NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt)) > 0)
|
||||
return V_MUST_DEF_RESULT (STMT_V_MUST_DEF_OPS (stmt), 0);
|
||||
else
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
|
||||
/* Return true if STMT is of the form 'LHS = mem_ref', where 'mem_ref'
|
||||
is a non-volatile pointer dereference, a structure reference or a
|
||||
reference to a single _DECL. Ignore volatile memory references
|
||||
because they are not interesting for the optimizers. */
|
||||
|
||||
bool
|
||||
stmt_makes_single_load (tree stmt)
|
||||
{
|
||||
tree rhs;
|
||||
|
||||
if (TREE_CODE (stmt) != MODIFY_EXPR)
|
||||
return false;
|
||||
|
||||
if (NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) == 0
|
||||
&& NUM_VUSES (STMT_VUSE_OPS (stmt)) == 0)
|
||||
return false;
|
||||
|
||||
rhs = TREE_OPERAND (stmt, 1);
|
||||
STRIP_NOPS (rhs);
|
||||
|
||||
return (!TREE_THIS_VOLATILE (rhs)
|
||||
&& (DECL_P (rhs)
|
||||
|| TREE_CODE_CLASS (TREE_CODE (rhs)) == tcc_reference));
|
||||
}
|
||||
|
||||
|
||||
/* Return true if STMT is of the form 'mem_ref = RHS', where 'mem_ref'
|
||||
is a non-volatile pointer dereference, a structure reference or a
|
||||
reference to a single _DECL. Ignore volatile memory references
|
||||
because they are not interesting for the optimizers. */
|
||||
|
||||
bool
|
||||
stmt_makes_single_store (tree stmt)
|
||||
{
|
||||
tree lhs;
|
||||
|
||||
if (TREE_CODE (stmt) != MODIFY_EXPR)
|
||||
return false;
|
||||
|
||||
if (NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) == 0
|
||||
&& NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt)) == 0)
|
||||
return false;
|
||||
|
||||
lhs = TREE_OPERAND (stmt, 0);
|
||||
STRIP_NOPS (lhs);
|
||||
|
||||
return (!TREE_THIS_VOLATILE (lhs)
|
||||
&& (DECL_P (lhs)
|
||||
|| TREE_CODE_CLASS (TREE_CODE (lhs)) == tcc_reference));
|
||||
}
|
||||
|
||||
|
||||
/* If STMT makes a single memory load and all the virtual use operands
|
||||
have the same value in array VALUES, return it. Otherwise, return
|
||||
NULL. */
|
||||
|
||||
prop_value_t *
|
||||
get_value_loaded_by (tree stmt, prop_value_t *values)
|
||||
{
|
||||
ssa_op_iter i;
|
||||
tree vuse;
|
||||
prop_value_t *prev_val = NULL;
|
||||
prop_value_t *val = NULL;
|
||||
|
||||
FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, i, SSA_OP_VIRTUAL_USES)
|
||||
{
|
||||
val = &values[SSA_NAME_VERSION (vuse)];
|
||||
if (prev_val && prev_val->value != val->value)
|
||||
return NULL;
|
||||
prev_val = val;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
/* Propagation statistics. */
|
||||
struct prop_stats_d
|
||||
{
|
||||
long num_const_prop;
|
||||
long num_copy_prop;
|
||||
};
|
||||
|
||||
static struct prop_stats_d prop_stats;
|
||||
|
||||
/* Replace USE references in statement STMT with the values stored in
|
||||
PROP_VALUE. 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. */
|
||||
|
||||
bool
|
||||
replace_uses_in (tree stmt, bool *replaced_addresses_p,
|
||||
prop_value_t *prop_value)
|
||||
{
|
||||
bool replaced = false;
|
||||
use_operand_p use;
|
||||
ssa_op_iter iter;
|
||||
|
||||
FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE)
|
||||
{
|
||||
tree tuse = USE_FROM_PTR (use);
|
||||
tree val = prop_value[SSA_NAME_VERSION (tuse)].value;
|
||||
|
||||
if (val == tuse || val == NULL_TREE)
|
||||
continue;
|
||||
|
||||
if (TREE_CODE (stmt) == ASM_EXPR
|
||||
&& !may_propagate_copy_into_asm (tuse))
|
||||
continue;
|
||||
|
||||
if (!may_propagate_copy (tuse, val))
|
||||
continue;
|
||||
|
||||
if (TREE_CODE (val) != SSA_NAME)
|
||||
prop_stats.num_const_prop++;
|
||||
else
|
||||
prop_stats.num_copy_prop++;
|
||||
|
||||
propagate_value (use, 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 the values
|
||||
stored in PROP_VALUE. Return true if a reference was replaced. If
|
||||
REPLACED_ADDRESSES_P is given, it will be set to true if an address
|
||||
constant was replaced.
|
||||
|
||||
Replacing VUSE operands is slightly more complex than replacing
|
||||
regular USEs. We are only interested in two types of replacements
|
||||
here:
|
||||
|
||||
1- If the value to be replaced is a constant or an SSA name for a
|
||||
GIMPLE register, then we are making a copy/constant propagation
|
||||
from a memory store. For instance,
|
||||
|
||||
# a_3 = V_MAY_DEF <a_2>
|
||||
a.b = x_1;
|
||||
...
|
||||
# VUSE <a_3>
|
||||
y_4 = a.b;
|
||||
|
||||
This replacement is only possible iff STMT is an assignment
|
||||
whose RHS is identical to the LHS of the statement that created
|
||||
the VUSE(s) that we are replacing. Otherwise, we may do the
|
||||
wrong replacement:
|
||||
|
||||
# a_3 = V_MAY_DEF <a_2>
|
||||
# b_5 = V_MAY_DEF <b_4>
|
||||
*p = 10;
|
||||
...
|
||||
# VUSE <b_5>
|
||||
x_8 = b;
|
||||
|
||||
Even though 'b_5' acquires the value '10' during propagation,
|
||||
there is no way for the propagator to tell whether the
|
||||
replacement is correct in every reached use, because values are
|
||||
computed at definition sites. Therefore, when doing final
|
||||
substitution of propagated values, we have to check each use
|
||||
site. Since the RHS of STMT ('b') is different from the LHS of
|
||||
the originating statement ('*p'), we cannot replace 'b' with
|
||||
'10'.
|
||||
|
||||
Similarly, when merging values from PHI node arguments,
|
||||
propagators need to take care not to merge the same values
|
||||
stored in different locations:
|
||||
|
||||
if (...)
|
||||
# a_3 = V_MAY_DEF <a_2>
|
||||
a.b = 3;
|
||||
else
|
||||
# a_4 = V_MAY_DEF <a_2>
|
||||
a.c = 3;
|
||||
# a_5 = PHI <a_3, a_4>
|
||||
|
||||
It would be wrong to propagate '3' into 'a_5' because that
|
||||
operation merges two stores to different memory locations.
|
||||
|
||||
|
||||
2- If the value to be replaced is an SSA name for a virtual
|
||||
register, then we simply replace each VUSE operand with its
|
||||
value from PROP_VALUE. This is the same replacement done by
|
||||
replace_uses_in. */
|
||||
|
||||
static bool
|
||||
replace_vuses_in (tree stmt, bool *replaced_addresses_p,
|
||||
prop_value_t *prop_value)
|
||||
{
|
||||
bool replaced = false;
|
||||
ssa_op_iter iter;
|
||||
use_operand_p vuse;
|
||||
|
||||
if (stmt_makes_single_load (stmt))
|
||||
{
|
||||
/* If STMT is an assignment whose RHS is a single memory load,
|
||||
see if we are trying to propagate a constant or a GIMPLE
|
||||
register (case #1 above). */
|
||||
prop_value_t *val = get_value_loaded_by (stmt, prop_value);
|
||||
tree rhs = TREE_OPERAND (stmt, 1);
|
||||
|
||||
if (val
|
||||
&& val->value
|
||||
&& (is_gimple_reg (val->value)
|
||||
|| is_gimple_min_invariant (val->value))
|
||||
&& simple_cst_equal (rhs, val->mem_ref) == 1)
|
||||
|
||||
{
|
||||
/* If we are replacing a constant address, inform our
|
||||
caller. */
|
||||
if (TREE_CODE (val->value) != SSA_NAME
|
||||
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 1)))
|
||||
&& replaced_addresses_p)
|
||||
*replaced_addresses_p = true;
|
||||
|
||||
/* We can only perform the substitution if the load is done
|
||||
from the same memory location as the original store.
|
||||
Since we already know that there are no intervening
|
||||
stores between DEF_STMT and STMT, we only need to check
|
||||
that the RHS of STMT is the same as the memory reference
|
||||
propagated together with the value. */
|
||||
TREE_OPERAND (stmt, 1) = val->value;
|
||||
|
||||
if (TREE_CODE (val->value) != SSA_NAME)
|
||||
prop_stats.num_const_prop++;
|
||||
else
|
||||
prop_stats.num_copy_prop++;
|
||||
|
||||
/* Since we have replaced the whole RHS of STMT, there
|
||||
is no point in checking the other VUSEs, as they will
|
||||
all have the same value. */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, the values for every VUSE operand must be other
|
||||
SSA_NAMEs that can be propagated into STMT. */
|
||||
FOR_EACH_SSA_USE_OPERAND (vuse, stmt, iter, SSA_OP_VIRTUAL_USES)
|
||||
{
|
||||
tree var = USE_FROM_PTR (vuse);
|
||||
tree val = prop_value[SSA_NAME_VERSION (var)].value;
|
||||
|
||||
if (val == NULL_TREE || var == val)
|
||||
continue;
|
||||
|
||||
/* Constants and copies propagated between real and virtual
|
||||
operands are only possible in the cases handled above. They
|
||||
should be ignored in any other context. */
|
||||
if (is_gimple_min_invariant (val) || is_gimple_reg (val))
|
||||
continue;
|
||||
|
||||
propagate_value (vuse, val);
|
||||
prop_stats.num_copy_prop++;
|
||||
replaced = true;
|
||||
}
|
||||
|
||||
return replaced;
|
||||
}
|
||||
|
||||
|
||||
/* Replace propagated values into all the arguments for PHI using the
|
||||
values from PROP_VALUE. */
|
||||
|
||||
static void
|
||||
replace_phi_args_in (tree phi, prop_value_t *prop_value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PHI_NUM_ARGS (phi); i++)
|
||||
{
|
||||
tree arg = PHI_ARG_DEF (phi, i);
|
||||
|
||||
if (TREE_CODE (arg) == SSA_NAME)
|
||||
{
|
||||
tree val = prop_value[SSA_NAME_VERSION (arg)].value;
|
||||
|
||||
if (val && val != arg && may_propagate_copy (arg, val))
|
||||
{
|
||||
if (TREE_CODE (val) != SSA_NAME)
|
||||
prop_stats.num_const_prop++;
|
||||
else
|
||||
prop_stats.num_copy_prop++;
|
||||
|
||||
propagate_value (PHI_ARG_DEF_PTR (phi, i), val);
|
||||
|
||||
/* If we propagated a copy and this argument flows
|
||||
through an abnormal edge, update the replacement
|
||||
accordingly. */
|
||||
if (TREE_CODE (val) == SSA_NAME
|
||||
&& PHI_ARG_EDGE (phi, i)->flags & EDGE_ABNORMAL)
|
||||
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Perform final substitution and folding of propagated values. */
|
||||
|
||||
void
|
||||
substitute_and_fold (prop_value_t *prop_value)
|
||||
{
|
||||
basic_block bb;
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file,
|
||||
"\nSubstituing values and folding statements\n\n");
|
||||
|
||||
memset (&prop_stats, 0, sizeof (prop_stats));
|
||||
|
||||
/* Substitute values in every statement of every basic block. */
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
block_stmt_iterator i;
|
||||
tree phi;
|
||||
|
||||
/* Propagate our known values into PHI nodes. */
|
||||
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Replaced ");
|
||||
print_generic_stmt (dump_file, phi, TDF_SLIM);
|
||||
}
|
||||
|
||||
replace_phi_args_in (phi, prop_value);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, " with ");
|
||||
print_generic_stmt (dump_file, phi, TDF_SLIM);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
|
||||
{
|
||||
bool replaced_address, did_replace;
|
||||
tree stmt = bsi_stmt (i);
|
||||
|
||||
get_stmt_operands (stmt);
|
||||
|
||||
/* Replace the statement with its folded version and mark it
|
||||
folded. */
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Replaced ");
|
||||
print_generic_stmt (dump_file, stmt, TDF_SLIM);
|
||||
}
|
||||
|
||||
replaced_address = false;
|
||||
did_replace = replace_uses_in (stmt, &replaced_address, prop_value);
|
||||
did_replace |= replace_vuses_in (stmt, &replaced_address, prop_value);
|
||||
if (did_replace)
|
||||
{
|
||||
fold_stmt (bsi_stmt_ptr (i));
|
||||
stmt = bsi_stmt(i);
|
||||
|
||||
/* If we folded a builtin function, we'll likely
|
||||
need to rename VDEFs. */
|
||||
mark_new_vars_to_rename (stmt);
|
||||
|
||||
/* If we cleaned up EH information from the statement,
|
||||
remove EH edges. */
|
||||
if (maybe_clean_eh_stmt (stmt))
|
||||
tree_purge_dead_eh_edges (bb);
|
||||
}
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, " with ");
|
||||
print_generic_stmt (dump_file, stmt, TDF_SLIM);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dump_file && (dump_flags & TDF_STATS))
|
||||
{
|
||||
fprintf (dump_file, "Constants propagated: %6ld\n",
|
||||
prop_stats.num_const_prop);
|
||||
fprintf (dump_file, "Copies propagated: %6ld\n",
|
||||
prop_stats.num_copy_prop);
|
||||
}
|
||||
}
|
||||
#include "gt-tree-ssa-propagate.h"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Data structures and function declarations for the SSA value propagation
|
||||
engine.
|
||||
Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
|
||||
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
Contributed by Diego Novillo <dnovillo@redhat.com>
|
||||
|
||||
This file is part of GCC.
|
||||
|
@ -30,7 +30,6 @@ Boston, MA 02111-1307, USA. */
|
|||
/* Lattice values used for propagation purposes. Specific instances
|
||||
of a propagation engine must return these values from the statement
|
||||
and PHI visit functions to direct the engine. */
|
||||
|
||||
enum ssa_prop_result {
|
||||
/* The statement produces nothing of interest. No edges will be
|
||||
added to the work lists. */
|
||||
|
@ -51,12 +50,43 @@ enum ssa_prop_result {
|
|||
};
|
||||
|
||||
|
||||
struct prop_value_d {
|
||||
/* Lattice value. Each propagator is free to define its own
|
||||
lattice and this field is only meaningful while propagating.
|
||||
It will not be used by substitute_and_fold. */
|
||||
unsigned lattice_val;
|
||||
|
||||
/* Propagated value. */
|
||||
tree value;
|
||||
|
||||
/* If this value is held in an SSA name for a non-register
|
||||
variable, this field holds the actual memory reference
|
||||
associated with this value. This field is taken from
|
||||
the LHS of the assignment that generated the associated SSA
|
||||
name. However, in the case of PHI nodes, this field is copied
|
||||
from the PHI arguments (assuming that all the arguments have
|
||||
the same memory reference). See replace_vuses_in for a more
|
||||
detailed description. */
|
||||
tree mem_ref;
|
||||
};
|
||||
|
||||
typedef struct prop_value_d prop_value_t;
|
||||
|
||||
|
||||
/* Call-back functions used by the value propagation engine. */
|
||||
typedef enum ssa_prop_result (*ssa_prop_visit_stmt_fn) (tree, edge *, tree *);
|
||||
typedef enum ssa_prop_result (*ssa_prop_visit_phi_fn) (tree);
|
||||
|
||||
|
||||
/* In tree-ssa-propagate.c */
|
||||
void ssa_propagate (ssa_prop_visit_stmt_fn, ssa_prop_visit_phi_fn);
|
||||
tree get_rhs (tree);
|
||||
bool set_rhs (tree *, tree);
|
||||
tree first_vdef (tree);
|
||||
bool stmt_makes_single_load (tree);
|
||||
bool stmt_makes_single_store (tree);
|
||||
prop_value_t *get_value_loaded_by (tree, prop_value_t *);
|
||||
bool replace_uses_in (tree, bool *, prop_value_t *);
|
||||
void substitute_and_fold (prop_value_t *);
|
||||
|
||||
#endif /* _TREE_SSA_PROPAGATE_H */
|
||||
|
|
|
@ -584,6 +584,9 @@ struct tree_opt_pass pass_sink_code =
|
|||
0, /* properties_provided */
|
||||
0, /* properties_destroyed */
|
||||
0, /* todo_flags_start */
|
||||
TODO_rename_vars | TODO_dump_func | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */
|
||||
TODO_update_ssa
|
||||
| TODO_dump_func
|
||||
| TODO_ggc_collect
|
||||
| TODO_verify_ssa, /* todo_flags_finish */
|
||||
0 /* letter */
|
||||
};
|
||||
|
|
315
gcc/tree-ssa.c
315
gcc/tree-ssa.c
|
@ -285,7 +285,7 @@ verify_use (basic_block bb, basic_block def_bb, use_operand_p use_p,
|
|||
{
|
||||
fprintf (stderr, "for SSA_NAME: ");
|
||||
print_generic_expr (stderr, ssa_name, TDF_VOPS);
|
||||
fprintf (stderr, "in statement:\n");
|
||||
fprintf (stderr, " in statement:\n");
|
||||
print_generic_stmt (stderr, stmt, TDF_VOPS);
|
||||
}
|
||||
|
||||
|
@ -1028,319 +1028,6 @@ walk_use_def_chains (tree var, walk_use_def_chains_fn fn, void *data,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Replaces VAR with REPL in memory reference expression *X in
|
||||
statement STMT at use location USE_P. Return TRUE if Anything was done. */
|
||||
|
||||
static bool
|
||||
propagate_into_addr (tree stmt, use_operand_p use_p, tree *x, tree repl)
|
||||
{
|
||||
tree new_var, ass_stmt, addr_var;
|
||||
basic_block bb;
|
||||
block_stmt_iterator bsi;
|
||||
|
||||
/* There is nothing special to handle in the other cases. */
|
||||
if (TREE_CODE (repl) != ADDR_EXPR)
|
||||
return false;
|
||||
addr_var = TREE_OPERAND (repl, 0);
|
||||
|
||||
while (handled_component_p (*x)
|
||||
|| TREE_CODE (*x) == REALPART_EXPR
|
||||
|| TREE_CODE (*x) == IMAGPART_EXPR)
|
||||
x = &TREE_OPERAND (*x, 0);
|
||||
|
||||
/* Heres a hack but since KRPhinodes is going away soon, Im not going to
|
||||
sweat it. */
|
||||
if (TREE_CODE (*x) != INDIRECT_REF
|
||||
|| &(TREE_OPERAND (*x, 0)) != use_p->use) /* HACK ALERT. */
|
||||
return false;
|
||||
|
||||
if (TREE_TYPE (*x) == TREE_TYPE (addr_var))
|
||||
{
|
||||
*x = addr_var;
|
||||
mark_new_vars_to_rename (stmt, vars_to_rename);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Frontends sometimes produce expressions like *&a instead of a[0].
|
||||
Create a temporary variable to handle this case. */
|
||||
ass_stmt = build2 (MODIFY_EXPR, void_type_node, NULL_TREE, repl);
|
||||
new_var = duplicate_ssa_name (USE_FROM_PTR (use_p), ass_stmt);
|
||||
TREE_OPERAND (*x, 0) = new_var;
|
||||
TREE_OPERAND (ass_stmt, 0) = new_var;
|
||||
|
||||
bb = bb_for_stmt (stmt);
|
||||
tree_block_label (bb);
|
||||
bsi = bsi_after_labels (bb);
|
||||
bsi_insert_after (&bsi, ass_stmt, BSI_NEW_STMT);
|
||||
|
||||
mark_new_vars_to_rename (stmt, vars_to_rename);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Replaces immediate uses of VAR by REPL. */
|
||||
|
||||
static void
|
||||
replace_immediate_uses (tree var, tree repl)
|
||||
{
|
||||
tree stmt;
|
||||
bool mark_new_vars;
|
||||
use_operand_p imm_use;
|
||||
imm_use_iterator imm_iter;
|
||||
|
||||
FOR_EACH_IMM_USE_SAFE (imm_use, imm_iter, var)
|
||||
{
|
||||
stmt = USE_STMT (imm_use);
|
||||
|
||||
if (TREE_CODE (stmt) == PHI_NODE)
|
||||
{
|
||||
int index = PHI_ARG_INDEX_FROM_USE (imm_use);
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (&(PHI_ARG_IMM_USE_NODE (stmt, index)) == imm_use);
|
||||
#endif
|
||||
SET_USE (imm_use, repl);
|
||||
if (TREE_CODE (repl) == SSA_NAME
|
||||
&& PHI_ARG_EDGE (stmt, index)->flags & EDGE_ABNORMAL)
|
||||
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (repl) = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
gcc_assert (!stmt_modified_p (stmt));
|
||||
|
||||
mark_new_vars = false;
|
||||
if (is_gimple_reg (SSA_NAME_VAR (var)))
|
||||
{
|
||||
bool propagated = false;
|
||||
if (TREE_CODE (stmt) == MODIFY_EXPR)
|
||||
{
|
||||
if (TREE_CODE (repl) == ADDR_EXPR)
|
||||
{
|
||||
propagated =
|
||||
propagate_into_addr (stmt, imm_use, &TREE_OPERAND (stmt, 0),
|
||||
repl);
|
||||
if (!propagated)
|
||||
propagated =
|
||||
propagate_into_addr (stmt, imm_use,
|
||||
&TREE_OPERAND (stmt, 1), repl);
|
||||
}
|
||||
}
|
||||
if (!propagated)
|
||||
propagate_value (imm_use, repl);
|
||||
mark_new_vars = POINTER_TYPE_P (TREE_TYPE (repl));
|
||||
}
|
||||
else
|
||||
propagate_value (imm_use, repl);
|
||||
|
||||
/* FIXME. If REPL is a constant, we need to fold STMT.
|
||||
However, fold_stmt wants a pointer to the statement, because
|
||||
it may happen that it needs to replace the whole statement
|
||||
with a new expression. Since the current def-use machinery
|
||||
does not return pointers to statements, we call fold_stmt
|
||||
with the address of a local temporary, if that call changes
|
||||
the temporary then we fallback on looking for a proper
|
||||
pointer to STMT by scanning STMT's basic block.
|
||||
|
||||
Note that all this will become unnecessary soon. This
|
||||
pass is being replaced with a proper copy propagation pass
|
||||
for 4.1 (dnovillo, 2004-09-17). */
|
||||
if (TREE_CODE (repl) != SSA_NAME)
|
||||
{
|
||||
tree tmp = stmt;
|
||||
fold_stmt (&tmp);
|
||||
mark_new_vars = true;
|
||||
if (tmp != stmt)
|
||||
{
|
||||
block_stmt_iterator si = bsi_for_stmt (stmt);
|
||||
mark_new_vars_to_rename (tmp, vars_to_rename);
|
||||
bsi_replace (&si, tmp, true);
|
||||
stmt = bsi_stmt (si);
|
||||
}
|
||||
}
|
||||
|
||||
/* If REPL is a pointer, it may have different memory tags associated
|
||||
with it. For instance, VAR may have had a name tag while REPL
|
||||
only had a type tag. In these cases, the virtual operands (if
|
||||
any) in the statement will refer to different symbols which need
|
||||
to be renamed. */
|
||||
if (mark_new_vars)
|
||||
mark_new_vars_to_rename (stmt, vars_to_rename);
|
||||
else
|
||||
update_stmt (stmt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Gets the value VAR is equivalent to according to EQ_TO. */
|
||||
|
||||
static tree
|
||||
get_eq_name (tree *eq_to, tree var)
|
||||
{
|
||||
unsigned ver;
|
||||
tree val = var;
|
||||
|
||||
while (TREE_CODE (val) == SSA_NAME)
|
||||
{
|
||||
ver = SSA_NAME_VERSION (val);
|
||||
if (!eq_to[ver])
|
||||
break;
|
||||
|
||||
val = eq_to[ver];
|
||||
}
|
||||
|
||||
while (TREE_CODE (var) == SSA_NAME)
|
||||
{
|
||||
ver = SSA_NAME_VERSION (var);
|
||||
if (!eq_to[ver])
|
||||
break;
|
||||
|
||||
var = eq_to[ver];
|
||||
eq_to[ver] = val;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Checks whether phi node PHI is redundant and if it is, records the ssa name
|
||||
its result is redundant to to EQ_TO array. */
|
||||
|
||||
static void
|
||||
check_phi_redundancy (tree phi, tree *eq_to)
|
||||
{
|
||||
tree val = NULL_TREE, def, res = PHI_RESULT (phi), stmt;
|
||||
unsigned i, ver = SSA_NAME_VERSION (res);
|
||||
imm_use_iterator imm_iter;
|
||||
use_operand_p use_p;
|
||||
|
||||
/* It is unlikely that such large phi node would be redundant. */
|
||||
if (PHI_NUM_ARGS (phi) > 16)
|
||||
return;
|
||||
|
||||
for (i = 0; i < (unsigned) PHI_NUM_ARGS (phi); i++)
|
||||
{
|
||||
def = PHI_ARG_DEF (phi, i);
|
||||
|
||||
if (TREE_CODE (def) == SSA_NAME)
|
||||
{
|
||||
def = get_eq_name (eq_to, def);
|
||||
if (def == res)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (val
|
||||
&& !operand_equal_for_phi_arg_p (val, def))
|
||||
return;
|
||||
|
||||
val = def;
|
||||
}
|
||||
|
||||
/* At least one of the arguments should not be equal to the result, or
|
||||
something strange is happening. */
|
||||
gcc_assert (val);
|
||||
|
||||
if (get_eq_name (eq_to, res) == val)
|
||||
return;
|
||||
|
||||
if (!may_propagate_copy (res, val))
|
||||
return;
|
||||
|
||||
eq_to[ver] = val;
|
||||
|
||||
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, res)
|
||||
{
|
||||
stmt = USE_STMT (use_p);
|
||||
if (TREE_CODE (stmt) == PHI_NODE)
|
||||
check_phi_redundancy (stmt, eq_to);
|
||||
}
|
||||
}
|
||||
|
||||
/* Removes redundant phi nodes.
|
||||
|
||||
A redundant PHI node is a PHI node where all of its PHI arguments
|
||||
are the same value, excluding any PHI arguments which are the same
|
||||
as the PHI result.
|
||||
|
||||
A redundant PHI node is effectively a copy, so we forward copy propagate
|
||||
which removes all uses of the destination of the PHI node then
|
||||
finally we delete the redundant PHI node.
|
||||
|
||||
Note that if we can not copy propagate the PHI node, then the PHI
|
||||
will not be removed. Thus we do not have to worry about dependencies
|
||||
between PHIs and the problems serializing PHIs into copies creates.
|
||||
|
||||
The most important effect of this pass is to remove degenerate PHI
|
||||
nodes created by removing unreachable code. */
|
||||
|
||||
void
|
||||
kill_redundant_phi_nodes (void)
|
||||
{
|
||||
tree *eq_to;
|
||||
unsigned i, old_num_ssa_names;
|
||||
basic_block bb;
|
||||
tree phi, repl, stmt;
|
||||
|
||||
/* The EQ_TO[VER] holds the value by that the ssa name VER should be
|
||||
replaced. If EQ_TO[VER] is ssa name and it is decided to replace it by
|
||||
other value, it may be necessary to follow the chain till the final value.
|
||||
We perform path shortening (replacing the entries of the EQ_TO array with
|
||||
heads of these chains) whenever we access the field to prevent quadratic
|
||||
complexity (probably would not occur in practice anyway, but let us play
|
||||
it safe). */
|
||||
eq_to = xcalloc (num_ssa_names, sizeof (tree));
|
||||
|
||||
old_num_ssa_names = num_ssa_names;
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
|
||||
check_phi_redundancy (phi, eq_to);
|
||||
}
|
||||
|
||||
/* Now propagate the values. */
|
||||
for (i = 0; i < old_num_ssa_names; i++)
|
||||
{
|
||||
if (!ssa_name (i))
|
||||
continue;
|
||||
|
||||
repl = get_eq_name (eq_to, ssa_name (i));
|
||||
if (repl != ssa_name (i))
|
||||
replace_immediate_uses (ssa_name (i), repl);
|
||||
}
|
||||
|
||||
/* And remove the dead phis. */
|
||||
for (i = 0; i < old_num_ssa_names; i++)
|
||||
{
|
||||
if (!ssa_name (i))
|
||||
continue;
|
||||
|
||||
repl = get_eq_name (eq_to, ssa_name (i));
|
||||
if (repl != ssa_name (i))
|
||||
{
|
||||
stmt = SSA_NAME_DEF_STMT (ssa_name (i));
|
||||
remove_phi_node (stmt, NULL_TREE);
|
||||
}
|
||||
}
|
||||
|
||||
free (eq_to);
|
||||
}
|
||||
|
||||
struct tree_opt_pass pass_redundant_phi =
|
||||
{
|
||||
"redphi", /* name */
|
||||
NULL, /* gate */
|
||||
kill_redundant_phi_nodes, /* execute */
|
||||
NULL, /* sub */
|
||||
NULL, /* next */
|
||||
0, /* static_pass_number */
|
||||
TV_TREE_REDPHI, /* tv_id */
|
||||
PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
|
||||
0, /* properties_provided */
|
||||
0, /* properties_destroyed */
|
||||
0, /* todo_flags_start */
|
||||
TODO_dump_func | TODO_rename_vars
|
||||
| TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */
|
||||
0 /* letter */
|
||||
};
|
||||
|
||||
/* Emit warnings for uninitialized variables. This is done in two passes.
|
||||
|
||||
|
|
|
@ -349,9 +349,18 @@ vect_create_data_ref_ptr (tree stmt, block_stmt_iterator *bsi, tree offset,
|
|||
|
||||
tag = STMT_VINFO_MEMTAG (stmt_info);
|
||||
gcc_assert (tag);
|
||||
get_var_ann (vect_ptr)->type_mem_tag = tag;
|
||||
get_var_ann (vect_ptr)->subvars = STMT_VINFO_SUBVARS (stmt_info);
|
||||
|
||||
/* If the memory tag of the original reference was not a type tag or
|
||||
if the pointed-to type of VECT_PTR has an alias set number
|
||||
different than TAG's, then we need to create a new type tag for
|
||||
VECT_PTR and add TAG to its alias set. */
|
||||
if (var_ann (tag)->mem_tag_kind == NOT_A_TAG
|
||||
|| get_alias_set (tag) != get_alias_set (TREE_TYPE (vect_ptr_type)))
|
||||
add_type_alias (vect_ptr, tag);
|
||||
else
|
||||
var_ann (vect_ptr)->type_mem_tag = tag;
|
||||
|
||||
var_ann (vect_ptr)->subvars = STMT_VINFO_SUBVARS (stmt_info);
|
||||
|
||||
/** (3) Calculate the initial address the vector-pointer, and set
|
||||
the vector-pointer to point to it before the loop: **/
|
||||
|
|
|
@ -1836,10 +1836,6 @@ vectorize_loops (struct loops *loops)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_loop_closed_ssa ();
|
||||
#endif
|
||||
|
||||
/* ----------- Analyze loops. ----------- */
|
||||
|
||||
/* If some loop was duplicated, it gets bigger number
|
||||
|
|
|
@ -176,7 +176,11 @@ typedef struct _stmt_vec_info {
|
|||
/* Information about the data-ref (access function, etc). */
|
||||
struct data_reference *data_ref_info;
|
||||
|
||||
/* Aliasing information. */
|
||||
/* Aliasing information. This field represents the symbol that
|
||||
should be aliased by a pointer holding the address of this data
|
||||
reference. If the original data reference was a pointer
|
||||
dereference, then this field contains the memory tag that should
|
||||
be used by the new vector-pointer. */
|
||||
tree memtag;
|
||||
struct ptr_info_def *ptr_info;
|
||||
subvar_t subvars;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
14
gcc/tree.def
14
gcc/tree.def
|
@ -899,6 +899,20 @@ DEFTREECODE (STATEMENT_LIST, "statement_list", tcc_exceptional, 0)
|
|||
the same value, they will be assigned the same value handle. */
|
||||
DEFTREECODE (VALUE_HANDLE, "value_handle", tcc_exceptional, 0)
|
||||
|
||||
/* Predicate assertion. Artificial expression generated by the optimizers
|
||||
to keep track of predicate values. This expression may only appear on
|
||||
the RHS of assignments.
|
||||
|
||||
Given X = ASSERT_EXPR <Y, EXPR>, the optimizers can infer
|
||||
two things:
|
||||
|
||||
1- X is a copy of Y.
|
||||
2- EXPR is a GIMPLE conditional expression (as defined by
|
||||
is_gimple_condexpr) and is known to be true.
|
||||
|
||||
The type of the expression is the same as Y. */
|
||||
DEFTREECODE (ASSERT_EXPR, "assert_expr", tcc_expression, 2)
|
||||
|
||||
/* Base class information. Holds information about a class as a
|
||||
baseclass of itself or another class. */
|
||||
DEFTREECODE (TREE_BINFO, "tree_binfo", tcc_exceptional, 0)
|
||||
|
|
19
gcc/tree.h
19
gcc/tree.h
|
@ -1283,6 +1283,10 @@ struct tree_vec GTY(())
|
|||
#define OBJ_TYPE_REF_OBJECT(NODE) TREE_OPERAND (OBJ_TYPE_REF_CHECK (NODE), 1)
|
||||
#define OBJ_TYPE_REF_TOKEN(NODE) TREE_OPERAND (OBJ_TYPE_REF_CHECK (NODE), 2)
|
||||
|
||||
/* ASSERT_EXPR accessors. */
|
||||
#define ASSERT_EXPR_VAR(NODE) TREE_OPERAND (ASSERT_EXPR_CHECK (NODE), 0)
|
||||
#define ASSERT_EXPR_COND(NODE) TREE_OPERAND (ASSERT_EXPR_CHECK (NODE), 1)
|
||||
|
||||
struct tree_exp GTY(())
|
||||
{
|
||||
struct tree_common common;
|
||||
|
@ -1329,12 +1333,17 @@ struct tree_exp GTY(())
|
|||
#define SSA_NAME_VALUE(N) \
|
||||
SSA_NAME_CHECK (N)->ssa_name.value_handle
|
||||
|
||||
/* Range information for SSA_NAMEs. */
|
||||
#define SSA_NAME_VALUE_RANGE(N) \
|
||||
SSA_NAME_CHECK (N)->ssa_name.value_range
|
||||
|
||||
/* Auxiliary pass-specific data. */
|
||||
#define SSA_NAME_AUX(N) \
|
||||
SSA_NAME_CHECK (N)->ssa_name.aux
|
||||
|
||||
#ifndef _TREE_FLOW_H
|
||||
struct ptr_info_def;
|
||||
struct value_range_def;
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -1372,6 +1381,9 @@ struct tree_ssa_name GTY(())
|
|||
as well. */
|
||||
tree value_handle;
|
||||
|
||||
/* Value range information. */
|
||||
struct value_range_def *value_range;
|
||||
|
||||
/* Auxiliary information stored with the ssa name. */
|
||||
PTR GTY((skip)) aux;
|
||||
|
||||
|
@ -1395,9 +1407,6 @@ struct tree_ssa_name GTY(())
|
|||
the link to the next PHI is in PHI_CHAIN. */
|
||||
#define PHI_CHAIN(NODE) TREE_CHAIN (PHI_NODE_CHECK (NODE))
|
||||
|
||||
/* Nonzero if the PHI node was rewritten by a previous pass through the
|
||||
SSA renamer. */
|
||||
#define PHI_REWRITTEN(NODE) PHI_NODE_CHECK (NODE)->phi.rewritten
|
||||
#define PHI_NUM_ARGS(NODE) PHI_NODE_CHECK (NODE)->phi.num_args
|
||||
#define PHI_ARG_CAPACITY(NODE) PHI_NODE_CHECK (NODE)->phi.capacity
|
||||
#define PHI_ARG_ELT(NODE, I) PHI_NODE_ELT_CHECK (NODE, I)
|
||||
|
@ -1422,10 +1431,6 @@ struct tree_phi_node GTY(())
|
|||
int num_args;
|
||||
int capacity;
|
||||
|
||||
/* Nonzero if the PHI node was rewritten by a previous pass through the
|
||||
SSA renamer. */
|
||||
int rewritten;
|
||||
|
||||
/* Basic block to that the phi node belongs. */
|
||||
struct basic_block_def *bb;
|
||||
|
||||
|
|
Loading…
Reference in New Issue