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:
Diego Novillo 2005-04-09 01:37:54 +00:00 committed by Diego Novillo
parent 45f9480e29
commit 0bca51f080
65 changed files with 7281 additions and 1576 deletions

View File

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

View File

@ -958,7 +958,8 @@ OBJS-common = \
varasm.o varray.o vec.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \
et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o \
rtl-profile.o tree-profile.o rtlhooks.o cfgexpand.o lambda-mat.o \
lambda-trans.o lambda-code.o tree-loop-linear.o tree-ssa-sink.o
lambda-trans.o lambda-code.o tree-loop-linear.o tree-ssa-sink.o \
tree-vrp.o
OBJS-md = $(out_object_file)
OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o \
@ -1654,7 +1655,7 @@ tree-nrv.o : tree-nrv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
tree-ssa-copy.o : tree-ssa-copy.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \
errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
$(BASIC_BLOCK_H) tree-pass.h langhooks.h
$(BASIC_BLOCK_H) tree-pass.h langhooks.h tree-ssa-propagate.h
tree-ssa-propagate.o : tree-ssa-propagate.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \
diagnostic.h errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h \
@ -1691,6 +1692,10 @@ tree-ssa-pre.o : tree-ssa-pre.c $(TREE_FLOW_H) $(CONFIG_H) \
tree-vn.o : tree-vn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GGC_H) \
$(TREE_H) $(TREE_FLOW_H) $(HASHTAB_H) langhooks.h tree-pass.h \
$(TREE_DUMP_H) diagnostic.h
tree-vrp.o : tree-vrp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) diagnostic.h $(GGC_H) \
$(BASIC_BLOCK_H) tree-ssa-propagate.h $(FLAGS_H) $(TREE_DUMP_H) \
$(CFGLOOP_H) tree-scalar-evolution.h tree-chrec.h
tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
diagnostic.h errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h \

View File

@ -896,6 +896,8 @@ extern void calculate_dominance_info (enum cdi_direction);
extern void free_dominance_info (enum cdi_direction);
extern basic_block nearest_common_dominator (enum cdi_direction,
basic_block, basic_block);
extern basic_block nearest_common_dominator_for_set (enum cdi_direction,
bitmap);
extern void set_immediate_dominator (enum cdi_direction, basic_block,
basic_block);
extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);

View File

@ -828,6 +828,10 @@ ftree-ccp
Common Report Var(flag_tree_ccp)
Enable SSA-CCP optimization on trees
ftree-store-ccp
Common Report Var(flag_tree_store_ccp)
Enable SSA-CCP optimization for stores and loads
ftree-ch
Common Report Var(flag_tree_ch)
Enable loop header copying on trees
@ -840,6 +844,14 @@ ftree-copyrename
Common Report Var(flag_tree_copyrename)
Replace SSA temporaries with better names in copies.
ftree-copy-prop
Common Report Var(flag_tree_copy_prop)
Enable copy propagation on trees
ftree-store-copy-prop
Common Report Var(flag_tree_store_copy_prop)
Enable copy propagation for stores and loads
ftree-dce
Common Report Var(flag_tree_dce)
Enable SSA dead code elimination optimization on trees
@ -896,6 +908,10 @@ ftree-lrs
Common Report Var(flag_tree_live_range_split)
Perform live range splitting during the SSA->normal pass.
ftree-vrp
Common Report Var(flag_tree_vrp) Init(0)
Perform Value Range Propagation on trees
funit-at-a-time
Common Report Var(flag_unit_at_a_time)
Compile whole compilation unit at a time

View File

@ -269,6 +269,7 @@ Objective-C and Objective-C++ Dialects}.
-fdump-tree-salias @gol
-fdump-tree-fre@r{[}-@var{n}@r{]} @gol
-ftree-vectorizer-verbose=@var{n} @gol
-fdump-tree-storeccp@r{[}-@var{n}@r{]} @gol
-feliminate-dwarf2-dups -feliminate-unused-debug-types @gol
-feliminate-unused-debug-symbols -fmem-report -fprofile-arcs -ftree-based-profiling @gol
-frandom-seed=@var{string} -fsched-verbose=@var{n} @gol
@ -324,6 +325,7 @@ Objective-C and Objective-C++ Dialects}.
-ftree-dominator-opts -ftree-dse -ftree-copyrename -ftree-sink @gol
-ftree-ch -ftree-sra -ftree-ter -ftree-lrs -ftree-fre -ftree-vectorize @gol
-ftree-salias -fweb @gol
-ftree-copy-prop -ftree-store-ccp -ftree-store-copy-prop @gol
--param @var{name}=@var{value}
-O -O0 -O1 -O2 -O3 -Os}
@ -3879,6 +3881,11 @@ appending @file{.alias} to the source file name.
Dump each function after CCP@. The file name is made by appending
@file{.ccp} to the source file name.
@item storeccp
@opindex fdump-tree-storeccp
Dump each function after STORE-CCP. The file name is made by appending
@file{.storeccp} to the source file name.
@item pre
@opindex fdump-tree-pre
Dump trees after partial redundancy elimination. The file name is made
@ -3889,6 +3896,16 @@ by appending @file{.pre} to the source file name.
Dump trees after full redundancy elimination. The file name is made
by appending @file{.fre} to the source file name.
@item copyprop
@opindex fdump-tree-copyprop
Dump trees after copy propagation. The file name is made
by appending @file{.copyprop} to the source file name.
@item store_copyprop
@opindex fdump-tree-store_copyprop
Dump trees after store copy-propagation. The file name is made
by appending @file{.store_copyprop} to the source file name.
@item dce
@opindex fdump-tree-dce
Dump each function after dead code elimination. The file name is made by
@ -4745,6 +4762,17 @@ that are computed on all paths leading to the redundant computation.
This analysis faster than PRE, though it exposes fewer redundancies.
This flag is enabled by default at @option{-O} and higher.
@item -ftree-copy-prop
Perform copy propagation on trees. This pass eliminates unnecessary
copy operations. This flag is enabled by default at @option{-O} and
higher.
@item -ftree-store-copy-prop
Perform copy propagation of memory loads and stores. This pass
eliminates unnecessary copy operations in memory references
(structures, global variables, arrays, etc). This flag is enabled by
default at @option{-O2} and higher.
@item -ftree-salias
Perform structural alias analysis on trees. This flag
is enabled by default at @option{-O} and higher.
@ -4754,8 +4782,15 @@ Perform forward store motion on trees. This flag is
enabled by default at @option{-O} and higher.
@item -ftree-ccp
Perform sparse conditional constant propagation (CCP) on trees. This flag
is enabled by default at @option{-O} and higher.
Perform sparse conditional constant propagation (CCP) on trees. This
pass only operates on local scalar variables and is enabled by default
at @option{-O} and higher.
@item -ftree-store-ccp
Perform sparse conditional constant propagation (CCP) on trees. This
pass operates on both local scalar variables and memory stores and
loads (global variables, structures, arrays, etc). This flag is
enabled by default at @option{-O2} and higher.
@item -ftree-dce
Perform dead code elimination (DCE) on trees. This flag is enabled by

View File

@ -83,8 +83,7 @@ perfectly happy to take it as input and spit out GIMPLE@.
GIMPLE is a simplified subset of GENERIC for use in optimization. The
particular subset chosen (and the name) was heavily influenced by the
SIMPLE IL used by the McCAT compiler project at McGill University
(@uref{http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html}),
SIMPLE IL used by the McCAT compiler project at McGill University,
though we have made some different choices. For one thing, SIMPLE
doesn't support @code{goto}; a production compiler can't afford that
kind of restriction.
@ -1111,18 +1110,129 @@ Returns the @code{SSA_NAME} for the @var{i}th argument of @var{phi}.
@subsection Preserving the SSA form
@findex vars_to_rename
@findex update_ssa
@cindex preserving SSA form
Some optimization passes make changes to the function that
invalidate the SSA property. This can happen when a pass has
added new variables or changed the program so that variables that
were previously aliased aren't anymore.
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

View File

@ -797,6 +797,27 @@ nearest_common_dominator (enum cdi_direction dir, basic_block bb1, basic_block b
return et_nca (bb1->dom[dir], bb2->dom[dir])->data;
}
/* Find the nearest common dominator for the basic blocks in BLOCKS,
using dominance direction DIR. */
basic_block
nearest_common_dominator_for_set (enum cdi_direction dir, bitmap blocks)
{
unsigned i, first;
bitmap_iterator bi;
basic_block dom;
first = bitmap_first_set_bit (blocks);
dom = BASIC_BLOCK (first);
EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
if (dom != BASIC_BLOCK (i))
dom = nearest_common_dominator (dir, dom, BASIC_BLOCK (i));
return dom;
}
/* Return TRUE in case BB1 is dominated by BB2. */
bool
dominated_by_p (enum cdi_direction dir, basic_block bb1, basic_block bb2)

View File

@ -145,6 +145,14 @@ walk_dominator_tree (struct dom_walk_data *walk_data, basic_block bb)
void *bd = NULL;
basic_block dest;
block_stmt_iterator bsi;
bool is_interesting;
/* If block BB is not interesting to the caller, then none of the
callbacks that walk the statements in BB are going to be
executed. */
is_interesting = bb->index < 0
|| walk_data->interesting_blocks == NULL
|| TEST_BIT (walk_data->interesting_blocks, bb->index);
/* Callback to initialize the local data structure. */
if (walk_data->initialize_block_local_data)
@ -179,7 +187,7 @@ walk_dominator_tree (struct dom_walk_data *walk_data, basic_block bb)
(*walk_data->before_dom_children_before_stmts) (walk_data, bb);
/* Statement walk before walking dominator children. */
if (walk_data->before_dom_children_walk_stmts)
if (is_interesting && walk_data->before_dom_children_walk_stmts)
{
if (walk_data->walk_stmts_backward)
for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
@ -211,7 +219,7 @@ walk_dominator_tree (struct dom_walk_data *walk_data, basic_block bb)
(*walk_data->after_dom_children_before_stmts) (walk_data, bb);
/* Statement walk after walking dominator children. */
if (walk_data->after_dom_children_walk_stmts)
if (is_interesting && walk_data->after_dom_children_walk_stmts)
{
if (walk_data->walk_stmts_backward)
for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))

View File

@ -105,6 +105,14 @@ struct dom_walk_data
/* Stack of available block local structures. */
varray_type free_block_data;
/* Interesting blocks to process. If this field is not NULL, this
set is used to determine which blocks to walk. If we encounter
block I in the dominator traversal, but block I is not present in
INTERESTING_BLOCKS, then none of the callback functions are
invoked on it. This is useful when a particular traversal wants
to filter out non-interesting blocks from the dominator tree. */
sbitmap interesting_blocks;
};
void walk_dominator_tree (struct dom_walk_data *, basic_block);

View File

@ -10005,6 +10005,21 @@ fold (tree expr)
case CONST_DECL:
return fold (DECL_INITIAL (t));
case ASSERT_EXPR:
{
/* Given ASSERT_EXPR <Y, COND>, return Y if COND can be folded
to boolean_true_node. If COND folds to boolean_false_node,
return ASSERT_EXPR <Y, 0>. Otherwise, return the original
expression. */
tree c = fold (ASSERT_EXPR_COND (t));
if (c == boolean_true_node)
return ASSERT_EXPR_VAR (t);
else if (c == boolean_false_node)
return build (ASSERT_EXPR, TREE_TYPE (t), ASSERT_EXPR_VAR (t), c);
else
return t;
}
default:
return t;
} /* switch (code) */

View File

@ -524,6 +524,7 @@ decode_options (unsigned int argc, const char **argv)
flag_tree_sra = 1;
flag_tree_copyrename = 1;
flag_tree_fre = 1;
flag_tree_copy_prop = 1;
flag_tree_sink = 1;
flag_tree_salias = 1;
@ -562,6 +563,9 @@ decode_options (unsigned int argc, const char **argv)
flag_reorder_blocks = 1;
flag_reorder_functions = 1;
flag_unit_at_a_time = 1;
flag_tree_store_ccp = 1;
flag_tree_store_copy_prop = 1;
flag_tree_vrp = 1;
if (!optimize_size)
{

View File

@ -1,3 +1,20 @@
2005-04-08 Diego Novillo <dnovillo@redhat.com>
* g++.dg/tree-ssa/pr18178.C: New test.
* gcc.c-torture/execute/20030216-1.x: Ignore at -O1.
* gcc.c-torture/execute/20041019-1.c: New test.
* gcc.dg/tree-ssa/20041008-1.c: New test.
* gcc.dg/tree-ssa/ssa-ccp-12.c: New test.
* gcc.dg/tree-ssa/20030731-2.c: Update to use -fdump-tree-store_ccp.
* gcc.dg/tree-ssa/20030917-1.c: Likewise.
* gcc.dg/tree-ssa/20030917-3.c: Likewise.
* gcc.dg/tree-ssa/20040721-1.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-1.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-2.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-3.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-7.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-9.c: Likewise.
2005-04-09 Hans-Peter Nilsson <hp@axis.com>
PR rtl-optimization/20466

View File

@ -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"} } */

View File

@ -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

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-ccp" } */
/* { dg-options "-O1 -fdump-tree-store_ccp" } */
bar (int i, int partial, int args_addr)
@ -13,5 +13,5 @@ bar (int i, int partial, int args_addr)
/* There should be only one IF conditional since the first does nothing
useful. */
/* { dg-final { scan-tree-dump-times "if " 1 "ccp"} } */
/* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-final { scan-tree-dump-times "if " 1 "store_ccp"} } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-ccp" } */
/* { dg-options "-O1 -fdump-tree-store_ccp" } */
extern int board[];
@ -15,5 +15,5 @@ findbestextension (int blah, int blah2)
}
/* The argument to "foo" should be a variable, not a constant. */
/* { dg-final { scan-tree-dump-times "foo .defval" 1 "ccp"} } */
/* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-final { scan-tree-dump-times "foo .defval" 1 "store_ccp"} } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fno-tree-dominator-opts -fdump-tree-ccp" } */
/* { dg-options "-O1 -fno-tree-dominator-opts -fdump-tree-store_ccp" } */
extern int printf (const char *, ...);
@ -20,5 +20,5 @@ main ()
/* The argument to "printf" should be a constant, not a variable. */
/* { dg-final { scan-tree-dump-times "printf.*, 0" 1 "ccp"} } */
/* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-final { scan-tree-dump-times "printf.*, 0" 1 "store_ccp"} } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-ccp-vops" } */
/* { dg-options "-O2 -fdump-tree-store_ccp-vops" } */
/* Test to check whether global variables are being
constant propagated. */
@ -24,5 +24,5 @@ main ()
}
/* There should be no G on the RHS of an assignment. */
/* { dg-final { scan-tree-dump-times "= G;" 0 "ccp"} } */
/* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-final { scan-tree-dump-times "= G;" 0 "store_ccp"} } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-ccp" } */
/* { dg-options "-O1 -fdump-tree-store_ccp" } */
extern void link_error (void);
@ -71,5 +71,5 @@ void test11111 (int p, int q, int r)
/* There should be not link_error calls, if there is any the
optimization has failed */
/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */
/* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp"} } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-ccp" } */
/* { dg-options "-O1 -fdump-tree-store_ccp" } */
extern void link_error (void);
@ -168,5 +168,5 @@ int test99999 (void)
/* There should be not link_error calls, if there is any the
optimization has failed */
/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */
/* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp"} } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-ccp" } */
/* { dg-options "-O1 -fdump-tree-store_ccp" } */
extern void link_error (void);
@ -131,5 +131,5 @@ int* test666 (int * __restrict__ rp1, int * __restrict__ rp2, int *p1)
optimization has failed */
/* ??? While we indeed don't handle some of these, a couple of the
restrict tests are incorrect. */
/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-ccp" } */
/* { dg-options "-O1 -fdump-tree-store_ccp" } */
extern void link_error (void);
@ -23,5 +23,5 @@ int test7 (int a)
/* There should be not link_error calls, if there is any the
optimization has failed */
/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */
/* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp"} } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-ccp" } */
/* { dg-options "-O1 -fdump-tree-store_ccp" } */
/* Check that cprop works for assignments to array elements and structs. */
@ -51,5 +51,5 @@ test99999 (int *arr, int j)
/* There should be no link_error calls, if there is any, the
optimization has failed */
/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */
/* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "store_ccp"} } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */

View File

@ -65,15 +65,20 @@ DEFTIMEVAR (TV_TREE_GIMPLIFY , "tree gimplify")
DEFTIMEVAR (TV_TREE_EH , "tree eh")
DEFTIMEVAR (TV_TREE_CFG , "tree CFG construction")
DEFTIMEVAR (TV_TREE_CLEANUP_CFG , "tree CFG cleanup")
DEFTIMEVAR (TV_TREE_VRP , "tree VRP")
DEFTIMEVAR (TV_TREE_COPY_PROP , "tree copy propagation")
DEFTIMEVAR (TV_TREE_STORE_COPY_PROP , "tree store copy propagation")
DEFTIMEVAR (TV_FIND_REFERENCED_VARS , "tree find referenced vars")
DEFTIMEVAR (TV_TREE_PTA , "tree PTA")
DEFTIMEVAR (TV_TREE_MAY_ALIAS , "tree alias analysis")
DEFTIMEVAR (TV_TREE_INSERT_PHI_NODES , "tree PHI insertion")
DEFTIMEVAR (TV_TREE_SSA_REWRITE_BLOCKS, "tree SSA rewrite")
DEFTIMEVAR (TV_TREE_SSA_OTHER , "tree SSA other")
DEFTIMEVAR (TV_TREE_SSA_INCREMENTAL , "tree SSA incremental")
DEFTIMEVAR (TV_TREE_OPS , "tree operand scan")
DEFTIMEVAR (TV_TREE_SSA_DOMINATOR_OPTS , "dominator optimization")
DEFTIMEVAR (TV_TREE_SRA , "tree SRA")
DEFTIMEVAR (TV_TREE_STORE_CCP , "tree STORE-CCP")
DEFTIMEVAR (TV_TREE_CCP , "tree CCP")
DEFTIMEVAR (TV_TREE_SPLIT_EDGES , "tree split crit edges")
DEFTIMEVAR (TV_TREE_PRE , "tree PRE")

View File

@ -1282,8 +1282,7 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
&& DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)))
return false;
/* There may be no phi nodes at the start of b. Most of these degenerate
phi nodes should be cleaned up by kill_redundant_phi_nodes. */
/* There may be no PHI nodes at the start of B. */
if (phi_nodes (b))
return false;
@ -3428,6 +3427,15 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
}
break;
case ASSERT_EXPR:
x = fold (ASSERT_EXPR_COND (t));
if (x == boolean_false_node)
{
error ("ASSERT_EXPR with an always-false condition");
return *tp;
}
break;
case MODIFY_EXPR:
x = TREE_OPERAND (t, 0);
if (TREE_CODE (x) == BIT_FIELD_REF

View File

@ -1023,7 +1023,7 @@ struct tree_opt_pass pass_lower_vector_ssa =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_rename_vars /* todo_flags_finish */
TODO_dump_func | TODO_update_ssa /* todo_flags_finish */
| TODO_ggc_collect | TODO_verify_ssa
| TODO_verify_stmts | TODO_verify_flow,
0 /* letter */

View File

@ -215,8 +215,9 @@ make_rename_temp (tree type, const char *prefix)
if (referenced_vars)
{
add_referenced_tmp_var (t);
bitmap_set_bit (vars_to_rename, var_ann (t)->uid);
mark_sym_for_renaming (t);
}
return t;
}
@ -617,11 +618,11 @@ add_referenced_tmp_var (tree var)
}
/* Add all the non-SSA variables found in STMT's operands to the bitmap
VARS_TO_RENAME. */
/* Mark all the non-SSA variables found in STMT's operands to be
processed by update_ssa. */
void
mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename)
mark_new_vars_to_rename (tree stmt)
{
ssa_op_iter iter;
tree val;
@ -660,13 +661,11 @@ mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename)
v_must_defs_after = NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt));
FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_ALL_OPERANDS)
{
if (DECL_P (val))
{
found_exposed_symbol = true;
bitmap_set_bit (vars_to_rename, var_ann (val)->uid);
}
}
if (DECL_P (val))
{
found_exposed_symbol = true;
mark_sym_for_renaming (val);
}
/* If we found any newly exposed symbols, or if there are fewer VDEF
operands in the statement, add the variables we had set in
@ -676,7 +675,7 @@ mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename)
if (found_exposed_symbol
|| v_may_defs_before > v_may_defs_after
|| v_must_defs_before > v_must_defs_after)
bitmap_ior_into (vars_to_rename, vars_in_vops_to_rename);
mark_set_for_renaming (vars_in_vops_to_rename);
BITMAP_FREE (vars_in_vops_to_rename);
}
@ -691,7 +690,10 @@ find_new_referenced_vars_1 (tree *tp, int *walk_subtrees,
tree t = *tp;
if (TREE_CODE (t) == VAR_DECL && !var_ann (t))
add_referenced_tmp_var (t);
{
add_referenced_tmp_var (t);
mark_sym_for_renaming (t);
}
if (IS_TYPE_OR_DECL_P (t))
*walk_subtrees = 0;
@ -706,20 +708,6 @@ find_new_referenced_vars (tree *stmt_p)
}
/* Mark all call-clobbered variables for renaming. */
void
mark_call_clobbered_vars_to_rename (void)
{
unsigned i;
bitmap_iterator bi;
EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
{
tree var = referenced_var (i);
bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
}
}
/* If REF is a COMPONENT_REF for a structure that can have sub-variables, and
we know where REF is accessing, return the variable in REF that has the
sub-variables. If the return value is not NULL, POFFSET will be the

View File

@ -1176,6 +1176,17 @@ op_iter_init_maydef (ssa_op_iter *ptr, tree stmt, use_operand_p *use,
op_iter_next_maydef (use, def, ptr);
}
/* Return true if VAR cannot be modified by the program. */
static inline bool
unmodifiable_var_p (tree var)
{
if (TREE_CODE (var) == SSA_NAME)
var = SSA_NAME_VAR (var);
return TREE_READONLY (var) && (TREE_STATIC (var) || DECL_EXTERNAL (var));
}
/* Initialize iterator PTR to the operands in STMT. Return the first operands
in KILL and DEF. */
static inline void

View File

@ -80,6 +80,34 @@ struct ptr_info_def GTY(())
};
/* Types of value ranges. */
enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING };
/* Ranges of values that can be associated with an SSA_NAME after VRP
has executed. */
struct value_range_def GTY(())
{
/* Lattice value represented by this range. */
enum value_range_type type;
/* Minimum and maximum values represented by this range. These
values are _CST nodes that should be interpreted as follows:
- If TYPE == VR_UNDEFINED then MIN and MAX must be NULL.
- If TYPE == VR_RANGE then MIN holds the minimum value and
MAX holds the maximum value of the range [MIN, MAX].
- If TYPE == ANTI_RANGE the variable is known to NOT
take any values in the range [MIN, MAX]. */
tree min;
tree max;
};
typedef struct value_range_def value_range;
/*---------------------------------------------------------------------------
Tree annotations stored in tree_common.ann
---------------------------------------------------------------------------*/
@ -534,7 +562,7 @@ extern tree create_phi_node (tree, basic_block);
extern void add_phi_arg (tree, tree, edge);
extern void remove_phi_args (edge);
extern void remove_phi_node (tree, tree);
extern void remove_all_phi_nodes_for (bitmap);
extern tree find_phi_node_for (basic_block, tree, tree *);
extern tree phi_reverse (tree);
extern void dump_dfa_stats (FILE *);
extern void debug_dfa_stats (void);
@ -544,9 +572,8 @@ extern void dump_variable (FILE *, tree);
extern void debug_variable (tree);
extern tree get_virtual_var (tree);
extern void add_referenced_tmp_var (tree);
extern void mark_new_vars_to_rename (tree, bitmap);
extern void mark_new_vars_to_rename (tree);
extern void find_new_referenced_vars (tree *);
void mark_call_clobbered_vars_to_rename (void);
extern tree make_rename_temp (tree, const char *);
@ -568,6 +595,8 @@ extern void dump_points_to_info_for (FILE *, tree);
extern void debug_points_to_info_for (tree);
extern bool may_be_aliased (tree);
extern struct ptr_info_def *get_ptr_info (tree);
extern void add_type_alias (tree, tree);
extern void count_uses_and_derefs (tree, tree, unsigned *, unsigned *, bool *);
static inline subvar_t get_subvars_for_var (tree);
static inline bool ref_contains_array_ref (tree);
extern tree okay_component_ref_for_subvars (tree, HOST_WIDE_INT *,
@ -596,24 +625,43 @@ extern void verify_ssa (bool);
extern void delete_tree_ssa (void);
extern void register_new_def (tree, VEC (tree_on_heap) **);
extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
extern void kill_redundant_phi_nodes (void);
extern bool stmt_references_memory_p (tree);
/* In tree-into-ssa.c */
extern void rewrite_into_ssa (bool);
extern void rewrite_ssa_into_ssa (void);
extern void rewrite_def_def_chains (void);
void update_ssa (unsigned);
void register_new_name_mapping (tree, tree);
tree create_new_def_for (tree, tree, def_operand_p);
bool need_ssa_update_p (void);
bool name_registered_for_update_p (tree);
bitmap ssa_names_to_replace (void);
void release_ssa_name_after_update_ssa (tree name);
void dump_repl_tbl (FILE *);
void debug_repl_tbl (void);
void dump_names_replaced_by (FILE *, tree);
void debug_names_replaced_by (tree);
void compute_global_livein (bitmap, bitmap);
tree duplicate_ssa_name (tree, tree);
void mark_sym_for_renaming (tree);
void mark_set_for_renaming (bitmap);
/* In tree-ssa-ccp.c */
bool fold_stmt (tree *);
tree widen_bitfield (tree, tree, tree);
/* In tree-vrp.c */
value_range *get_value_range (tree);
void dump_value_range (FILE *, value_range *);
void debug_value_range (value_range *);
void dump_all_value_ranges (FILE *);
void debug_all_value_ranges (void);
bool expr_computes_nonzero (tree);
/* In tree-ssa-dom.c */
extern void dump_dominator_optimization_stats (FILE *);
extern void debug_dominator_optimization_stats (void);
int loop_depth_of_name (tree);
/* In tree-ssa-copy.c */
extern void propagate_value (use_operand_p, tree);
@ -711,6 +759,7 @@ extern enum move_pos movement_possibility (tree);
static inline bool is_call_clobbered (tree);
static inline void mark_call_clobbered (tree);
static inline void set_is_used (tree);
static inline bool unmodifiable_var_p (tree);
/* In tree-eh.c */
extern void make_eh_edges (tree);

View File

@ -73,6 +73,7 @@ is_gimple_formal_tmp_rhs (tree t)
case COMPLEX_CST:
case VECTOR_CST:
case OBJ_TYPE_REF:
case ASSERT_EXPR:
return true;
default:

View File

@ -117,7 +117,8 @@ static void add_to_predicate_list (basic_block, tree);
static tree add_to_dst_predicate_list (struct loop * loop, basic_block, tree, tree,
block_stmt_iterator *);
static void clean_predicate_lists (struct loop *loop);
static basic_block find_phi_replacement_condition (basic_block, tree *,
static basic_block find_phi_replacement_condition (struct loop *loop,
basic_block, tree *,
block_stmt_iterator *);
static void replace_phi_with_cond_modify_expr (tree, tree, basic_block,
block_stmt_iterator *);
@ -677,7 +678,8 @@ clean_predicate_lists (struct loop *loop)
whose phi arguments are selected when cond is true. */
static basic_block
find_phi_replacement_condition (basic_block bb, tree *cond,
find_phi_replacement_condition (struct loop *loop,
basic_block bb, tree *cond,
block_stmt_iterator *bsi)
{
edge e;
@ -702,12 +704,22 @@ find_phi_replacement_condition (basic_block bb, tree *cond,
tmp_cond = p1->aux;
if (TREE_CODE (tmp_cond) == TRUTH_NOT_EXPR)
{
*cond = p2->aux;
/* If p2 is loop->header than its aux field does not have useful
info. Instead use !(cond) where cond is p1's aux field. */
if (p2 == loop->header)
*cond = invert_truthvalue (unshare_expr (p1->aux));
else
*cond = p2->aux;
true_bb = p2;
}
else
{
*cond = p1->aux;
/* If p1 is loop->header than its aux field does not have useful
info. Instead use !(cond) where cond is p2's aux field. */
if (p1 == loop->header)
*cond = invert_truthvalue (unshare_expr (p2->aux));
else
*cond = p1->aux;
true_bb = p1;
}
@ -828,7 +840,7 @@ process_phi_nodes (struct loop *loop)
/* BB has two predecessors. Using predecessor's aux field, set
appropriate condition for the PHI node replacement. */
if (phi)
true_bb = find_phi_replacement_condition (bb, &cond, &bsi);
true_bb = find_phi_replacement_condition (loop, bb, &cond, &bsi);
while (phi)
{
@ -1113,20 +1125,17 @@ gate_tree_if_conversion (void)
struct tree_opt_pass pass_if_conversion =
{
"ifcvt", /* name */
gate_tree_if_conversion, /* gate */
main_tree_if_conversion, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
0, /* tv_id */
PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
TODO_dump_func, /* todo_flags_start */
TODO_dump_func
| TODO_verify_ssa
| TODO_verify_stmts
| TODO_verify_flow, /* todo_flags_finish */
0 /* letter */
"ifcvt", /* name */
gate_tree_if_conversion, /* gate */
main_tree_if_conversion, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
0, /* tv_id */
PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_verify_loops, /* todo_flags_finish */
0 /* letter */
};

File diff suppressed because it is too large Load Diff

View File

@ -371,9 +371,6 @@ linear_transform_loops (struct loops *loops)
free_data_refs (datarefs);
}
scev_reset ();
rewrite_into_ssa (false);
update_ssa (TODO_update_ssa);
rewrite_into_loop_closed_ssa (NULL);
#ifdef ENABLE_CHECKING
verify_loop_closed_ssa ();
#endif
}

View File

@ -52,7 +52,6 @@ Boston, MA 02111-1307, USA. */
/* Global variables used to communicate with passes. */
int dump_flags;
bitmap vars_to_rename;
bool in_gimple_form;
/* The root of the compilation pass tree, once constructed. */
@ -355,8 +354,9 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_early_warn_uninitialized);
NEXT_PASS (pass_dce);
NEXT_PASS (pass_dominator);
NEXT_PASS (pass_redundant_phi);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_dce);
NEXT_PASS (pass_vrp);
NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_phiopt);
@ -371,14 +371,14 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_dominator);
NEXT_PASS (pass_redundant_phi);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_dce);
NEXT_PASS (pass_dse);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_phiopt);
NEXT_PASS (pass_ccp);
NEXT_PASS (pass_redundant_phi);
NEXT_PASS (pass_store_ccp);
NEXT_PASS (pass_store_copy_prop);
NEXT_PASS (pass_fold_builtins);
/* FIXME: May alias should a TODO but for 4.0.0,
we add may_alias right after fold builtins
@ -389,7 +389,7 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_sink_code);
NEXT_PASS (pass_loop);
NEXT_PASS (pass_dominator);
NEXT_PASS (pass_redundant_phi);
NEXT_PASS (pass_copy_prop);
/* FIXME: If DCE is not run before checking for uninitialized uses,
we may get false warnings (e.g., testsuite/gcc.dg/uninit-5.c).
However, this also causes us to misdiagnose cases that should be
@ -415,6 +415,7 @@ init_tree_optimization_passes (void)
p = &pass_loop.sub;
NEXT_PASS (pass_loop_init);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_lim);
NEXT_PASS (pass_unswitch);
NEXT_PASS (pass_record_bounds);
@ -443,15 +444,15 @@ execute_todo (struct tree_opt_pass *pass, unsigned int flags, bool use_required)
int properties
= use_required ? pass->properties_required : pass->properties_provided;
if (flags & TODO_rename_vars)
#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 (&reg_obstack); /* FIXME, only at RTL generation*/
vars_to_rename = BITMAP_ALLOC (NULL);
/* Perform all tree transforms and optimizations. */
execute_pass_list (all_passes);

View File

@ -28,8 +28,6 @@ extern FILE *dump_file;
extern int dump_flags;
extern const char *dump_file_name;
extern struct bitmap_head_def *vars_to_rename;
/* Return the dump_file_info for the given phase. */
extern struct dump_file_info *get_dump_file_info (enum tree_dump_index);
@ -101,19 +99,60 @@ struct dump_file_info
(PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh)
/* To-do flags. */
#define TODO_dump_func (1 << 0) /* pass doesn't dump itself */
#define TODO_rename_vars (1 << 1) /* rewrite new vars to ssa */
#define TODO_ggc_collect (1 << 2) /* run the collector */
#define TODO_verify_ssa (1 << 3)
#define TODO_verify_flow (1 << 4)
#define TODO_verify_stmts (1 << 5)
#define TODO_fix_def_def_chains (1 << 6) /* rewrite def-def chains */
#define TODO_cleanup_cfg (1 << 7) /* cleanup the cfg. */
#define TODO_dump_func (1 << 0)
#define TODO_ggc_collect (1 << 1)
#define TODO_verify_ssa (1 << 2)
#define TODO_verify_flow (1 << 3)
#define TODO_verify_stmts (1 << 4)
#define TODO_cleanup_cfg (1 << 5)
#define TODO_verify_loops (1 << 6)
/* To-do flags for calls to update_ssa. */
/* Update the SSA form inserting PHI nodes for newly exposed symbols
and virtual names marked for updating. When updating real names,
only insert PHI nodes for a real name O_j in blocks reached by all
the new and old definitions for O_j. If the iterated dominance
frontier for O_j is not pruned, we may end up inserting PHI nodes
in blocks that have one or more edges with no incoming definition
for O_j. This would lead to uninitialized warnings for O_j's
symbol. */
#define TODO_update_ssa (1 << 7)
/* Update the SSA form without inserting any new PHI nodes at all.
This is used by passes that have either inserted all the PHI nodes
themselves or passes that need only to patch use-def and def-def
chains for virtuals (e.g., DCE). */
#define TODO_update_ssa_no_phi (1 << 8)
/* Insert PHI nodes everywhere they are needed. No prunning of the
IDF is done. This is used by passes that need the PHI nodes for
O_j even if it means that some arguments will come from the default
definition of O_j's symbol (e.g., pass_linear_transform).
WARNING: If you need to use this flag, chances are that your pass
may be doing something wrong. Inserting PHI nodes for an old name
where not all edges carry a new replacement may lead to silent
codegen errors or spurious uninitialized warnings. */
#define TODO_update_ssa_full_phi (1 << 9)
/* Passes that update the SSA form on their own may want to delegate
the updating of virtual names to the generic updater. Since FUD
chains are easier to maintain, this simplifies the work they need
to do. NOTE: If this flag is used, any OLD->NEW mappings for real
names are explicitly destroyed and only the symbols marked for
renaming are processed. */
#define TODO_update_ssa_only_virtuals (1 << 10)
#define TODO_update_ssa_any \
(TODO_update_ssa \
| TODO_update_ssa_no_phi \
| TODO_update_ssa_full_phi \
| TODO_update_ssa_only_virtuals)
#define TODO_verify_all \
(TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts)
extern struct tree_opt_pass pass_mudflap_1;
extern struct tree_opt_pass pass_mudflap_2;
extern struct tree_opt_pass pass_remove_useless_stmts;
@ -167,6 +206,10 @@ extern struct tree_opt_pass pass_rest_of_compilation;
extern struct tree_opt_pass pass_sink_code;
extern struct tree_opt_pass pass_fre;
extern struct tree_opt_pass pass_linear_transform;
extern struct tree_opt_pass pass_copy_prop;
extern struct tree_opt_pass pass_store_ccp;
extern struct tree_opt_pass pass_store_copy_prop;
extern struct tree_opt_pass pass_vrp;
extern struct tree_opt_pass pass_create_structure_vars;
#endif /* GCC_TREE_PASS_H */

View File

@ -197,10 +197,8 @@ ideal_phi_node_len (int len)
return new_len;
}
/* Return a PHI node for variable VAR defined in statement STMT.
STMT may be an empty statement for artificial references (e.g., default
definitions created when a variable is used without a preceding
definition). */
/* Return a PHI node with LEN argument slots for variable VAR. */
static tree
make_phi_node (tree var, int len)
@ -468,58 +466,30 @@ remove_phi_node (tree phi, tree prev)
}
/* Remove all the PHI nodes for variables in the VARS bitmap. */
/* Find the first PHI node P in basic block BB for symbol SYM. If
PREV_P is given, the PHI node preceding P is stored in *PREV_P. */
void
remove_all_phi_nodes_for (bitmap vars)
tree
find_phi_node_for (basic_block bb, tree sym, tree *prev_p)
{
basic_block bb;
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"

View File

@ -1430,6 +1430,14 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
pp_printf (buffer, "VH.%d", VALUE_HANDLE_ID (node));
break;
case ASSERT_EXPR:
pp_string (buffer, "ASSERT_EXPR <");
dump_generic_node (buffer, ASSERT_EXPR_VAR (node), spc, flags, false);
pp_string (buffer, ", ");
dump_generic_node (buffer, ASSERT_EXPR_COND (node), spc, flags, false);
pp_string (buffer, ">");
break;
case SCEV_KNOWN:
pp_string (buffer, "scev_known");
break;

View File

@ -1065,8 +1065,8 @@ follow_ssa_edge_in_rhs (struct loop *loop,
- an INTEGER_CST,
- a PLUS_EXPR,
- a MINUS_EXPR,
- other cases are not yet handled.
*/
- an ASSERT_EXPR,
- other cases are not yet handled. */
switch (TREE_CODE (rhs))
{
case NOP_EXPR:
@ -1247,6 +1247,20 @@ follow_ssa_edge_in_rhs (struct loop *loop,
break;
case ASSERT_EXPR:
{
/* This assignment is of the form: "a_1 = ASSERT_EXPR <a_2, ...>"
It must be handled as a copy assignment of the form a_1 = a_2. */
tree op0 = ASSERT_EXPR_VAR (rhs);
if (TREE_CODE (op0) == SSA_NAME)
res = follow_ssa_edge (loop, SSA_NAME_DEF_STMT (op0),
halting_phi, evolution_of_loop);
else
res = false;
break;
}
default:
res = false;
break;
@ -1701,6 +1715,11 @@ interpret_rhs_modify_expr (struct loop *loop,
case SSA_NAME:
res = chrec_convert (type, analyze_scalar_evolution (loop, opnd1));
break;
case ASSERT_EXPR:
opnd10 = ASSERT_EXPR_VAR (opnd1);
res = chrec_convert (type, analyze_scalar_evolution (loop, opnd10));
break;
case NOP_EXPR:
case CONVERT_EXPR:

View File

@ -1428,6 +1428,8 @@ decide_instantiations (void)
}
bitmap_clear (&done_head);
mark_set_for_renaming (sra_candidates);
if (dump_file)
fputc ('\n', dump_file);
}
@ -1439,7 +1441,7 @@ decide_instantiations (void)
renaming. This becomes necessary when we modify all of a non-scalar. */
static void
mark_all_v_defs (tree stmt)
mark_all_v_defs_1 (tree stmt)
{
tree sym;
ssa_op_iter iter;
@ -1450,10 +1452,28 @@ mark_all_v_defs (tree stmt)
{
if (TREE_CODE (sym) == SSA_NAME)
sym = SSA_NAME_VAR (sym);
bitmap_set_bit (vars_to_rename, var_ann (sym)->uid);
mark_sym_for_renaming (sym);
}
}
/* Mark all the variables in virtual operands in all the statements in
LIST for renaming. */
static void
mark_all_v_defs (tree list)
{
if (TREE_CODE (list) != STATEMENT_LIST)
mark_all_v_defs_1 (list);
else
{
tree_stmt_iterator i;
for (i = tsi_start (list); !tsi_end_p (i); tsi_next (&i))
mark_all_v_defs_1 (tsi_stmt (i));
}
}
/* Build a single level component reference to ELT rooted at BASE. */
static tree
@ -1706,7 +1726,7 @@ generate_element_init (struct sra_elt *elt, tree init, tree *list_p)
new = num_referenced_vars;
for (j = old; j < new; ++j)
bitmap_set_bit (vars_to_rename, j);
mark_sym_for_renaming (referenced_var (j));
}
return ret;
@ -1820,7 +1840,7 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
generate_copy_inout (elt, is_output, generate_element_ref (elt), &list);
if (list == NULL)
return;
mark_all_v_defs (expr_first (list));
mark_all_v_defs (list);
if (is_output)
sra_insert_after (bsi, list);
else
@ -1865,7 +1885,7 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
generate_element_ref (rhs_elt), &list);
if (list)
{
mark_all_v_defs (expr_first (list));
mark_all_v_defs (list);
sra_insert_before (bsi, list);
}
@ -1873,7 +1893,10 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
generate_copy_inout (lhs_elt, true,
generate_element_ref (lhs_elt), &list);
if (list)
sra_insert_after (bsi, list);
{
mark_all_v_defs (list);
sra_insert_after (bsi, list);
}
}
else
{
@ -1887,6 +1910,7 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
list = NULL;
generate_element_copy (lhs_elt, rhs_elt, &list);
gcc_assert (list);
mark_all_v_defs (list);
sra_replace (bsi, list);
}
}
@ -1936,7 +1960,7 @@ scalarize_init (struct sra_elt *lhs_elt, tree rhs, block_stmt_iterator *bsi)
exposes constants to later optimizations. */
if (list)
{
mark_all_v_defs (expr_first (list));
mark_all_v_defs (list);
sra_insert_after (bsi, list);
}
}
@ -1946,6 +1970,7 @@ scalarize_init (struct sra_elt *lhs_elt, tree rhs, block_stmt_iterator *bsi)
replaces the original structure assignment. */
gcc_assert (list);
mark_all_v_defs (bsi_stmt (*bsi));
mark_all_v_defs (list);
sra_replace (bsi, list);
}
}
@ -1996,6 +2021,7 @@ scalarize_ldst (struct sra_elt *elt, tree other,
mark_all_v_defs (stmt);
generate_copy_inout (elt, is_output, other, &list);
mark_all_v_defs (list);
gcc_assert (list);
/* Preserve EH semantics. */
@ -2051,7 +2077,10 @@ scalarize_parms (void)
}
if (list)
insert_edge_copies (list, ENTRY_BLOCK_PTR);
{
insert_edge_copies (list, ENTRY_BLOCK_PTR);
mark_all_v_defs (list);
}
}
/* Entry point to phase 4. Update the function to match replacements. */
@ -2154,7 +2183,7 @@ struct tree_opt_pass pass_sra =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_rename_vars
TODO_dump_func | TODO_update_ssa
| TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */
0 /* letter */
};

View File

@ -371,7 +371,7 @@ struct tree_opt_pass pass_may_alias =
PROP_alias, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_rename_vars
TODO_dump_func | TODO_update_ssa
| TODO_ggc_collect | TODO_verify_ssa
| TODO_verify_stmts, /* todo_flags_finish */
0 /* letter */
@ -407,7 +407,7 @@ count_ptr_derefs (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
*NUM_DEREFS_P respectively. *IS_STORE_P is set to 'true' if at
least one of those dereferences is a store operation. */
static void
void
count_uses_and_derefs (tree ptr, tree stmt, unsigned *num_uses_p,
unsigned *num_derefs_p, bool *is_store)
{
@ -770,7 +770,7 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
/* Mark variables in V_MAY_DEF operands as being written to. */
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS)
{
tree var = SSA_NAME_VAR (op);
tree var = DECL_P (op) ? op : SSA_NAME_VAR (op);
var_ann_t ann = var_ann (var);
bitmap_set_bit (ai->written_vars, ann->uid);
}
@ -855,7 +855,7 @@ create_name_tags (struct alias_info *ai)
needs to be removed from the IL, so we mark it for
renaming. */
if (old_name_tag && old_name_tag != pi->name_mem_tag)
bitmap_set_bit (vars_to_rename, var_ann (old_name_tag)->uid);
mark_sym_for_renaming (old_name_tag);
}
else if (pi->pt_malloc)
{
@ -875,7 +875,7 @@ create_name_tags (struct alias_info *ai)
|= TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (ptr)));
/* Mark the new name tag for renaming. */
bitmap_set_bit (vars_to_rename, var_ann (pi->name_mem_tag)->uid);
mark_sym_for_renaming (pi->name_mem_tag);
}
}
@ -1000,7 +1000,11 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
|| bitmap_bit_p (ai->written_vars, v_ann->uid);
if (!tag_stored_p && !var_stored_p)
continue;
if ((unmodifiable_var_p (tag) && !unmodifiable_var_p (var))
|| (unmodifiable_var_p (var) && !unmodifiable_var_p (tag)))
continue;
if (may_alias_p (p_map->var, p_map->set, var, v_map->set))
{
subvar_t svars;
@ -1449,9 +1453,10 @@ setup_pointers_and_addressables (struct alias_info *ai)
&& !is_global_var (var))
{
bool okay_to_mark = true;
/* Since VAR is now a regular GIMPLE register, we will need
to rename VAR into SSA afterwards. */
bitmap_set_bit (vars_to_rename, v_ann->uid);
mark_sym_for_renaming (var);
if (var_can_have_subvars (var)
&& (svars = get_subvars_for_var (var)))
@ -1463,15 +1468,15 @@ setup_pointers_and_addressables (struct alias_info *ai)
var_ann_t svann = var_ann (sv->var);
if (bitmap_bit_p (ai->addresses_needed, svann->uid))
okay_to_mark = false;
bitmap_set_bit (vars_to_rename, svann->uid);
mark_sym_for_renaming (sv->var);
}
}
/* The address of VAR is not needed, remove the
addressable bit, so that it can be optimized as a
regular variable. */
if (okay_to_mark)
mark_non_addressable (var);
}
else
{
@ -1496,7 +1501,7 @@ setup_pointers_and_addressables (struct alias_info *ai)
if (may_be_aliased (var))
{
create_alias_map_for (var, ai);
bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
mark_sym_for_renaming (var);
}
/* Add pointer variables that have been dereferenced to the POINTERS
@ -1519,7 +1524,13 @@ setup_pointers_and_addressables (struct alias_info *ai)
afterwards. Note that we cannot do this inside
get_tmt_for because aliasing may run multiple times
and we only create type tags the first time. */
bitmap_set_bit (vars_to_rename, t_ann->uid);
mark_sym_for_renaming (tag);
/* Similarly, if pointer VAR used to have another type
tag, we will need to process it in the renamer to
remove the stale virtual operands. */
if (v_ann->type_mem_tag)
mark_sym_for_renaming (v_ann->type_mem_tag);
/* Associate the tag with pointer VAR. */
v_ann->type_mem_tag = tag;
@ -1555,7 +1566,7 @@ setup_pointers_and_addressables (struct alias_info *ai)
tree tag = ann->type_mem_tag;
if (tag)
{
bitmap_set_bit (vars_to_rename, var_ann (tag)->uid);
mark_sym_for_renaming (tag);
ann->type_mem_tag = NULL_TREE;
}
}
@ -1661,11 +1672,11 @@ maybe_create_global_var (struct alias_info *ai)
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
bitmap_set_bit (vars_to_rename, var_ann (sv->var)->uid);
mark_sym_for_renaming (sv->var);
}
}
bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
mark_sym_for_renaming (var);
}
}
@ -1802,7 +1813,7 @@ set_pt_anything (tree ptr)
disassociated from PTR. */
if (pi->name_mem_tag)
{
bitmap_set_bit (vars_to_rename, var_ann (pi->name_mem_tag)->uid);
mark_sym_for_renaming (pi->name_mem_tag);
pi->name_mem_tag = NULL_TREE;
}
}
@ -2358,7 +2369,7 @@ create_global_var (void)
TREE_ADDRESSABLE (global_var) = 0;
add_referenced_tmp_var (global_var);
bitmap_set_bit (vars_to_rename, var_ann (global_var)->uid);
mark_sym_for_renaming (global_var);
}
@ -2673,6 +2684,83 @@ may_be_aliased (tree var)
return true;
}
/* Add VAR to the list of may-aliases of PTR's type tag. If PTR
doesn't already have a type tag, create one. */
void
add_type_alias (tree ptr, tree var)
{
varray_type aliases;
tree tag;
var_ann_t ann = var_ann (ptr);
if (ann->type_mem_tag == NULL_TREE)
{
size_t i;
tree q = NULL_TREE;
tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
HOST_WIDE_INT tag_set = get_alias_set (tag_type);
/* PTR doesn't have a type tag, create a new one and add VAR to
the new tag's alias set.
FIXME, This is slower than necessary. We need to determine
whether there is another pointer Q with the same alias set as
PTR. This could be sped up by having type tags associated
with types. */
for (i = 0; i < num_referenced_vars; i++)
{
q = referenced_var (i);
if (POINTER_TYPE_P (TREE_TYPE (q))
&& tag_set == get_alias_set (TREE_TYPE (TREE_TYPE (q))))
{
/* Found another pointer Q with the same alias set as
the PTR's pointed-to type. If Q has a type tag, use
it. Otherwise, create a new memory tag for PTR. */
var_ann_t ann1 = var_ann (q);
if (ann1->type_mem_tag)
ann->type_mem_tag = ann1->type_mem_tag;
else
ann->type_mem_tag = create_memory_tag (tag_type, true);
goto found_tag;
}
}
/* Couldn't find any other pointer with a type tag we could use.
Create a new memory tag for PTR. */
ann->type_mem_tag = create_memory_tag (tag_type, true);
}
found_tag:
/* If VAR is not already PTR's type tag, add it to the may-alias set
for PTR's type tag. */
gcc_assert (var_ann (var)->type_mem_tag == NOT_A_TAG);
tag = ann->type_mem_tag;
add_may_alias (tag, var);
/* TAG and its set of aliases need to be marked for renaming. */
mark_sym_for_renaming (tag);
if ((aliases = var_ann (tag)->may_aliases) != NULL)
{
size_t i;
for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++)
mark_sym_for_renaming (VARRAY_TREE (aliases, i));
}
/* If we had grouped aliases, VAR may have aliases of its own. Mark
them for renaming as well. Other statements referencing the
aliases of VAR will need to be updated. */
if ((aliases = var_ann (var)->may_aliases) != NULL)
{
size_t i;
for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++)
mark_sym_for_renaming (VARRAY_TREE (aliases, i));
}
}
/* This structure is simply used during pushing fields onto the fieldstack
to track the offset of the field, since bitpos_of_field gives it relative
to its immediate containing type, and we want it relative to the ultimate
@ -3168,4 +3256,3 @@ struct tree_opt_pass pass_create_structure_vars =
TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* Const/copy propagation and SSA_NAME replacement support routines.
/* Copy propagation and SSA_NAME replacement support routines.
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
@ -37,11 +37,13 @@ Boston, MA 02111-1307, USA. */
#include "tree-dump.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "tree-ssa-propagate.h"
#include "langhooks.h"
/* This file provides a handful of interfaces for performing const/copy
propagation and simple expression replacement which keep variable
annotations up-to-date.
/* This file implements the copy propagation pass and provides a
handful of interfaces for performing const/copy propagation and
simple expression replacement which keep variable annotations
up-to-date.
We require that for any copy operation where the RHS and LHS have
a non-null memory tag the memory tag be the same. It is OK
@ -54,7 +56,6 @@ Boston, MA 02111-1307, USA. */
replacements of one SSA_NAME with a different SSA_NAME to use the
APIs defined in this file. */
/* Return true if we may propagate ORIG into DEST, false otherwise. */
bool
@ -103,8 +104,10 @@ may_propagate_copy (tree dest, tree orig)
I think that GIMPLE should emit the appropriate type-casts. For the
time being, blocking copy-propagation in these cases is the safe thing
to do. */
if (TREE_CODE (dest) == SSA_NAME && TREE_CODE (orig) == SSA_NAME
&& POINTER_TYPE_P (type_d) && POINTER_TYPE_P (type_o))
if (TREE_CODE (dest) == SSA_NAME
&& TREE_CODE (orig) == SSA_NAME
&& POINTER_TYPE_P (type_d)
&& POINTER_TYPE_P (type_o))
{
tree mt_dest = var_ann (SSA_NAME_VAR (dest))->type_mem_tag;
tree mt_orig = var_ann (SSA_NAME_VAR (orig))->type_mem_tag;
@ -123,17 +126,9 @@ may_propagate_copy (tree dest, tree orig)
{
/* If both operands are SSA_NAMEs referring to virtual operands, then
we can always propagate. */
if (TREE_CODE (orig) == SSA_NAME)
{
if (!is_gimple_reg (orig))
return true;
#ifdef ENABLE_CHECKING
/* If we have one real and one virtual operand, then something has
gone terribly wrong. */
gcc_assert (!is_gimple_reg (orig));
#endif
}
if (TREE_CODE (orig) == SSA_NAME
&& !is_gimple_reg (orig))
return true;
/* We have a "copy" from something like a constant into a virtual
operand. Reject these. */
@ -202,30 +197,33 @@ merge_alias_info (tree orig, tree new)
else
gcc_assert (new_ann->type_mem_tag == orig_ann->type_mem_tag);
#if defined ENABLE_CHECKING
{
struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig);
struct ptr_info_def *new_ptr_info = SSA_NAME_PTR_INFO (new);
if (orig_ptr_info
&& new_ptr_info
&& orig_ptr_info->name_mem_tag
&& new_ptr_info->name_mem_tag
&& orig_ptr_info->pt_vars
&& new_ptr_info->pt_vars)
/* Synchronize the name tags. If NEW did not have a name tag, get
it from ORIG. This happens when NEW is a compiler generated
temporary which still hasn't had its points-to information filled
in. */
if (SSA_NAME_PTR_INFO (orig))
{
/* Note that pointer NEW may actually have a different set of
pointed-to variables. However, since NEW is being
copy-propagated into ORIG, it must always be true that the
pointed-to set for pointer NEW is the same, or a subset, of
the pointed-to set for pointer ORIG. If this isn't the case,
we shouldn't have been able to do the propagation of NEW into
ORIG. */
gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
orig_ptr_info->pt_vars));
struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig);
struct ptr_info_def *new_ptr_info = SSA_NAME_PTR_INFO (new);
if (new_ptr_info == NULL)
duplicate_ssa_name_ptr_info (new, orig_ptr_info);
else if (orig_ptr_info->name_mem_tag
&& new_ptr_info->name_mem_tag
&& orig_ptr_info->pt_vars
&& new_ptr_info->pt_vars)
{
/* Note that pointer NEW may actually have a different set
of pointed-to variables. However, since NEW is being
copy-propagated into ORIG, it must always be true that
the pointed-to set for pointer NEW is the same, or a
subset, of the pointed-to set for pointer ORIG. If this
isn't the case, we shouldn't have been able to do the
propagation of NEW into ORIG. */
gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
orig_ptr_info->pt_vars));
}
}
}
#endif
}
@ -310,3 +308,776 @@ replace_exp (use_operand_p op_p, tree val)
{
replace_exp_1 (op_p, val, false);
}
/*---------------------------------------------------------------------------
Copy propagation
---------------------------------------------------------------------------*/
/* During propagation, we keep chains of variables that are copies of
one another. If variable X_i is a copy of X_j and X_j is a copy of
X_k, COPY_OF will contain:
COPY_OF[i].VALUE = X_j
COPY_OF[j].VALUE = X_k
COPY_OF[k].VALUE = X_k
After propagation, the copy-of value for each variable X_i is
converted into the final value by walking the copy-of chains and
updating COPY_OF[i].VALUE to be the last element of the chain. */
static prop_value_t *copy_of;
/* Used in set_copy_of_val to determine if the last link of a copy-of
chain has changed. */
static tree *cached_last_copy_of;
/* True if we are doing copy propagation on loads and stores. */
static bool do_store_copy_prop;
/* Return true if this statement may generate a useful copy. */
static bool
stmt_may_generate_copy (tree stmt)
{
tree lhs, rhs;
stmt_ann_t ann;
if (TREE_CODE (stmt) == PHI_NODE)
return !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (stmt));
if (TREE_CODE (stmt) != MODIFY_EXPR)
return false;
lhs = TREE_OPERAND (stmt, 0);
rhs = TREE_OPERAND (stmt, 1);
ann = stmt_ann (stmt);
/* If the statement has volatile operands, it won't generate a
useful copy. */
if (ann->has_volatile_ops)
return false;
/* If we are not doing store copy-prop, statements with loads and/or
stores will never generate a useful copy. */
if (!do_store_copy_prop
&& (NUM_VUSES (VUSE_OPS (ann)) > 0
|| NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) > 0
|| NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) > 0))
return false;
/* Otherwise, the only statements that generate useful copies are
assignments whose RHS is just an SSA name that doesn't flow
through abnormal edges. */
return TREE_CODE (rhs) == SSA_NAME && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs);
}
/* Return the copy-of value for VAR. */
static inline prop_value_t *
get_copy_of_val (tree var)
{
prop_value_t *val = &copy_of[SSA_NAME_VERSION (var)];
if (val->value == NULL_TREE
&& !stmt_may_generate_copy (SSA_NAME_DEF_STMT (var)))
{
/* If the variable will never generate a useful copy relation,
make it its own copy. */
val->value = var;
val->mem_ref = NULL_TREE;
}
return val;
}
/* Return last link in the copy-of chain for VAR. */
static tree
get_last_copy_of (tree var)
{
tree last;
int i;
/* Traverse COPY_OF starting at VAR until we get to the last
link in the chain. Since it is possible to have cycles in PHI
nodes, the copy-of chain may also contain cycles.
To avoid infinite loops and to avoid traversing lengthy copy-of
chains, we artificially limit the maximum number of chains we are
willing to traverse.
The value 5 was taken from a compiler and runtime library
bootstrap and a mixture of C and C++ code from various sources.
More than 82% of all copy-of chains were shorter than 5 links. */
#define LIMIT 5
last = var;
for (i = 0; i < LIMIT; i++)
{
tree copy = copy_of[SSA_NAME_VERSION (last)].value;
if (copy == NULL_TREE || copy == last)
break;
last = copy;
}
/* If we have reached the limit, then we are either in a copy-of
cycle or the copy-of chain is too long. In this case, just
return VAR so that it is not considered a copy of anything. */
return (i < LIMIT ? last : var);
}
/* Set FIRST to be the first variable in the copy-of chain for DEST.
If DEST's copy-of value or its copy-of chain have changed, return
true.
MEM_REF is the memory reference where FIRST is stored. This is
used when DEST is a non-register and we are copy propagating loads
and stores. */
static inline bool
set_copy_of_val (tree dest, tree first, tree mem_ref)
{
unsigned int dest_ver = SSA_NAME_VERSION (dest);
tree old_first, old_last, new_last;
/* Set FIRST to be the first link in COPY_OF[DEST]. If that
changed, return true. */
old_first = copy_of[dest_ver].value;
copy_of[dest_ver].value = first;
copy_of[dest_ver].mem_ref = mem_ref;
if (old_first != first)
return true;
/* If FIRST and OLD_FIRST are the same, we need to check whether the
copy-of chain starting at FIRST ends in a different variable. If
the copy-of chain starting at FIRST ends up in a different
variable than the last cached value we had for DEST, then return
true because DEST is now a copy of a different variable.
This test is necessary because even though the first link in the
copy-of chain may not have changed, if any of the variables in
the copy-of chain changed its final value, DEST will now be the
copy of a different variable, so we have to do another round of
propagation for everything that depends on DEST. */
old_last = cached_last_copy_of[dest_ver];
new_last = get_last_copy_of (dest);
cached_last_copy_of[dest_ver] = new_last;
return (old_last != new_last);
}
/* Dump the copy-of value for variable VAR to DUMP_FILE. */
static void
dump_copy_of (FILE *dump_file, tree var)
{
tree val;
print_generic_expr (dump_file, var, dump_flags);
if (TREE_CODE (var) != SSA_NAME)
return;
fprintf (dump_file, " copy-of chain: ");
val = var;
print_generic_expr (dump_file, val, 0);
fprintf (dump_file, " ");
while (copy_of[SSA_NAME_VERSION (val)].value
&& copy_of[SSA_NAME_VERSION (val)].value != val)
{
fprintf (dump_file, "-> ");
val = copy_of[SSA_NAME_VERSION (val)].value;
print_generic_expr (dump_file, val, 0);
fprintf (dump_file, " ");
}
val = get_copy_of_val (var)->value;
if (val == NULL_TREE)
fprintf (dump_file, "[UNDEFINED]");
else if (val != var)
fprintf (dump_file, "[COPY]");
else
fprintf (dump_file, "[NOT A COPY]");
}
/* Evaluate the RHS of STMT. If it produces a valid copy, set the LHS
value and store the LHS into *RESULT_P. If STMT generates more
than one name (i.e., STMT is an aliased store), it is enough to
store the first name in the V_MAY_DEF list into *RESULT_P. After
all, the names generated will be VUSEd in the same statements. */
static enum ssa_prop_result
copy_prop_visit_assignment (tree stmt, tree *result_p)
{
tree lhs, rhs;
prop_value_t *rhs_val;
lhs = TREE_OPERAND (stmt, 0);
rhs = TREE_OPERAND (stmt, 1);
gcc_assert (TREE_CODE (rhs) == SSA_NAME);
rhs_val = get_copy_of_val (rhs);
if (TREE_CODE (lhs) == SSA_NAME)
{
/* Straight copy between two SSA names. First, make sure that
we can propagate the RHS into uses of LHS. */
if (!may_propagate_copy (lhs, rhs))
return SSA_PROP_VARYING;
/* Avoid copy propagation from an inner into an outer loop.
Otherwise, this may move loop variant variables outside of
their loops and prevent coalescing opportunities. If the
value was loop invariant, it will be hoisted by LICM and
exposed for copy propagation. */
if (loop_depth_of_name (rhs) > loop_depth_of_name (lhs))
return SSA_PROP_VARYING;
/* Notice that in the case of assignments, we make the LHS be a
copy of RHS's value, not of RHS itself. This avoids keeping
unnecessary copy-of chains (assignments cannot be in a cycle
like PHI nodes), speeding up the propagation process.
This is different from what we do in copy_prop_visit_phi_node.
In those cases, we are interested in the copy-of chains. */
*result_p = lhs;
if (set_copy_of_val (*result_p, rhs_val->value, rhs_val->mem_ref))
return SSA_PROP_INTERESTING;
else
return SSA_PROP_NOT_INTERESTING;
}
else if (stmt_makes_single_store (stmt))
{
/* Otherwise, set the names in V_MAY_DEF/V_MUST_DEF operands
to be a copy of RHS. */
ssa_op_iter i;
tree vdef;
bool changed;
/* This should only be executed when doing store copy-prop. */
gcc_assert (do_store_copy_prop);
/* Set the value of every VDEF to RHS_VAL. */
changed = false;
FOR_EACH_SSA_TREE_OPERAND (vdef, stmt, i, SSA_OP_VIRTUAL_DEFS)
changed |= set_copy_of_val (vdef, rhs_val->value, lhs);
/* Note that for propagation purposes, we are only interested in
visiting statements that load the exact same memory reference
stored here. Those statements will have the exact same list
of virtual uses, so it is enough to set the output of this
statement to be its first virtual definition. */
*result_p = first_vdef (stmt);
if (changed)
return SSA_PROP_INTERESTING;
else
return SSA_PROP_NOT_INTERESTING;
}
return SSA_PROP_VARYING;
}
/* Visit the COND_EXPR STMT. Return SSA_PROP_INTERESTING
if it can determine which edge will be taken. Otherwise, return
SSA_PROP_VARYING. */
static enum ssa_prop_result
copy_prop_visit_cond_stmt (tree stmt, edge *taken_edge_p)
{
enum ssa_prop_result retval;
tree cond;
use_optype uses;
cond = COND_EXPR_COND (stmt);
uses = STMT_USE_OPS (stmt);
retval = SSA_PROP_VARYING;
/* The only conditionals that we may be able to compute statically
are predicates involving at least one SSA_NAME. */
if (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
&& NUM_USES (uses) >= 1)
{
unsigned i;
tree *orig;
/* Save the original operands. */
orig = xmalloc (sizeof (tree) * NUM_USES (uses));
for (i = 0; i < NUM_USES (uses); i++)
{
orig[i] = USE_OP (uses, i);
SET_USE_OP (uses, i, get_last_copy_of (USE_OP (uses, i)));
}
/* See if we can determine the predicate's value. */
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Trying to determine truth value of ");
fprintf (dump_file, "predicate ");
print_generic_stmt (dump_file, cond, 0);
}
*taken_edge_p = find_taken_edge (bb_for_stmt (stmt), cond);
if (*taken_edge_p)
retval = SSA_PROP_INTERESTING;
/* Restore the original operands. */
for (i = 0; i < NUM_USES (uses); i++)
SET_USE_OP (uses, i, orig[i]);
free (orig);
}
if (dump_file && (dump_flags & TDF_DETAILS) && *taken_edge_p)
fprintf (dump_file, "\nConditional will always take edge %d->%d\n",
(*taken_edge_p)->src->index, (*taken_edge_p)->dest->index);
return retval;
}
/* Evaluate statement STMT. If the statement produces a new output
value, return SSA_PROP_INTERESTING and store the SSA_NAME holding
the new value in *RESULT_P.
If STMT is a conditional branch and we can determine its truth
value, set *TAKEN_EDGE_P accordingly.
If the new value produced by STMT is varying, return
SSA_PROP_VARYING. */
static enum ssa_prop_result
copy_prop_visit_stmt (tree stmt, edge *taken_edge_p, tree *result_p)
{
stmt_ann_t ann;
enum ssa_prop_result retval;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nVisiting statement:\n");
print_generic_stmt (dump_file, stmt, dump_flags);
fprintf (dump_file, "\n");
}
ann = stmt_ann (stmt);
if (TREE_CODE (stmt) == MODIFY_EXPR
&& TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME
&& (do_store_copy_prop
|| TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME))
{
/* If the statement is a copy assignment, evaluate its RHS to
see if the lattice value of its output has changed. */
retval = copy_prop_visit_assignment (stmt, result_p);
}
else if (TREE_CODE (stmt) == COND_EXPR)
{
/* See if we can determine which edge goes out of a conditional
jump. */
retval = copy_prop_visit_cond_stmt (stmt, taken_edge_p);
}
else
retval = SSA_PROP_VARYING;
if (retval == SSA_PROP_VARYING)
{
tree def;
ssa_op_iter i;
/* Any other kind of statement is not interesting for constant
propagation and, therefore, not worth simulating. */
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "No interesting values produced.\n");
/* The assignment is not a copy operation. Don't visit this
statement again and mark all the definitions in the statement
to be copies of nothing. */
FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_ALL_DEFS)
set_copy_of_val (def, def, NULL_TREE);
}
return retval;
}
/* Visit PHI node PHI. If all the arguments produce the same value,
set it to be the value of the LHS of PHI. */
static enum ssa_prop_result
copy_prop_visit_phi_node (tree phi)
{
enum ssa_prop_result retval;
int i;
tree lhs;
prop_value_t phi_val = { 0, NULL_TREE, NULL_TREE };
lhs = PHI_RESULT (phi);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nVisiting PHI node: ");
print_generic_expr (dump_file, phi, dump_flags);
fprintf (dump_file, "\n\n");
}
for (i = 0; i < PHI_NUM_ARGS (phi); i++)
{
prop_value_t *arg_val;
tree arg = PHI_ARG_DEF (phi, i);
edge e = PHI_ARG_EDGE (phi, i);
/* We don't care about values flowing through non-executable
edges. */
if (!(e->flags & EDGE_EXECUTABLE))
continue;
/* Constants in the argument list never generate a useful copy.
Similarly, names that flow through abnormal edges cannot be
used to derive copies. */
if (TREE_CODE (arg) != SSA_NAME || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (arg))
{
phi_val.value = lhs;
break;
}
/* Avoid copy propagation from an inner into an outer loop.
Otherwise, this may move loop variant variables outside of
their loops and prevent coalescing opportunities. If the
value was loop invariant, it will be hoisted by LICM and
exposed for copy propagation. */
if (loop_depth_of_name (arg) > loop_depth_of_name (lhs))
{
phi_val.value = lhs;
break;
}
/* If the LHS appears in the argument list, ignore it. It is
irrelevant as a copy. */
if (arg == lhs || get_last_copy_of (arg) == lhs)
continue;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\tArgument #%d: ", i);
dump_copy_of (dump_file, arg);
fprintf (dump_file, "\n");
}
arg_val = get_copy_of_val (arg);
/* If the LHS didn't have a value yet, make it a copy of the
first argument we find. Notice that while we make the LHS be
a copy of the argument itself, we take the memory reference
from the argument's value so that we can compare it to the
memory reference of all the other arguments. */
if (phi_val.value == NULL_TREE)
{
phi_val.value = arg;
phi_val.mem_ref = arg_val->mem_ref;
continue;
}
/* If PHI_VAL and ARG don't have a common copy-of chain, then
this PHI node cannot be a copy operation. Also, if we are
copy propagating stores and these two arguments came from
different memory references, they cannot be considered
copies. */
if (get_last_copy_of (phi_val.value) != get_last_copy_of (arg)
|| (do_store_copy_prop
&& phi_val.mem_ref
&& arg_val->mem_ref
&& simple_cst_equal (phi_val.mem_ref, arg_val->mem_ref) != 1))
{
phi_val.value = lhs;
break;
}
}
if (phi_val.value && set_copy_of_val (lhs, phi_val.value, phi_val.mem_ref))
retval = (phi_val.value != lhs) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING;
else
retval = SSA_PROP_NOT_INTERESTING;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nPHI node ");
dump_copy_of (dump_file, lhs);
fprintf (dump_file, "\nTelling the propagator to ");
if (retval == SSA_PROP_INTERESTING)
fprintf (dump_file, "add SSA edges out of this PHI and continue.");
else if (retval == SSA_PROP_VARYING)
fprintf (dump_file, "add SSA edges out of this PHI and never visit again.");
else
fprintf (dump_file, "do nothing with SSA edges and keep iterating.");
fprintf (dump_file, "\n\n");
}
return retval;
}
/* Initialize structures used for copy propagation. */
static void
init_copy_prop (void)
{
basic_block bb;
copy_of = xmalloc (num_ssa_names * sizeof (*copy_of));
memset (copy_of, 0, num_ssa_names * sizeof (*copy_of));
cached_last_copy_of = xmalloc (num_ssa_names * sizeof (*cached_last_copy_of));
memset (cached_last_copy_of, 0, num_ssa_names * sizeof (*cached_last_copy_of));
FOR_EACH_BB (bb)
{
block_stmt_iterator si;
tree phi;
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
{
tree stmt = bsi_stmt (si);
/* The only statements that we care about are those that may
generate useful copies. We also need to mark conditional
jumps so that their outgoing edges are added to the work
lists of the propagator. */
if (stmt_ends_bb_p (stmt))
DONT_SIMULATE_AGAIN (stmt) = false;
else if (stmt_may_generate_copy (stmt))
DONT_SIMULATE_AGAIN (stmt) = false;
else
{
tree def;
ssa_op_iter iter;
/* No need to simulate this statement anymore. */
DONT_SIMULATE_AGAIN (stmt) = true;
/* Mark all the outputs of this statement as not being
the copy of anything. */
FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
set_copy_of_val (def, def, NULL_TREE);
}
}
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
DONT_SIMULATE_AGAIN (phi) = false;
}
}
/* Deallocate memory used in copy propagation and do final
substitution. */
static void
fini_copy_prop (void)
{
size_t i;
/* Set the final copy-of value for each variable by traversing the
copy-of chains. */
for (i = 1; i < num_ssa_names; i++)
{
tree var = ssa_name (i);
if (var && copy_of[i].value && copy_of[i].value != var)
copy_of[i].value = get_last_copy_of (var);
}
substitute_and_fold (copy_of);
free (copy_of);
}
/* Main entry point to the copy propagator. The algorithm propagates
the value COPY-OF using ssa_propagate. For every variable X_i,
COPY-OF(X_i) indicates which variable is X_i created from. The
following example shows how the algorithm proceeds at a high level:
1 a_24 = x_1
2 a_2 = PHI <a_24, x_1>
3 a_5 = PHI <a_2>
4 x_1 = PHI <x_298, a_5, a_2>
The end result should be that a_2, a_5, a_24 and x_1 are a copy of
x_298. Propagation proceeds as follows.
Visit #1: a_24 is copy-of x_1. Value changed.
Visit #2: a_2 is copy-of x_1. Value changed.
Visit #3: a_5 is copy-of x_1. Value changed.
Visit #4: x_1 is copy-of x_298. Value changed.
Visit #1: a_24 is copy-of x_298. Value changed.
Visit #2: a_2 is copy-of x_298. Value changed.
Visit #3: a_5 is copy-of x_298. Value changed.
Visit #4: x_1 is copy-of x_298. Stable state reached.
When visiting PHI nodes, we only consider arguments that flow
through edges marked executable by the propagation engine. So,
when visiting statement #2 for the first time, we will only look at
the first argument (a_24) and optimistically assume that its value
is the copy of a_24 (x_1).
The problem with this approach is that it may fail to discover copy
relations in PHI cycles. Instead of propagating copy-of
values, we actually propagate copy-of chains. For instance:
A_3 = B_1;
C_9 = A_3;
D_4 = C_9;
X_i = D_4;
In this code fragment, COPY-OF (X_i) = { D_4, C_9, A_3, B_1 }.
Obviously, we are only really interested in the last value of the
chain, however the propagator needs to access the copy-of chain
when visiting PHI nodes.
To represent the copy-of chain, we use the array COPY_CHAINS, which
holds the first link in the copy-of chain for every variable.
If variable X_i is a copy of X_j, which in turn is a copy of X_k,
the array will contain:
COPY_CHAINS[i] = X_j
COPY_CHAINS[j] = X_k
COPY_CHAINS[k] = X_k
Keeping copy-of chains instead of copy-of values directly becomes
important when visiting PHI nodes. Suppose that we had the
following PHI cycle, such that x_52 is already considered a copy of
x_53:
1 x_54 = PHI <x_53, x_52>
2 x_53 = PHI <x_898, x_54>
Visit #1: x_54 is copy-of x_53 (because x_52 is copy-of x_53)
Visit #2: x_53 is copy-of x_898 (because x_54 is a copy of x_53,
so it is considered irrelevant
as a copy).
Visit #1: x_54 is copy-of nothing (x_53 is a copy-of x_898 and
x_52 is a copy of x_53, so
they don't match)
Visit #2: x_53 is copy-of nothing
This problem is avoided by keeping a chain of copies, instead of
the final copy-of value. Propagation will now only keep the first
element of a variable's copy-of chain. When visiting PHI nodes,
arguments are considered equal if their copy-of chains end in the
same variable. So, as long as their copy-of chains overlap, we
know that they will be a copy of the same variable, regardless of
which variable that may be).
Propagation would then proceed as follows (the notation a -> b
means that a is a copy-of b):
Visit #1: x_54 = PHI <x_53, x_52>
x_53 -> x_53
x_52 -> x_53
Result: x_54 -> x_53. Value changed. Add SSA edges.
Visit #1: x_53 = PHI <x_898, x_54>
x_898 -> x_898
x_54 -> x_53
Result: x_53 -> x_898. Value changed. Add SSA edges.
Visit #2: x_54 = PHI <x_53, x_52>
x_53 -> x_898
x_52 -> x_53 -> x_898
Result: x_54 -> x_898. Value changed. Add SSA edges.
Visit #2: x_53 = PHI <x_898, x_54>
x_898 -> x_898
x_54 -> x_898
Result: x_53 -> x_898. Value didn't change. Stable state
Once the propagator stabilizes, we end up with the desired result
x_53 and x_54 are both copies of x_898. */
static void
execute_copy_prop (bool store_copy_prop)
{
do_store_copy_prop = store_copy_prop;
init_copy_prop ();
ssa_propagate (copy_prop_visit_stmt, copy_prop_visit_phi_node);
fini_copy_prop ();
}
static bool
gate_copy_prop (void)
{
return flag_tree_copy_prop != 0;
}
static void
do_copy_prop (void)
{
execute_copy_prop (false);
}
struct tree_opt_pass pass_copy_prop =
{
"copyprop", /* name */
gate_copy_prop, /* gate */
do_copy_prop, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_TREE_COPY_PROP, /* tv_id */
PROP_ssa | PROP_alias | PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_cleanup_cfg
| TODO_dump_func
| TODO_ggc_collect
| TODO_verify_ssa
| TODO_update_ssa, /* todo_flags_finish */
0 /* letter */
};
static bool
gate_store_copy_prop (void)
{
/* STORE-COPY-PROP is enabled only with -ftree-store-copy-prop, but
when -fno-tree-store-copy-prop is specified, we should run
regular COPY-PROP. That's why the pass is enabled with either
flag. */
return flag_tree_store_copy_prop != 0 || flag_tree_copy_prop != 0;
}
static void
store_copy_prop (void)
{
/* If STORE-COPY-PROP is not enabled, we just run regular COPY-PROP. */
execute_copy_prop (flag_tree_store_copy_prop != 0);
}
struct tree_opt_pass pass_store_copy_prop =
{
"store_copyprop", /* name */
gate_store_copy_prop, /* gate */
store_copy_prop, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_TREE_STORE_COPY_PROP, /* tv_id */
PROP_ssa | PROP_alias | PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func
| TODO_cleanup_cfg
| TODO_ggc_collect
| TODO_verify_ssa
| TODO_update_ssa, /* todo_flags_finish */
0 /* letter */
};

View File

@ -779,8 +779,7 @@ remove_dead_stmt (block_stmt_iterator *i, basic_block bb)
SSA_OP_VIRTUAL_DEFS | SSA_OP_VIRTUAL_KILLS)
{
tree def = DEF_FROM_PTR (def_p);
bitmap_set_bit (vars_to_rename,
var_ann (SSA_NAME_VAR (def))->uid);
mark_sym_for_renaming (SSA_NAME_VAR (def));
}
bsi_remove (i);
release_defs (t);
@ -942,7 +941,11 @@ struct tree_opt_pass pass_dce =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_fix_def_def_chains | TODO_cleanup_cfg | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */
TODO_dump_func
| TODO_update_ssa_no_phi
| TODO_cleanup_cfg
| TODO_ggc_collect
| TODO_verify_ssa, /* todo_flags_finish */
0 /* letter */
};
@ -959,8 +962,12 @@ struct tree_opt_pass pass_cd_dce =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_fix_def_def_chains | TODO_cleanup_cfg | TODO_ggc_collect | TODO_verify_ssa | TODO_verify_flow,
/* todo_flags_finish */
TODO_dump_func
| TODO_update_ssa_no_phi
| TODO_cleanup_cfg
| TODO_ggc_collect
| TODO_verify_ssa
| TODO_verify_flow, /* todo_flags_finish */
0 /* letter */
};

View File

@ -174,6 +174,8 @@ struct opt_stats_d
long num_stmts;
long num_exprs_considered;
long num_re;
long num_const_prop;
long num_copy_prop;
};
static struct opt_stats_d opt_stats;
@ -299,6 +301,7 @@ static edge single_incoming_edge_ignoring_loop_edges (basic_block);
static void restore_nonzero_vars_to_original_value (void);
static inline bool unsafe_associative_fp_binop (tree);
/* Local version of fold that doesn't introduce cruft. */
static tree
@ -403,6 +406,7 @@ tree_ssa_dominator_optimize (void)
structure. */
walk_data.global_data = NULL;
walk_data.block_local_data_size = 0;
walk_data.interesting_blocks = NULL;
/* Now initialize the dominator walker. */
init_walk_dominator_tree (&walk_data);
@ -442,11 +446,7 @@ tree_ssa_dominator_optimize (void)
interactions between rewriting of _DECL nodes into SSA form
and rewriting SSA_NAME nodes into SSA form after block
duplication and CFG manipulation. */
if (!bitmap_empty_p (vars_to_rename))
{
rewrite_into_ssa (false);
bitmap_clear (vars_to_rename);
}
update_ssa (TODO_update_ssa);
free_all_edge_infos ();
@ -572,7 +572,8 @@ struct tree_opt_pass pass_dominator =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_rename_vars
TODO_dump_func
| TODO_update_ssa
| TODO_verify_ssa, /* todo_flags_finish */
0 /* letter */
};
@ -1200,7 +1201,7 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb)
break;
VEC_pop (tree_on_heap, stmts_to_rescan);
mark_new_vars_to_rename (stmt, vars_to_rename);
mark_new_vars_to_rename (stmt);
}
}
@ -1386,6 +1387,10 @@ dump_dominator_optimization_stats (FILE *file)
fprintf (file, " Redundant expressions eliminated: %6ld (%.0f%%)\n",
opt_stats.num_re, PERCENT (opt_stats.num_re,
n_exprs));
fprintf (file, " Constants propagated: %6ld\n",
opt_stats.num_const_prop);
fprintf (file, " Copies propagated: %6ld\n",
opt_stats.num_copy_prop);
fprintf (file, "\nHash table statistics:\n");
@ -1600,7 +1605,7 @@ record_const_or_copy_1 (tree x, tree y, tree prev_x)
will be relatively correct, and as more passes are taught to keep loop info
up to date, the result will become more and more accurate. */
static int
int
loop_depth_of_name (tree x)
{
tree defstmt;
@ -2229,9 +2234,9 @@ simplify_cond_and_lookup_avail_expr (tree stmt,
Similarly the high value for the merged range is the
minimum of the previous high value and the high value of
this record. */
low = (tree_int_cst_compare (low, tmp_low) == 1
low = (low && tree_int_cst_compare (low, tmp_low) == 1
? low : tmp_low);
high = (tree_int_cst_compare (high, tmp_high) == -1
high = (high && tree_int_cst_compare (high, tmp_high) == -1
? high : tmp_high);
}
@ -2424,12 +2429,11 @@ cprop_into_successor_phis (basic_block bb, bitmap nonzero_vars)
ORIG_P with its value in our constant/copy table. */
new = SSA_NAME_VALUE (orig);
if (new
&& new != orig
&& (TREE_CODE (new) == SSA_NAME
|| is_gimple_min_invariant (new))
&& may_propagate_copy (orig, new))
{
propagate_value (orig_p, new);
}
propagate_value (orig_p, new);
}
}
}
@ -2624,7 +2628,6 @@ static void
propagate_to_outgoing_edges (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
basic_block bb)
{
record_edge_info (bb);
cprop_into_successor_phis (bb, nonzero_vars);
}
@ -2756,24 +2759,7 @@ record_equivalences_from_stmt (tree stmt,
|| is_gimple_min_invariant (rhs)))
SSA_NAME_VALUE (lhs) = rhs;
/* alloca never returns zero and the address of a non-weak symbol
is never zero. NOP_EXPRs and CONVERT_EXPRs can be completely
stripped as they do not affect this equivalence. */
while (TREE_CODE (rhs) == NOP_EXPR
|| TREE_CODE (rhs) == CONVERT_EXPR)
rhs = TREE_OPERAND (rhs, 0);
if (alloca_call_p (rhs)
|| (TREE_CODE (rhs) == ADDR_EXPR
&& DECL_P (TREE_OPERAND (rhs, 0))
&& ! DECL_WEAK (TREE_OPERAND (rhs, 0))))
record_var_is_nonzero (lhs);
/* IOR of any value with a nonzero value will result in a nonzero
value. Even if we do not know the exact result recording that
the result is nonzero is worth the effort. */
if (TREE_CODE (rhs) == BIT_IOR_EXPR
&& integer_nonzerop (TREE_OPERAND (rhs, 1)))
if (expr_computes_nonzero (rhs))
record_var_is_nonzero (lhs);
}
@ -2875,7 +2861,7 @@ cprop_operand (tree stmt, use_operand_p op_p)
copy of some other variable, use the value or copy stored in
CONST_AND_COPIES. */
val = SSA_NAME_VALUE (op);
if (val && TREE_CODE (val) != VALUE_HANDLE)
if (val && val != op && TREE_CODE (val) != VALUE_HANDLE)
{
tree op_type, val_type;
@ -2885,8 +2871,9 @@ cprop_operand (tree stmt, use_operand_p op_p)
statement. Also only allow the new value to be an SSA_NAME
for propagation into virtual operands. */
if (!is_gimple_reg (op)
&& (get_virtual_var (val) != get_virtual_var (op)
|| TREE_CODE (val) != SSA_NAME))
&& (TREE_CODE (val) != SSA_NAME
|| is_gimple_reg (val)
|| get_virtual_var (val) != get_virtual_var (op)))
return false;
/* Do not replace hard register operands in asm statements. */
@ -2952,6 +2939,11 @@ cprop_operand (tree stmt, use_operand_p op_p)
&& is_gimple_min_invariant (val)))
may_have_exposed_new_symbols = true;
if (TREE_CODE (val) != SSA_NAME)
opt_stats.num_const_prop++;
else
opt_stats.num_copy_prop++;
propagate_value (op_p, val);
/* And note that we modified this statement. This is now

View File

@ -251,6 +251,9 @@ dse_optimize_stmt (struct dom_walk_data *walk_data,
&& operand_equal_p (TREE_OPERAND (stmt, 0),
TREE_OPERAND (use_stmt, 0), 0))
{
tree def;
ssa_op_iter iter;
/* Make sure we propagate the ABNORMAL bit setting. */
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (USE_FROM_PTR (first_use_p)))
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (usevar) = 1;
@ -267,6 +270,12 @@ dse_optimize_stmt (struct dom_walk_data *walk_data,
/* Remove the dead store. */
bsi_remove (&bsi);
/* The virtual defs for the dead statement will need to be
updated. Since these names are going to disappear,
FUD chains for uses downstream need to be updated. */
FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_VIRTUAL_DEFS)
mark_sym_for_renaming (SSA_NAME_VAR (def));
/* And release any SSA_NAMEs set in this statement back to the
SSA_NAME manager. */
release_defs (stmt);
@ -347,6 +356,7 @@ tree_ssa_dse (void)
walk_data.after_dom_children_before_stmts = NULL;
walk_data.after_dom_children_walk_stmts = NULL;
walk_data.after_dom_children_after_stmts = dse_finalize_block;
walk_data.interesting_blocks = NULL;
walk_data.block_local_data_size = sizeof (struct dse_block_local_data);
@ -384,12 +394,15 @@ struct tree_opt_pass pass_dse = {
NULL, /* next */
0, /* static_pass_number */
TV_TREE_DSE, /* tv_id */
PROP_cfg | PROP_ssa
PROP_cfg
| PROP_ssa
| PROP_alias, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */
| TODO_verify_ssa,
0 /* letter */
TODO_dump_func
| TODO_ggc_collect
| TODO_update_ssa
| TODO_verify_ssa, /* todo_flags_finish */
0 /* letter */
};

View File

@ -237,10 +237,6 @@ copy_loop_headers (void)
free (bbs);
free (copied_bbs);
#ifdef ENABLE_CHECKING
verify_loop_closed_ssa ();
#endif
loop_optimizer_finalize (loops, NULL);
}

View File

@ -720,15 +720,14 @@ move_computations (void)
fini_walk_dominator_tree (&walk_data);
loop_commit_inserts ();
rewrite_into_ssa (false);
if (!bitmap_empty_p (vars_to_rename))
{
/* The rewrite of ssa names may cause violation of loop closed ssa
form invariants. TODO -- avoid these rewrites completely.
Information in virtual phi nodes is sufficient for it. */
rewrite_into_loop_closed_ssa (NULL);
}
bitmap_clear (vars_to_rename);
if (need_ssa_update_p ())
update_ssa (TODO_update_ssa);
/* The movement of LI code may cause violation of loop closed SSA
form invariants. TODO -- avoid these rewrites completely.
Information in virtual phi nodes is sufficient for it. */
rewrite_into_loop_closed_ssa (NULL);
}
/* Checks whether the statement defining variable *INDEX can be hoisted
@ -1096,10 +1095,7 @@ rewrite_mem_refs (tree tmp_var, struct mem_ref *mem_refs)
for (; mem_refs; mem_refs = mem_refs->next)
{
FOR_EACH_SSA_TREE_OPERAND (var, mem_refs->stmt, iter, SSA_OP_ALL_VIRTUALS)
{
var = SSA_NAME_VAR (var);
bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
}
mark_sym_for_renaming (SSA_NAME_VAR (var));
*mem_refs->ref = tmp_var;
update_stmt (mem_refs->stmt);

View File

@ -4810,7 +4810,7 @@ unshare_and_remove_ssa_names (tree ref)
static void
rewrite_address_base (block_stmt_iterator *bsi, tree *op, tree with)
{
tree bvar, var, new_var, new_name, copy, name;
tree bvar, var, new_name, copy, name;
tree orig;
var = bvar = get_base_address (*op);
@ -4832,24 +4832,27 @@ rewrite_address_base (block_stmt_iterator *bsi, tree *op, tree with)
else
goto do_rewrite;
if (var_ann (var)->type_mem_tag)
var = var_ann (var)->type_mem_tag;
/* We need to add a memory tag for the variable. But we do not want
to add it to the temporary used for the computations, since this leads
to problems in redundancy elimination when there are common parts
in two computations referring to the different arrays. So we copy
the variable to a new temporary. */
copy = build2 (MODIFY_EXPR, void_type_node, NULL_TREE, with);
if (name)
new_name = duplicate_ssa_name (name, copy);
else
{
new_var = create_tmp_var (TREE_TYPE (with), "ruatmp");
add_referenced_tmp_var (new_var);
var_ann (new_var)->type_mem_tag = var;
new_name = make_ssa_name (new_var, copy);
tree tag = var_ann (var)->type_mem_tag;
tree new_ptr = create_tmp_var (TREE_TYPE (with), "ruatmp");
add_referenced_tmp_var (new_ptr);
if (tag)
var_ann (new_ptr)->type_mem_tag = tag;
else
add_type_alias (new_ptr, var);
new_name = make_ssa_name (new_ptr, copy);
}
TREE_OPERAND (copy, 0) = new_name;
update_stmt (copy);
bsi_insert_before (bsi, copy, BSI_SAME_STMT);
@ -4870,6 +4873,10 @@ do_rewrite:
/* Record the original reference, for purposes of alias analysis. */
REF_ORIGINAL (*op) = orig;
/* Virtual operands in the original statement may have to be renamed
because of the replacement. */
mark_new_vars_to_rename (bsi_stmt (*bsi));
}
/* Rewrites USE (address that is an iv) using candidate CAND. */
@ -5377,11 +5384,6 @@ tree_ssa_iv_optimize (struct loops *loops)
while (loop->inner)
loop = loop->inner;
#ifdef ENABLE_CHECKING
verify_loop_closed_ssa ();
verify_stmts ();
#endif
/* Scan the loops, inner ones first. */
while (loop != loops->tree_root)
{
@ -5400,10 +5402,27 @@ tree_ssa_iv_optimize (struct loops *loops)
loop = loop->outer;
}
#ifdef ENABLE_CHECKING
verify_loop_closed_ssa ();
verify_stmts ();
#endif
/* FIXME. IV opts introduces new aliases and call-clobbered
variables, which need to be renamed. However, when we call the
renamer, not all statements will be scanned for operands. In
particular, the newly introduced aliases may appear in statements
that are considered "unmodified", so the renamer will not get a
chance to rename those operands.
Work around this problem by forcing an operand re-scan on every
statement. This will not be necessary once the new operand
scanner is implemented. */
if (need_ssa_update_p ())
{
basic_block bb;
block_stmt_iterator si;
FOR_EACH_BB (bb)
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
update_stmt (bsi_stmt (si));
update_ssa (TODO_update_ssa);
}
rewrite_into_loop_closed_ssa (NULL);
tree_ssa_iv_optimize_finalize (loops, &data);
}

View File

@ -157,7 +157,10 @@ add_exit_phis_var (tree var, bitmap livein, bitmap exits)
basic_block def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (var));
bitmap_iterator bi;
bitmap_clear_bit (livein, def_bb->index);
if (is_gimple_reg (var))
bitmap_clear_bit (livein, def_bb->index);
else
bitmap_set_bit (livein, def_bb->index);
def = BITMAP_ALLOC (NULL);
bitmap_set_bit (def, def_bb->index);

View File

@ -53,17 +53,8 @@ tree_loop_optimizer_init (FILE *dump)
if (!loops)
return NULL;
/* Creation of preheaders may create redundant phi nodes if the loop is
entered by more than one edge, but the initial value of the induction
variable is the same on all of them. */
kill_redundant_phi_nodes ();
rewrite_into_ssa (false);
bitmap_clear (vars_to_rename);
update_ssa (TODO_update_ssa);
rewrite_into_loop_closed_ssa (NULL);
#ifdef ENABLE_CHECKING
verify_loop_closed_ssa ();
#endif
return loops;
}
@ -121,7 +112,7 @@ struct tree_opt_pass pass_loop_init =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
TODO_dump_func | TODO_verify_loops, /* todo_flags_finish */
0 /* letter */
};
@ -155,7 +146,7 @@ struct tree_opt_pass pass_lim =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
TODO_dump_func | TODO_verify_loops, /* todo_flags_finish */
0 /* letter */
};
@ -189,7 +180,7 @@ struct tree_opt_pass pass_unswitch =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
TODO_dump_func | TODO_verify_loops, /* todo_flags_finish */
0 /* letter */
};
@ -201,7 +192,6 @@ tree_vectorize (void)
if (!current_loops)
return;
bitmap_clear (vars_to_rename);
vectorize_loops (current_loops);
}
@ -224,7 +214,7 @@ struct tree_opt_pass pass_vectorize =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
TODO_dump_func | TODO_update_ssa, /* todo_flags_finish */
0 /* letter */
};
@ -259,7 +249,7 @@ struct tree_opt_pass pass_linear_transform =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
TODO_dump_func | TODO_verify_loops, /* todo_flags_finish */
0 /* letter */
};
@ -293,7 +283,7 @@ struct tree_opt_pass pass_iv_canon =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
TODO_dump_func | TODO_verify_loops, /* todo_flags_finish */
0 /* letter */
};
@ -356,7 +346,7 @@ struct tree_opt_pass pass_complete_unroll =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
TODO_dump_func | TODO_verify_loops, /* todo_flags_finish */
0 /* letter */
};
@ -390,7 +380,7 @@ struct tree_opt_pass pass_iv_optimize =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
TODO_dump_func | TODO_verify_loops, /* todo_flags_finish */
0 /* letter */
};
@ -402,10 +392,6 @@ tree_ssa_loop_done (void)
if (!current_loops)
return;
#ifdef ENABLE_CHECKING
verify_loop_closed_ssa ();
#endif
free_numbers_of_iterations_estimates (current_loops);
scev_finalize ();
loop_optimizer_finalize (current_loops,
@ -429,4 +415,3 @@ struct tree_opt_pass pass_loop_done =
TODO_cleanup_cfg | TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};

View File

@ -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);

View File

@ -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 */
};

View File

@ -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"

View File

@ -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 */

View File

@ -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 */
};

View File

@ -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.

View File

@ -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: **/

View File

@ -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

View File

@ -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;

2265
gcc/tree-vrp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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;