lambda-code.c (lambda_loopnest_to_gcc_loopnest): Use update_stmt.
2005-04-05 Andrew MacLeod <amacleod@redhat.com> * lambda-code.c (lambda_loopnest_to_gcc_loopnest): Use update_stmt. Use immediate use iterator. (stmt_is_bumper_for_loop): Use immediate use iterator. * predict.c (strip_builtin_expect): Use update_stmt. * tree-cfg.c (update_modified_stmts): New. Call update_stmt_if_modified on all elements of a STATEMENT_LIST. (bsi_insert_before, bsi_insert_after): Call update_modified_stmts. (bsi_remove): Remove imm_use links and mark the stmt as modified. (bsi_replace): Mark stmt as modified and the update it. * tree-complex.c (update_complex_assignment): Call mark_stmt_modified. (expand_complex_libcal): Call update_stmt. (expand_complex_comparison): Call mark_stmt_modified. (expand_complex_operations_1): Call update_stmt_if_modified. (expand_vector_operations_1): Call mark_stmt_modified. * tree-dfa.c (compute_immediate_uses, free_df_for_stmt, free_df, compute_immediate_uses_for_phi, compute_immediate_uses_for_stmt, add_immediate_use, redirect_immediate_use, redirect_immediate_uses, dump_immediate_uses, debug_immediate_uses, dump_immediate_uses_for, debug_immediate_uses_for): Delete. (mark_new_vars_to_rename): Call update_stmt. * tree-dump.c (dump_option_value_in): Add "stmtaddr". * tree-flow-inline.h (modify_stmt): Rename to mark_stmt_modified. Ignore PHI nodes. (unmodify_stmt): Delete. (update_stmt): New. Force an update of a stmt. (update_stmt_if_modified): update a stmt if it is out of date. (get_stmt_operands): Verify stmt is NOT modified. (stmt_modified_p): Update comment. (delink_imm_use): Remove a use node from its immuse list. (link_imm_use_to_list): Link a use node to a specific list. (link_imm_use): Link a node to the correct list. (set_ssa_use_from_ptr): Set a use node to a specific value, and insert it in the correct list, if appropriate. (link_imm_use_stmt): Link a use node, and set the stmt pointer. (relink_imm_use): Link a use node in place of another node in a list. (relink_imm_use_stmt): LInk a node in place of another node, and set the stmt pointer. (end_safe_imm_use_traverse): New. Terminate a safe immuse iterator. (end_safe_imm_use_p): New. Check for the end of a safe immuse iterator. (first_safe_imm_use): New. Initialize a safe immuse iterator. (next_safe_imm_use): New. Proceed to next safe immuse iterator value. (end_readonly_imm_use_p): New. Check for end of a fast immuse iterator. (first_readonly_imm_use): New. Initialize a fast immuse iterator. (next_readonly_imm_use): New. Get the next fast immuse iterator value. (has_zero_uses): New. Return true if there are no uses of a var. (has_single_use): New. Return true if there is only a single use of a variable. (single_imm_use): New. Return the simgle immediate use. (num_imm_uses): New. Return the number of immediate uses. (get_v_must_def_ops): Use is now a pointer. (use_operand_p, get_v_may_def_op_ptr, get_vuse_op_ptr, get_v_must_def_kill_ptr, get_phi_arg_def_ptr): Return the address of the use node. (get_immediate_uses, num_immediate_uses, immediate_use): Delete. (delink_stmt_imm_use): Delink all immuses from a stmt. (phi_arg_index_from_use): New. Return a phi arg index for a use. * tree-flow.h (struct dataflow_d): Delete. (immediate_use_iterator_d): New. Immediate use iterator struct. (FOR_EACH_IMM_USE_FAST): New. Macro for read only immuse iteration. (FOR_EACH_IMM_USE_SAFE): New. Macro for write-safe immuse iteration. (BREAK_FROM_SAFE_IMM_USE): New. Macro for earlyu exit from write-safe iteration. (struct stmt_ann_d): Remove dataflow_t from struct. * tree-if-conv.c (tree_if_conversion). Don't call free_df. (if_convertible_phi_p): Use FAST immuse iterator. (if_convertible_loop_p): Don't call compute_immediate_uses. (replace_phi_with_cond_modify_expr): Call update_stmt. * tree-into-ssa.c (mark_def_sites, ssa_mark_def_sites): Call update_stmt_if_modified. (rewrite_all_into_ssa): Initialize ssa operands. * tree-loop-linear.c (linear_transform_loops): Don't call free_df or compute_immediate_uses. * tree-optimize.c (execute_todo): Call verify_ssa whenever the ssa_property is available. (execute_one_pass): Change parameters passed to execute_todo. * tree-outof-ssa.c (rewrite_trees): Don't call modify_stmt. (remove_ssa_form): Call fini_ssa_operands. (insert_backedge_copies): Delete call to modify_stmt. * tree-phinodes.c (make_phi_node): Initialize use nodes. (release_phi_node): Delink any use nodes before releasing. (resize_phi_node): Relink any use nodes. (remove_phi_arg_num): Delink the use node. (remove_phi_node): Release the ssa_name AFTER releasing the phi node. (remove_all_phi_nodes_for): Release phi node first. * tree-pretty-print.c (dump_generic_node): Print stmt address. * tree-sra.c (mark_all_v_defs): Call update_stmt_if_modified. (scalarize_use, scalarize_copy): Call update_stmt. * tree-ssa-alias.c (compute_may_aliases): Update all modified stmts. (compute_points_to_and_addr_escape): Call mark_stmt_modified. * tree-ssa-cpp.c (need_imm_uses_for): Delete. (ccp_initialize): Remove call to compute_immediate_uses. (substitute_and_fold, execute_fold_all_builtins): Call update_stmt. * tree-ssa-dom.c (tree_ssa_dominator_optimize): Update all modified stmts. (simplify_cond_and_lookup_avail_expr): Call mark_stmt_modified. (simplify_switch_and_lookup_avail_expr): Call mark_stmt_modified. (eliminate_redundant_computations): Call mark_stmt_modified. (cprop_operand): Call mark_stmt_modified. (optimize_stmt): Call update_stmt_if_modified and mark_stmt_modified. * tree-ssa-dse.c (fix_phi_uses, fix_stmt_v_may_defs): Delete. (dse_optimize_stmt): Use new immuse interface. (tree_ssa_dse): Remove calls to compute_immediate_uses and free_df. * tree-ssa-forwprop.c (need_imm_uses_for): Delete. (substitute_single_use_vars): Use new immuse interface. (tree_ssa_forward_propagate_single_use_vars): Remove calls to free_df and compute_immediate_uses. * tree-ssa-loop-im.c (single_reachable_address): Use new immuse interface. (rewrite_mem_refs): Call update_stmt. (determine_lsm): Remove call to compute_imm_uses and free_df. * tree-ssa-loop-ivcanon.c (create_canonical_iv): Call update_stmt. (try_unroll_loop_completely): Call update_stmt. * tree-ssa-loop-ivopts.c (rewrite_address_base): Call update_stmt. (rewrite_use_compare): Call update_stmt. (compute_phi_arg_on_exit): Insert each stmt before trying to process. (rewrite_use) : Call update_stmt. * tree-ssa-loop-manip.c (verify_loop_closed_ssa): Add arg to call. * tree-ssa-loop-unswitch.c (tree_unswitch_single_loop): Call update_stmt. * tree-ssa-operands.c (NULL_USE_OPERAND_P): Remove declaration. (allocate_use_optype, allocate_vuse_optype): Adjust allocation size. (free_uses, free_vuses, free_v_may_defs, free_v_must_defs): Delink use nodes. (initialize_vuse_operand): New. Initialize a vuse operand. (initialize_v_may_def_operand): New. Initialize a maydef operand. (initialize_v_must_def_operand): New. Initialize a mustdef operand. (finalize_ssa_defs): Use stmt parameter. (correct_use_link): Ensure a use node is in the correct list, and has the correct stmt pointer. (finalize_ssa_uses, finalize_ssa_v_may_defs, finalize_ssa_vuses, finalize_ssa_v_must_defs): Also initialize use nodes. (finalize_ssa_stmt_operands): Pass extra stmt operands. (build_ssa_operands): Seperate parsing from final operand construction. (parse_ssa_operands): New. Parse entry point for operand building. (swap_tree_operands): New. Swap 2 tree operands. (update_stmt_operands): Ranamed from get_stmt_operands. Always builds operands. (get_expr_operands): Call swap_tree_operands when needed. (copy_virtual_operands): Use initialize routines for virtual use ops. (create_ssa_artficial_load_stmt): Add extra stmt parameter. (verify_abort): New. Issue imm_use error. (verify_imm_links): New Verify imm_use links for a var. (dump_immediate_uses_for): New. Dump imm_uses for a var to file. (dump_immediate_uses): New. Dump imm_uses for all vars to file. (debug_immediate_uses): New. Dump imm_uses for all vars to stderr. (debug_immediate_uses_for): New. Dump imm_uses for a var to stderr. * tree-ssa-operands.h (struct use_operand_ptr): Delete. (NULL_USE_OPERAND_P) Define. (use_optype_d, v_def_use_operand_type, vuse_optype_d): Add immediate use node. (struct vuse_operand_type): New struct. (SET_USE): Call set_ssa_use_from_ptr. (USE_STMT): Define. (PHI_ARG_INDEX_FROM_USE): Define. * tree-ssa-phiopt.c (replace_phi_edge_with_variable): Set the phi argument via SET_USE, not PHI_ARG_DEF_TREE. * tree-ssa-pre.c (eliminate): Call update_stmt. * tree-ssa-propagate.c (cfg_blocks_get): Use imm_use iterators. Don't call free_df. * tree-ssa-sink.c (all_immediate_uses_same_place): Use imm_use iterator. (nearest_common_dominator_of_uses): Use imm_use iterator. (statement_sink_location): Use imm_use iterator and interface. (execute_sink_code): Don't call compute_immediate_uses or free-df. * tree-ssa-threadupdate.c (create_edge_and_update_destination_phis): Use PHI_ARG_DEF, not PHI_ARG_DEF_TREE. * tree-ssa.c (verify_use, verify_phi_args): Verify some imm_use info. (verify_ssa): Ensure no stmt is marked modify after optimization pass if new parameter is true. (init_tree_ssa): Don't initialize operand cache here. (delete_tree_ssa): Don't destroy operand cache here. (propagate_into_addr): Pass in a use pointer, return true if anything was changed. (replace_immediate_uses): Use imm_use iterator, call update_stmt. (check_phi_redundancy): Use imm_use iterator. (kill_redundant_phi_nodes): Don't call compute_immediate_uses or free_df. * tree-ssanames.c (make_ssa_name): Initialize imm_use node. (release_ssa_name): Delink node and all elements in its imm_use list. * tree-tailcall.c (adjust_return_value): Call update_stmt. * tree-vect-analyze.c (vect_stmt_relevant_p): Use imm_use iterator. * tree-vectorizer.c (need_imm_uses_for): Delete. (vectorize_loops): Dont call compute_immediate_uses or free_df. * tree.h (struct ssa_imm_use_d): Define. (SSA_NAME_IMM_USE_NODE): Define. (struct tree_ssa_name): Add imm_use node. (PHI_DF): Delete. (PHI_ARG_IMM_USE_NODE): Define. (struct phi_arg_d): Add imm_use node. (struct tree_phi_node): Remove struct dataflow_d element. (TDF_STMTADDR): Define. From-SVN: r97648
This commit is contained in:
parent
7701dad790
commit
f430bae872
40 changed files with 1607 additions and 979 deletions
193
gcc/ChangeLog
193
gcc/ChangeLog
|
@ -1,3 +1,196 @@
|
|||
2005-04-05 Andrew MacLeod <amacleod@redhat.com>
|
||||
|
||||
* lambda-code.c (lambda_loopnest_to_gcc_loopnest): Use update_stmt.
|
||||
Use immediate use iterator.
|
||||
(stmt_is_bumper_for_loop): Use immediate use iterator.
|
||||
* predict.c (strip_builtin_expect): Use update_stmt.
|
||||
* tree-cfg.c (update_modified_stmts): New. Call update_stmt_if_modified
|
||||
on all elements of a STATEMENT_LIST.
|
||||
(bsi_insert_before, bsi_insert_after): Call update_modified_stmts.
|
||||
(bsi_remove): Remove imm_use links and mark the stmt as modified.
|
||||
(bsi_replace): Mark stmt as modified and the update it.
|
||||
* tree-complex.c (update_complex_assignment): Call mark_stmt_modified.
|
||||
(expand_complex_libcal): Call update_stmt.
|
||||
(expand_complex_comparison): Call mark_stmt_modified.
|
||||
(expand_complex_operations_1): Call update_stmt_if_modified.
|
||||
(expand_vector_operations_1): Call mark_stmt_modified.
|
||||
* tree-dfa.c (compute_immediate_uses, free_df_for_stmt, free_df,
|
||||
compute_immediate_uses_for_phi, compute_immediate_uses_for_stmt,
|
||||
add_immediate_use, redirect_immediate_use,
|
||||
redirect_immediate_uses, dump_immediate_uses, debug_immediate_uses,
|
||||
dump_immediate_uses_for, debug_immediate_uses_for): Delete.
|
||||
(mark_new_vars_to_rename): Call update_stmt.
|
||||
* tree-dump.c (dump_option_value_in): Add "stmtaddr".
|
||||
* tree-flow-inline.h (modify_stmt): Rename to mark_stmt_modified.
|
||||
Ignore PHI nodes.
|
||||
(unmodify_stmt): Delete.
|
||||
(update_stmt): New. Force an update of a stmt.
|
||||
(update_stmt_if_modified): update a stmt if it is out of date.
|
||||
(get_stmt_operands): Verify stmt is NOT modified.
|
||||
(stmt_modified_p): Update comment.
|
||||
(delink_imm_use): Remove a use node from its immuse list.
|
||||
(link_imm_use_to_list): Link a use node to a specific list.
|
||||
(link_imm_use): Link a node to the correct list.
|
||||
(set_ssa_use_from_ptr): Set a use node to a specific value, and insert
|
||||
it in the correct list, if appropriate.
|
||||
(link_imm_use_stmt): Link a use node, and set the stmt pointer.
|
||||
(relink_imm_use): Link a use node in place of another node in a list.
|
||||
(relink_imm_use_stmt): LInk a node in place of another node, and set
|
||||
the stmt pointer.
|
||||
(end_safe_imm_use_traverse): New. Terminate a safe immuse iterator.
|
||||
(end_safe_imm_use_p): New. Check for the end of a safe immuse iterator.
|
||||
(first_safe_imm_use): New. Initialize a safe immuse iterator.
|
||||
(next_safe_imm_use): New. Proceed to next safe immuse iterator value.
|
||||
(end_readonly_imm_use_p): New. Check for end of a fast immuse iterator.
|
||||
(first_readonly_imm_use): New. Initialize a fast immuse iterator.
|
||||
(next_readonly_imm_use): New. Get the next fast immuse iterator value.
|
||||
(has_zero_uses): New. Return true if there are no uses of a var.
|
||||
(has_single_use): New. Return true if there is only a single use of a
|
||||
variable.
|
||||
(single_imm_use): New. Return the simgle immediate use.
|
||||
(num_imm_uses): New. Return the number of immediate uses.
|
||||
(get_v_must_def_ops): Use is now a pointer.
|
||||
(use_operand_p, get_v_may_def_op_ptr, get_vuse_op_ptr,
|
||||
get_v_must_def_kill_ptr, get_phi_arg_def_ptr): Return the address of
|
||||
the use node.
|
||||
(get_immediate_uses, num_immediate_uses, immediate_use): Delete.
|
||||
(delink_stmt_imm_use): Delink all immuses from a stmt.
|
||||
(phi_arg_index_from_use): New. Return a phi arg index for a use.
|
||||
* tree-flow.h (struct dataflow_d): Delete.
|
||||
(immediate_use_iterator_d): New. Immediate use iterator struct.
|
||||
(FOR_EACH_IMM_USE_FAST): New. Macro for read only immuse iteration.
|
||||
(FOR_EACH_IMM_USE_SAFE): New. Macro for write-safe immuse iteration.
|
||||
(BREAK_FROM_SAFE_IMM_USE): New. Macro for earlyu exit from write-safe
|
||||
iteration.
|
||||
(struct stmt_ann_d): Remove dataflow_t from struct.
|
||||
* tree-if-conv.c (tree_if_conversion). Don't call free_df.
|
||||
(if_convertible_phi_p): Use FAST immuse iterator.
|
||||
(if_convertible_loop_p): Don't call compute_immediate_uses.
|
||||
(replace_phi_with_cond_modify_expr): Call update_stmt.
|
||||
* tree-into-ssa.c (mark_def_sites, ssa_mark_def_sites): Call
|
||||
update_stmt_if_modified.
|
||||
(rewrite_all_into_ssa): Initialize ssa operands.
|
||||
* tree-loop-linear.c (linear_transform_loops): Don't call free_df or
|
||||
compute_immediate_uses.
|
||||
* tree-optimize.c (execute_todo): Call verify_ssa whenever the
|
||||
ssa_property is available.
|
||||
(execute_one_pass): Change parameters passed to execute_todo.
|
||||
* tree-outof-ssa.c (rewrite_trees): Don't call modify_stmt.
|
||||
(remove_ssa_form): Call fini_ssa_operands.
|
||||
(insert_backedge_copies): Delete call to modify_stmt.
|
||||
* tree-phinodes.c (make_phi_node): Initialize use nodes.
|
||||
(release_phi_node): Delink any use nodes before releasing.
|
||||
(resize_phi_node): Relink any use nodes.
|
||||
(remove_phi_arg_num): Delink the use node.
|
||||
(remove_phi_node): Release the ssa_name AFTER releasing the phi node.
|
||||
(remove_all_phi_nodes_for): Release phi node first.
|
||||
* tree-pretty-print.c (dump_generic_node): Print stmt address.
|
||||
* tree-sra.c (mark_all_v_defs): Call update_stmt_if_modified.
|
||||
(scalarize_use, scalarize_copy): Call update_stmt.
|
||||
* tree-ssa-alias.c (compute_may_aliases): Update all modified stmts.
|
||||
(compute_points_to_and_addr_escape): Call mark_stmt_modified.
|
||||
* tree-ssa-cpp.c (need_imm_uses_for): Delete.
|
||||
(ccp_initialize): Remove call to compute_immediate_uses.
|
||||
(substitute_and_fold, execute_fold_all_builtins): Call update_stmt.
|
||||
* tree-ssa-dom.c (tree_ssa_dominator_optimize): Update all modified
|
||||
stmts.
|
||||
(simplify_cond_and_lookup_avail_expr): Call mark_stmt_modified.
|
||||
(simplify_switch_and_lookup_avail_expr): Call mark_stmt_modified.
|
||||
(eliminate_redundant_computations): Call mark_stmt_modified.
|
||||
(cprop_operand): Call mark_stmt_modified.
|
||||
(optimize_stmt): Call update_stmt_if_modified and mark_stmt_modified.
|
||||
* tree-ssa-dse.c (fix_phi_uses, fix_stmt_v_may_defs): Delete.
|
||||
(dse_optimize_stmt): Use new immuse interface.
|
||||
(tree_ssa_dse): Remove calls to compute_immediate_uses and free_df.
|
||||
* tree-ssa-forwprop.c (need_imm_uses_for): Delete.
|
||||
(substitute_single_use_vars): Use new immuse interface.
|
||||
(tree_ssa_forward_propagate_single_use_vars): Remove calls to free_df
|
||||
and compute_immediate_uses.
|
||||
* tree-ssa-loop-im.c (single_reachable_address): Use new immuse
|
||||
interface.
|
||||
(rewrite_mem_refs): Call update_stmt.
|
||||
(determine_lsm): Remove call to compute_imm_uses and free_df.
|
||||
* tree-ssa-loop-ivcanon.c (create_canonical_iv): Call update_stmt.
|
||||
(try_unroll_loop_completely): Call update_stmt.
|
||||
* tree-ssa-loop-ivopts.c (rewrite_address_base): Call update_stmt.
|
||||
(rewrite_use_compare): Call update_stmt.
|
||||
(compute_phi_arg_on_exit): Insert each stmt before trying to process.
|
||||
(rewrite_use) : Call update_stmt.
|
||||
* tree-ssa-loop-manip.c (verify_loop_closed_ssa): Add arg to call.
|
||||
* tree-ssa-loop-unswitch.c (tree_unswitch_single_loop): Call
|
||||
update_stmt.
|
||||
* tree-ssa-operands.c (NULL_USE_OPERAND_P): Remove declaration.
|
||||
(allocate_use_optype, allocate_vuse_optype): Adjust allocation size.
|
||||
(free_uses, free_vuses, free_v_may_defs, free_v_must_defs): Delink
|
||||
use nodes.
|
||||
(initialize_vuse_operand): New. Initialize a vuse operand.
|
||||
(initialize_v_may_def_operand): New. Initialize a maydef operand.
|
||||
(initialize_v_must_def_operand): New. Initialize a mustdef operand.
|
||||
(finalize_ssa_defs): Use stmt parameter.
|
||||
(correct_use_link): Ensure a use node is in the correct list, and has
|
||||
the correct stmt pointer.
|
||||
(finalize_ssa_uses, finalize_ssa_v_may_defs, finalize_ssa_vuses,
|
||||
finalize_ssa_v_must_defs): Also initialize use nodes.
|
||||
(finalize_ssa_stmt_operands): Pass extra stmt operands.
|
||||
(build_ssa_operands): Seperate parsing from final operand construction.
|
||||
(parse_ssa_operands): New. Parse entry point for operand building.
|
||||
(swap_tree_operands): New. Swap 2 tree operands.
|
||||
(update_stmt_operands): Ranamed from get_stmt_operands. Always builds
|
||||
operands.
|
||||
(get_expr_operands): Call swap_tree_operands when needed.
|
||||
(copy_virtual_operands): Use initialize routines for virtual use ops.
|
||||
(create_ssa_artficial_load_stmt): Add extra stmt parameter.
|
||||
(verify_abort): New. Issue imm_use error.
|
||||
(verify_imm_links): New Verify imm_use links for a var.
|
||||
(dump_immediate_uses_for): New. Dump imm_uses for a var to file.
|
||||
(dump_immediate_uses): New. Dump imm_uses for all vars to file.
|
||||
(debug_immediate_uses): New. Dump imm_uses for all vars to stderr.
|
||||
(debug_immediate_uses_for): New. Dump imm_uses for a var to stderr.
|
||||
* tree-ssa-operands.h (struct use_operand_ptr): Delete.
|
||||
(NULL_USE_OPERAND_P) Define.
|
||||
(use_optype_d, v_def_use_operand_type, vuse_optype_d): Add immediate
|
||||
use node.
|
||||
(struct vuse_operand_type): New struct.
|
||||
(SET_USE): Call set_ssa_use_from_ptr.
|
||||
(USE_STMT): Define.
|
||||
(PHI_ARG_INDEX_FROM_USE): Define.
|
||||
* tree-ssa-phiopt.c (replace_phi_edge_with_variable): Set the phi
|
||||
argument via SET_USE, not PHI_ARG_DEF_TREE.
|
||||
* tree-ssa-pre.c (eliminate): Call update_stmt.
|
||||
* tree-ssa-propagate.c (cfg_blocks_get): Use imm_use iterators. Don't
|
||||
call free_df.
|
||||
* tree-ssa-sink.c (all_immediate_uses_same_place): Use imm_use iterator.
|
||||
(nearest_common_dominator_of_uses): Use imm_use iterator.
|
||||
(statement_sink_location): Use imm_use iterator and interface.
|
||||
(execute_sink_code): Don't call compute_immediate_uses or free-df.
|
||||
* tree-ssa-threadupdate.c (create_edge_and_update_destination_phis): Use
|
||||
PHI_ARG_DEF, not PHI_ARG_DEF_TREE.
|
||||
* tree-ssa.c (verify_use, verify_phi_args): Verify some imm_use info.
|
||||
(verify_ssa): Ensure no stmt is marked modify after optimization pass
|
||||
if new parameter is true.
|
||||
(init_tree_ssa): Don't initialize operand cache here.
|
||||
(delete_tree_ssa): Don't destroy operand cache here.
|
||||
(propagate_into_addr): Pass in a use pointer, return true if anything
|
||||
was changed.
|
||||
(replace_immediate_uses): Use imm_use iterator, call update_stmt.
|
||||
(check_phi_redundancy): Use imm_use iterator.
|
||||
(kill_redundant_phi_nodes): Don't call compute_immediate_uses or
|
||||
free_df.
|
||||
* tree-ssanames.c (make_ssa_name): Initialize imm_use node.
|
||||
(release_ssa_name): Delink node and all elements in its imm_use list.
|
||||
* tree-tailcall.c (adjust_return_value): Call update_stmt.
|
||||
* tree-vect-analyze.c (vect_stmt_relevant_p): Use imm_use iterator.
|
||||
* tree-vectorizer.c (need_imm_uses_for): Delete.
|
||||
(vectorize_loops): Dont call compute_immediate_uses or free_df.
|
||||
* tree.h (struct ssa_imm_use_d): Define.
|
||||
(SSA_NAME_IMM_USE_NODE): Define.
|
||||
(struct tree_ssa_name): Add imm_use node.
|
||||
(PHI_DF): Delete.
|
||||
(PHI_ARG_IMM_USE_NODE): Define.
|
||||
(struct phi_arg_d): Add imm_use node.
|
||||
(struct tree_phi_node): Remove struct dataflow_d element.
|
||||
(TDF_STMTADDR): Define.
|
||||
|
||||
2005-04-05 Dale Johannesen <dalej@apple.com>
|
||||
|
||||
* doc/invoke.texi (Optimization Options): Remove
|
||||
|
|
|
@ -1939,7 +1939,7 @@ lambda_loopnest_to_gcc_loopnest (struct loop *old_loopnest,
|
|||
COND_EXPR_COND (exitcond) = build (testtype,
|
||||
boolean_type_node,
|
||||
newupperbound, ivvarinced);
|
||||
modify_stmt (exitcond);
|
||||
update_stmt (exitcond);
|
||||
VEC_replace (tree, new_ivs, i, ivvar);
|
||||
|
||||
i++;
|
||||
|
@ -1951,11 +1951,21 @@ lambda_loopnest_to_gcc_loopnest (struct loop *old_loopnest,
|
|||
|
||||
for (i = 0; VEC_iterate (tree, old_ivs, i, oldiv); i++)
|
||||
{
|
||||
int j;
|
||||
dataflow_t imm = get_immediate_uses (SSA_NAME_DEF_STMT (oldiv));
|
||||
for (j = 0; j < num_immediate_uses (imm); j++)
|
||||
imm_use_iterator imm_iter;
|
||||
use_operand_p imm_use;
|
||||
tree oldiv_def;
|
||||
tree oldiv_stmt = SSA_NAME_DEF_STMT (oldiv);
|
||||
|
||||
gcc_assert (TREE_CODE (oldiv_stmt) == PHI_NODE
|
||||
|| NUM_DEFS (STMT_DEF_OPS (oldiv_stmt)) == 1);
|
||||
if (TREE_CODE (oldiv_stmt) == PHI_NODE)
|
||||
oldiv_def = PHI_RESULT (oldiv_stmt);
|
||||
else
|
||||
oldiv_def = DEF_OP (STMT_DEF_OPS (oldiv_stmt), 0);
|
||||
|
||||
FOR_EACH_IMM_USE_SAFE (imm_use, imm_iter, oldiv_def)
|
||||
{
|
||||
tree stmt = immediate_use (imm, j);
|
||||
tree stmt = USE_STMT (imm_use);
|
||||
use_operand_p use_p;
|
||||
ssa_op_iter iter;
|
||||
gcc_assert (TREE_CODE (stmt) != PHI_NODE);
|
||||
|
@ -1980,7 +1990,7 @@ lambda_loopnest_to_gcc_loopnest (struct loop *old_loopnest,
|
|||
expression. */
|
||||
bsi_insert_before (&bsi, stmts, BSI_SAME_STMT);
|
||||
propagate_value (use_p, newiv);
|
||||
modify_stmt (stmt);
|
||||
update_stmt (stmt);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2067,16 +2077,15 @@ stmt_is_bumper_for_loop (struct loop *loop, tree stmt)
|
|||
tree use;
|
||||
tree def;
|
||||
def_optype defs = STMT_DEF_OPS (stmt);
|
||||
dataflow_t imm;
|
||||
int i;
|
||||
imm_use_iterator iter;
|
||||
use_operand_p use_p;
|
||||
|
||||
if (NUM_DEFS (defs) != 1)
|
||||
return false;
|
||||
def = DEF_OP (defs, 0);
|
||||
imm = get_immediate_uses (stmt);
|
||||
for (i = 0; i < num_immediate_uses (imm); i++)
|
||||
FOR_EACH_IMM_USE_FAST (use_p, iter, def)
|
||||
{
|
||||
use = immediate_use (imm, i);
|
||||
use = USE_STMT (use_p);
|
||||
if (TREE_CODE (use) == PHI_NODE)
|
||||
{
|
||||
if (phi_loop_edge_uses_def (loop, use, def))
|
||||
|
|
|
@ -1013,7 +1013,7 @@ strip_builtin_expect (void)
|
|||
&& TREE_CHAIN (arglist))
|
||||
{
|
||||
TREE_OPERAND (stmt, 1) = TREE_VALUE (arglist);
|
||||
modify_stmt (stmt);
|
||||
update_stmt (stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3023,6 +3023,24 @@ bsi_for_stmt (tree stmt)
|
|||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Mark statement T as modified, and update it. */
|
||||
static inline void
|
||||
update_modified_stmts (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) == STATEMENT_LIST)
|
||||
{
|
||||
tree_stmt_iterator i;
|
||||
tree stmt;
|
||||
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
|
||||
{
|
||||
stmt = tsi_stmt (i);
|
||||
update_stmt_if_modified (stmt);
|
||||
}
|
||||
}
|
||||
else
|
||||
update_stmt_if_modified (t);
|
||||
}
|
||||
|
||||
/* Insert statement (or statement list) T before the statement
|
||||
pointed-to by iterator I. M specifies how to update iterator I
|
||||
after insertion (see enum bsi_iterator_update). */
|
||||
|
@ -3031,8 +3049,8 @@ void
|
|||
bsi_insert_before (block_stmt_iterator *i, tree t, enum bsi_iterator_update m)
|
||||
{
|
||||
set_bb_for_stmt (t, i->bb);
|
||||
update_modified_stmts (t);
|
||||
tsi_link_before (&i->tsi, t, m);
|
||||
modify_stmt (t);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3044,8 +3062,8 @@ void
|
|||
bsi_insert_after (block_stmt_iterator *i, tree t, enum bsi_iterator_update m)
|
||||
{
|
||||
set_bb_for_stmt (t, i->bb);
|
||||
update_modified_stmts (t);
|
||||
tsi_link_after (&i->tsi, t, m);
|
||||
modify_stmt (t);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3057,7 +3075,9 @@ bsi_remove (block_stmt_iterator *i)
|
|||
{
|
||||
tree t = bsi_stmt (*i);
|
||||
set_bb_for_stmt (t, NULL);
|
||||
delink_stmt_imm_use (t);
|
||||
tsi_delink (&i->tsi);
|
||||
mark_stmt_modified (t);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3121,7 +3141,8 @@ bsi_replace (const block_stmt_iterator *bsi, tree stmt, bool preserve_eh_info)
|
|||
}
|
||||
|
||||
*bsi_stmt_ptr (*bsi) = stmt;
|
||||
modify_stmt (stmt);
|
||||
mark_stmt_modified (stmt);
|
||||
update_modified_stmts (stmt);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ update_complex_assignment (block_stmt_iterator *bsi, tree r, tree i)
|
|||
|
||||
type = TREE_TYPE (TREE_OPERAND (stmt, 1));
|
||||
TREE_OPERAND (stmt, 1) = build (COMPLEX_EXPR, type, r, i);
|
||||
modify_stmt (stmt);
|
||||
mark_stmt_modified (stmt);
|
||||
}
|
||||
|
||||
/* Expand complex addition to scalars:
|
||||
|
@ -136,7 +136,7 @@ expand_complex_libcall (block_stmt_iterator *bsi, tree ar, tree ai,
|
|||
|
||||
TREE_OPERAND (stmt, 1)
|
||||
= build3 (CALL_EXPR, type, build_fold_addr_expr (fn), args, NULL);
|
||||
modify_stmt (stmt);
|
||||
update_stmt (stmt);
|
||||
}
|
||||
|
||||
/* Expand complex multiplication to scalars:
|
||||
|
@ -439,7 +439,7 @@ expand_complex_comparison (block_stmt_iterator *bsi, tree ar, tree ai,
|
|||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
modify_stmt (stmt);
|
||||
mark_stmt_modified (stmt);
|
||||
}
|
||||
|
||||
/* Process one statement. If we identify a complex operation, expand it. */
|
||||
|
@ -561,6 +561,7 @@ expand_complex_operations_1 (block_stmt_iterator *bsi)
|
|||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
update_stmt_if_modified (stmt);
|
||||
}
|
||||
|
||||
/* Build a constant of type TYPE, made of VALUE's bits replicated
|
||||
|
@ -931,7 +932,7 @@ expand_vector_operations_1 (block_stmt_iterator *bsi)
|
|||
*p_rhs = expand_vector_addition (bsi, do_binop, do_plus_minus, type,
|
||||
TREE_OPERAND (rhs, 0),
|
||||
TREE_OPERAND (rhs, 1), code);
|
||||
modify_stmt (bsi_stmt (*bsi));
|
||||
mark_stmt_modified (bsi_stmt (*bsi));
|
||||
return;
|
||||
|
||||
case NEGATE_EXPR:
|
||||
|
@ -941,7 +942,7 @@ expand_vector_operations_1 (block_stmt_iterator *bsi)
|
|||
*p_rhs = expand_vector_addition (bsi, do_unop, do_negate, type,
|
||||
TREE_OPERAND (rhs, 0),
|
||||
NULL_TREE, code);
|
||||
modify_stmt (bsi_stmt (*bsi));
|
||||
mark_stmt_modified (bsi_stmt (*bsi));
|
||||
return;
|
||||
|
||||
case BIT_AND_EXPR:
|
||||
|
@ -950,14 +951,14 @@ expand_vector_operations_1 (block_stmt_iterator *bsi)
|
|||
*p_rhs = expand_vector_parallel (bsi, do_binop, type,
|
||||
TREE_OPERAND (rhs, 0),
|
||||
TREE_OPERAND (rhs, 1), code);
|
||||
modify_stmt (bsi_stmt (*bsi));
|
||||
mark_stmt_modified (bsi_stmt (*bsi));
|
||||
return;
|
||||
|
||||
case BIT_NOT_EXPR:
|
||||
*p_rhs = expand_vector_parallel (bsi, do_unop, type,
|
||||
TREE_OPERAND (rhs, 0),
|
||||
NULL_TREE, code);
|
||||
modify_stmt (bsi_stmt (*bsi));
|
||||
mark_stmt_modified (bsi_stmt (*bsi));
|
||||
return;
|
||||
|
||||
default:
|
||||
|
@ -973,7 +974,7 @@ expand_vector_operations_1 (block_stmt_iterator *bsi)
|
|||
TREE_OPERAND (rhs, 0),
|
||||
TREE_OPERAND (rhs, 1), code);
|
||||
|
||||
modify_stmt (bsi_stmt (*bsi));
|
||||
mark_stmt_modified (bsi_stmt (*bsi));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
336
gcc/tree-dfa.c
336
gcc/tree-dfa.c
|
@ -77,11 +77,8 @@ struct walk_state
|
|||
/* Local functions. */
|
||||
static void collect_dfa_stats (struct dfa_stats_d *);
|
||||
static tree collect_dfa_stats_r (tree *, int *, void *);
|
||||
static void add_immediate_use (tree, tree);
|
||||
static tree find_vars_r (tree *, int *, void *);
|
||||
static void add_referenced_var (tree, struct walk_state *);
|
||||
static void compute_immediate_uses_for_phi (tree, bool (*)(tree));
|
||||
static void compute_immediate_uses_for_stmt (tree, int, bool (*)(tree));
|
||||
|
||||
|
||||
/* Global declarations. */
|
||||
|
@ -141,263 +138,6 @@ struct tree_opt_pass pass_referenced_vars =
|
|||
};
|
||||
|
||||
|
||||
/* Compute immediate uses.
|
||||
|
||||
CALC_FOR is an optional function pointer which indicates whether
|
||||
immediate uses information should be calculated for a given SSA
|
||||
variable. If NULL, then information is computed for all
|
||||
variables.
|
||||
|
||||
FLAGS is one of {TDFA_USE_OPS, TDFA_USE_VOPS}. It is used by
|
||||
compute_immediate_uses_for_stmt to determine whether to look at
|
||||
virtual and/or real operands while computing def-use chains. */
|
||||
|
||||
void
|
||||
compute_immediate_uses (int flags, bool (*calc_for)(tree))
|
||||
{
|
||||
basic_block bb;
|
||||
block_stmt_iterator si;
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
tree phi;
|
||||
|
||||
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
|
||||
{
|
||||
if (is_gimple_reg (PHI_RESULT (phi)))
|
||||
{
|
||||
if (!(flags & TDFA_USE_OPS))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(flags & TDFA_USE_VOPS))
|
||||
continue;
|
||||
}
|
||||
|
||||
compute_immediate_uses_for_phi (phi, calc_for);
|
||||
}
|
||||
|
||||
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
|
||||
{
|
||||
tree stmt = bsi_stmt (si);
|
||||
get_stmt_operands (stmt);
|
||||
compute_immediate_uses_for_stmt (stmt, flags, calc_for);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Invalidates dataflow information for a statement STMT. */
|
||||
|
||||
void
|
||||
free_df_for_stmt (tree stmt)
|
||||
{
|
||||
dataflow_t *df;
|
||||
|
||||
if (TREE_CODE (stmt) == PHI_NODE)
|
||||
df = &PHI_DF (stmt);
|
||||
else
|
||||
{
|
||||
stmt_ann_t ann = stmt_ann (stmt);
|
||||
|
||||
if (!ann)
|
||||
return;
|
||||
|
||||
df = &ann->df;
|
||||
}
|
||||
|
||||
if (!*df)
|
||||
return;
|
||||
|
||||
/* If we have a varray of immediate uses, then go ahead and release
|
||||
it for re-use. */
|
||||
if ((*df)->immediate_uses)
|
||||
ggc_free ((*df)->immediate_uses);
|
||||
|
||||
/* Similarly for the main dataflow structure. */
|
||||
ggc_free (*df);
|
||||
*df = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Invalidate dataflow information for the whole function.
|
||||
|
||||
Note this only invalidates dataflow information on statements and
|
||||
PHI nodes which are reachable.
|
||||
|
||||
A deleted statement may still have attached dataflow information
|
||||
on it. */
|
||||
|
||||
void
|
||||
free_df (void)
|
||||
{
|
||||
basic_block bb;
|
||||
block_stmt_iterator si;
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
tree phi;
|
||||
|
||||
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
|
||||
free_df_for_stmt (phi);
|
||||
|
||||
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
|
||||
{
|
||||
tree stmt = bsi_stmt (si);
|
||||
free_df_for_stmt (stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Helper for compute_immediate_uses. Check all the USE and/or VUSE
|
||||
operands in phi node PHI and add a def-use edge between their
|
||||
defining statement and PHI. CALC_FOR is as in
|
||||
compute_immediate_uses.
|
||||
|
||||
PHI nodes are easy, we only need to look at their arguments. */
|
||||
|
||||
static void
|
||||
compute_immediate_uses_for_phi (tree phi, bool (*calc_for)(tree))
|
||||
{
|
||||
int i;
|
||||
|
||||
gcc_assert (TREE_CODE (phi) == PHI_NODE);
|
||||
|
||||
for (i = 0; i < PHI_NUM_ARGS (phi); i++)
|
||||
{
|
||||
tree arg = PHI_ARG_DEF (phi, i);
|
||||
|
||||
if (TREE_CODE (arg) == SSA_NAME && (!calc_for || calc_for (arg)))
|
||||
{
|
||||
tree imm_rdef_stmt = SSA_NAME_DEF_STMT (PHI_ARG_DEF (phi, i));
|
||||
if (!IS_EMPTY_STMT (imm_rdef_stmt))
|
||||
add_immediate_use (imm_rdef_stmt, phi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Another helper for compute_immediate_uses. Depending on the value
|
||||
of FLAGS, check all the USE and/or VUSE operands in STMT and add a
|
||||
def-use edge between their defining statement and STMT. CALC_FOR
|
||||
is as in compute_immediate_uses. */
|
||||
|
||||
static void
|
||||
compute_immediate_uses_for_stmt (tree stmt, int flags, bool (*calc_for)(tree))
|
||||
{
|
||||
tree use;
|
||||
ssa_op_iter iter;
|
||||
|
||||
/* PHI nodes are handled elsewhere. */
|
||||
gcc_assert (TREE_CODE (stmt) != PHI_NODE);
|
||||
|
||||
/* Look at USE_OPS or VUSE_OPS according to FLAGS. */
|
||||
if (flags & TDFA_USE_OPS)
|
||||
{
|
||||
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
|
||||
{
|
||||
tree imm_stmt = SSA_NAME_DEF_STMT (use);
|
||||
if (!IS_EMPTY_STMT (imm_stmt) && (!calc_for || calc_for (use)))
|
||||
add_immediate_use (imm_stmt, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & TDFA_USE_VOPS)
|
||||
{
|
||||
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_VIRTUAL_USES)
|
||||
{
|
||||
tree imm_rdef_stmt = SSA_NAME_DEF_STMT (use);
|
||||
if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (use)))
|
||||
add_immediate_use (imm_rdef_stmt, stmt);
|
||||
}
|
||||
|
||||
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_KILLS)
|
||||
{
|
||||
tree imm_rdef_stmt = SSA_NAME_DEF_STMT (use);
|
||||
if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (use)))
|
||||
add_immediate_use (imm_rdef_stmt, stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Add statement USE_STMT to the list of statements that use definitions
|
||||
made by STMT. */
|
||||
|
||||
static void
|
||||
add_immediate_use (tree stmt, tree use_stmt)
|
||||
{
|
||||
struct dataflow_d **df;
|
||||
|
||||
if (TREE_CODE (stmt) == PHI_NODE)
|
||||
df = &PHI_DF (stmt);
|
||||
else
|
||||
{
|
||||
stmt_ann_t ann = get_stmt_ann (stmt);
|
||||
df = &ann->df;
|
||||
}
|
||||
|
||||
if (*df == NULL)
|
||||
{
|
||||
*df = ggc_alloc (sizeof (struct dataflow_d));
|
||||
memset ((void *) *df, 0, sizeof (struct dataflow_d));
|
||||
(*df)->uses[0] = use_stmt;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(*df)->uses[1])
|
||||
{
|
||||
(*df)->uses[1] = use_stmt;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*df)->immediate_uses == NULL)
|
||||
VARRAY_TREE_INIT ((*df)->immediate_uses, 4, "immediate_uses");
|
||||
|
||||
VARRAY_PUSH_TREE ((*df)->immediate_uses, use_stmt);
|
||||
}
|
||||
|
||||
|
||||
/* If the immediate use of USE points to OLD, then redirect it to NEW. */
|
||||
|
||||
static void
|
||||
redirect_immediate_use (tree use, tree old, tree new)
|
||||
{
|
||||
tree imm_stmt = SSA_NAME_DEF_STMT (use);
|
||||
struct dataflow_d *df = get_immediate_uses (imm_stmt);
|
||||
unsigned int num_uses = num_immediate_uses (df);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_uses; i++)
|
||||
{
|
||||
if (immediate_use (df, i) == old)
|
||||
{
|
||||
if (i == 0 || i == 1)
|
||||
df->uses[i] = new;
|
||||
else
|
||||
VARRAY_TREE (df->immediate_uses, i - 2) = new;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Redirect all immediate uses for operands in OLD so that they point
|
||||
to NEW. This routine should have no knowledge of how immediate
|
||||
uses are stored. */
|
||||
|
||||
void
|
||||
redirect_immediate_uses (tree old, tree new)
|
||||
{
|
||||
ssa_op_iter iter;
|
||||
tree val;
|
||||
|
||||
FOR_EACH_SSA_TREE_OPERAND (val, old, iter, SSA_OP_ALL_USES)
|
||||
redirect_immediate_use (val, old, new);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Manage annotations
|
||||
---------------------------------------------------------------------------*/
|
||||
|
@ -590,79 +330,6 @@ debug_variable (tree var)
|
|||
}
|
||||
|
||||
|
||||
/* Dump def-use edges on FILE. */
|
||||
|
||||
void
|
||||
dump_immediate_uses (FILE *file)
|
||||
{
|
||||
basic_block bb;
|
||||
block_stmt_iterator si;
|
||||
const char *funcname
|
||||
= lang_hooks.decl_printable_name (current_function_decl, 2);
|
||||
|
||||
fprintf (file, "\nDef-use edges for function %s\n", funcname);
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
tree phi;
|
||||
|
||||
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
|
||||
dump_immediate_uses_for (file, phi);
|
||||
|
||||
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
|
||||
dump_immediate_uses_for (file, bsi_stmt (si));
|
||||
}
|
||||
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
|
||||
|
||||
/* Dump def-use edges on stderr. */
|
||||
|
||||
void
|
||||
debug_immediate_uses (void)
|
||||
{
|
||||
dump_immediate_uses (stderr);
|
||||
}
|
||||
|
||||
|
||||
/* Dump all immediate uses for STMT on FILE. */
|
||||
|
||||
void
|
||||
dump_immediate_uses_for (FILE *file, tree stmt)
|
||||
{
|
||||
dataflow_t df = get_immediate_uses (stmt);
|
||||
int num_imm_uses = num_immediate_uses (df);
|
||||
|
||||
if (num_imm_uses > 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf (file, "-> ");
|
||||
print_generic_stmt (file, stmt, TDF_SLIM);
|
||||
fprintf (file, "\n");
|
||||
|
||||
for (i = 0; i < num_imm_uses; i++)
|
||||
{
|
||||
fprintf (file, "\t");
|
||||
print_generic_stmt (file, immediate_use (df, i), TDF_SLIM);
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Dump immediate uses for STMT on stderr. */
|
||||
|
||||
void
|
||||
debug_immediate_uses_for (tree stmt)
|
||||
{
|
||||
dump_immediate_uses_for (stderr, stmt);
|
||||
}
|
||||
|
||||
|
||||
/* Dump various DFA statistics to FILE. */
|
||||
|
||||
void
|
||||
|
@ -987,8 +654,7 @@ mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename)
|
|||
|
||||
/* Now force an operand re-scan on the statement and mark any newly
|
||||
exposed variables. */
|
||||
modify_stmt (stmt);
|
||||
get_stmt_operands (stmt);
|
||||
update_stmt (stmt);
|
||||
|
||||
v_may_defs_after = NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt));
|
||||
v_must_defs_after = NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt));
|
||||
|
|
|
@ -745,7 +745,9 @@ static const struct dump_option_value_info dump_options[] =
|
|||
{"vops", TDF_VOPS},
|
||||
{"lineno", TDF_LINENO},
|
||||
{"uid", TDF_UID},
|
||||
{"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA)},
|
||||
{"stmtaddr", TDF_STMTADDR},
|
||||
{"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA
|
||||
| TDF_STMTADDR)},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
|
|
|
@ -141,9 +141,13 @@ noreturn_call_p (tree t)
|
|||
|
||||
/* Mark statement T as modified. */
|
||||
static inline void
|
||||
modify_stmt (tree t)
|
||||
mark_stmt_modified (tree t)
|
||||
{
|
||||
stmt_ann_t ann = stmt_ann (t);
|
||||
stmt_ann_t ann;
|
||||
if (TREE_CODE (t) == PHI_NODE)
|
||||
return;
|
||||
|
||||
ann = stmt_ann (t);
|
||||
if (ann == NULL)
|
||||
ann = create_stmt_ann (t);
|
||||
else if (noreturn_call_p (t))
|
||||
|
@ -151,14 +155,42 @@ modify_stmt (tree t)
|
|||
ann->modified = 1;
|
||||
}
|
||||
|
||||
/* Mark statement T as unmodified. */
|
||||
/* Mark statement T as modified, and update it. */
|
||||
static inline void
|
||||
unmodify_stmt (tree t)
|
||||
update_stmt (tree t)
|
||||
{
|
||||
stmt_ann_t ann = stmt_ann (t);
|
||||
if (ann == NULL)
|
||||
ann = create_stmt_ann (t);
|
||||
ann->modified = 0;
|
||||
if (TREE_CODE (t) == PHI_NODE)
|
||||
return;
|
||||
mark_stmt_modified (t);
|
||||
update_stmt_operands (t);
|
||||
}
|
||||
|
||||
static inline void
|
||||
update_stmt_if_modified (tree t)
|
||||
{
|
||||
if (stmt_modified_p (t))
|
||||
update_stmt_operands (t);
|
||||
}
|
||||
|
||||
static inline void
|
||||
get_stmt_operands (tree stmt ATTRIBUTE_UNUSED)
|
||||
{
|
||||
#ifdef ENABLE_CHECKING
|
||||
stmt_ann_t ann;
|
||||
|
||||
/* The optimizers cannot handle statements that are nothing but a
|
||||
_DECL. This indicates a bug in the gimplifier. */
|
||||
gcc_assert (!SSA_VAR_P (stmt));
|
||||
|
||||
/* Ignore error statements. */
|
||||
if (TREE_CODE (stmt) == ERROR_MARK)
|
||||
return;
|
||||
|
||||
ann = get_stmt_ann (stmt);
|
||||
gcc_assert (!ann->modified);
|
||||
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return true if T is marked as modified, false otherwise. */
|
||||
|
@ -168,11 +200,286 @@ stmt_modified_p (tree t)
|
|||
stmt_ann_t ann = stmt_ann (t);
|
||||
|
||||
/* Note that if the statement doesn't yet have an annotation, we consider it
|
||||
modified. This will force the next call to get_stmt_operands to scan the
|
||||
statement. */
|
||||
modified. This will force the next call to update_stmt_operands to scan
|
||||
the statement. */
|
||||
return ann ? ann->modified : true;
|
||||
}
|
||||
|
||||
/* Delink an immediate_uses node from its chain. */
|
||||
static inline void
|
||||
delink_imm_use (ssa_imm_use_t *linknode)
|
||||
{
|
||||
/* Return if this node is not in a list. */
|
||||
if (linknode->prev == NULL)
|
||||
return;
|
||||
|
||||
linknode->prev->next = linknode->next;
|
||||
linknode->next->prev = linknode->prev;
|
||||
linknode->prev = NULL;
|
||||
linknode->next = NULL;
|
||||
}
|
||||
|
||||
/* Link ssa_imm_use node LINKNODE into the chain for LIST. */
|
||||
static inline void
|
||||
link_imm_use_to_list (ssa_imm_use_t *linknode, ssa_imm_use_t *list)
|
||||
{
|
||||
/* Link the new node at the head of the list. If we are in the process of
|
||||
traversing the list, we wont visit any new nodes added to it. */
|
||||
linknode->prev = list;
|
||||
linknode->next = list->next;
|
||||
list->next->prev = linknode;
|
||||
list->next = linknode;
|
||||
}
|
||||
|
||||
/* Link ssa_imm_use node LINKNODE into the chain for DEF. */
|
||||
static inline void
|
||||
link_imm_use (ssa_imm_use_t *linknode, tree def)
|
||||
{
|
||||
ssa_imm_use_t *root;
|
||||
|
||||
if (!def || TREE_CODE (def) != SSA_NAME)
|
||||
linknode->prev = NULL;
|
||||
else
|
||||
{
|
||||
root = &(SSA_NAME_IMM_USE_NODE (def));
|
||||
#ifdef ENABLE_CHECKING
|
||||
if (linknode->use)
|
||||
gcc_assert (*(linknode->use) == def);
|
||||
#endif
|
||||
link_imm_use_to_list (linknode, root);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the value of a use pointed by USE to VAL. */
|
||||
static inline void
|
||||
set_ssa_use_from_ptr (use_operand_p use, tree val)
|
||||
{
|
||||
delink_imm_use (use);
|
||||
*(use->use) = val;
|
||||
link_imm_use (use, val);
|
||||
}
|
||||
|
||||
/* Link ssa_imm_use node LINKNODE into the chain for DEF, with use occuring
|
||||
in STMT. */
|
||||
static inline void
|
||||
link_imm_use_stmt (ssa_imm_use_t *linknode, tree def, tree stmt)
|
||||
{
|
||||
if (stmt)
|
||||
link_imm_use (linknode, def);
|
||||
else
|
||||
link_imm_use (linknode, NULL);
|
||||
linknode->stmt = stmt;
|
||||
}
|
||||
|
||||
/* Relink a new node in place of an old node in the list. */
|
||||
static inline void
|
||||
relink_imm_use (ssa_imm_use_t *node, ssa_imm_use_t *old)
|
||||
{
|
||||
#ifdef ENABLE_CHECKING
|
||||
/* The node one had better be in the same list. */
|
||||
if (*(old->use) != *(node->use))
|
||||
abort ();
|
||||
#endif
|
||||
node->prev = old->prev;
|
||||
node->next = old->next;
|
||||
if (old->prev)
|
||||
{
|
||||
old->prev->next = node;
|
||||
old->next->prev = node;
|
||||
/* Remove the old node from the list. */
|
||||
old->prev = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Relink ssa_imm_use node LINKNODE into the chain for OLD, with use occuring
|
||||
in STMT. */
|
||||
static inline void
|
||||
relink_imm_use_stmt (ssa_imm_use_t *linknode, ssa_imm_use_t *old, tree stmt)
|
||||
{
|
||||
if (stmt)
|
||||
relink_imm_use (linknode, old);
|
||||
else
|
||||
link_imm_use (linknode, NULL);
|
||||
linknode->stmt = stmt;
|
||||
}
|
||||
|
||||
/* Finished the traverse of an immediate use list IMM by removing it from
|
||||
the list. */
|
||||
static inline void
|
||||
end_safe_imm_use_traverse (imm_use_iterator *imm)
|
||||
{
|
||||
delink_imm_use (&(imm->iter_node));
|
||||
}
|
||||
|
||||
/* Return true if IMM is at the end of the list. */
|
||||
static inline bool
|
||||
end_safe_imm_use_p (imm_use_iterator *imm)
|
||||
{
|
||||
return (imm->imm_use == imm->end_p);
|
||||
}
|
||||
|
||||
/* Initialize iterator IMM to process the list for VAR. */
|
||||
static inline use_operand_p
|
||||
first_safe_imm_use (imm_use_iterator *imm, tree var)
|
||||
{
|
||||
/* Set up and link the iterator node into the linked list for VAR. */
|
||||
imm->iter_node.use = NULL;
|
||||
imm->iter_node.stmt = NULL_TREE;
|
||||
imm->end_p = &(SSA_NAME_IMM_USE_NODE (var));
|
||||
/* Check if there are 0 elements. */
|
||||
if (imm->end_p->next == imm->end_p)
|
||||
{
|
||||
imm->imm_use = imm->end_p;
|
||||
return NULL_USE_OPERAND_P;
|
||||
}
|
||||
|
||||
link_imm_use (&(imm->iter_node), var);
|
||||
imm->imm_use = imm->iter_node.next;
|
||||
return imm->imm_use;
|
||||
}
|
||||
|
||||
/* Bump IMM to then next use in the list. */
|
||||
static inline use_operand_p
|
||||
next_safe_imm_use (imm_use_iterator *imm)
|
||||
{
|
||||
ssa_imm_use_t *ptr;
|
||||
use_operand_p old;
|
||||
|
||||
old = imm->imm_use;
|
||||
/* If the next node following the iter_node is still the one refered to by
|
||||
imm_use, then the list hasnt changed, go to the next node. */
|
||||
if (imm->iter_node.next == imm->imm_use)
|
||||
{
|
||||
ptr = &(imm->iter_node);
|
||||
/* Remove iternode fromn the list. */
|
||||
delink_imm_use (ptr);
|
||||
imm->imm_use = imm->imm_use->next;
|
||||
if (! end_safe_imm_use_p (imm))
|
||||
{
|
||||
/* This isnt the end, link iternode before the next use. */
|
||||
ptr->prev = imm->imm_use->prev;
|
||||
ptr->next = imm->imm_use;
|
||||
imm->imm_use->prev->next = ptr;
|
||||
imm->imm_use->prev = ptr;
|
||||
}
|
||||
else
|
||||
return old;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the 'next' value after the iterator isn't the same as it was, then
|
||||
a node has been deleted, so we sinply proceed to the node following
|
||||
where the iterator is in the list. */
|
||||
imm->imm_use = imm->iter_node.next;
|
||||
if (end_safe_imm_use_p (imm))
|
||||
{
|
||||
end_safe_imm_use_traverse (imm);
|
||||
return old;
|
||||
}
|
||||
}
|
||||
|
||||
return imm->imm_use;
|
||||
}
|
||||
|
||||
/* Return true is IMM has reached the end of the immeidate use list. */
|
||||
static inline bool
|
||||
end_readonly_imm_use_p (imm_use_iterator *imm)
|
||||
{
|
||||
return (imm->imm_use == imm->end_p);
|
||||
}
|
||||
|
||||
/* Initialize iterator IMM to process the list for VAR. */
|
||||
static inline use_operand_p
|
||||
first_readonly_imm_use (imm_use_iterator *imm, tree var)
|
||||
{
|
||||
gcc_assert (TREE_CODE (var) == SSA_NAME);
|
||||
|
||||
imm->end_p = &(SSA_NAME_IMM_USE_NODE (var));
|
||||
imm->imm_use = imm->end_p->next;
|
||||
#ifdef ENABLE_CHECKING
|
||||
imm->iter_node.next = imm->imm_use->next;
|
||||
#endif
|
||||
if (end_readonly_imm_use_p (imm))
|
||||
return NULL_USE_OPERAND_P;
|
||||
return imm->imm_use;
|
||||
}
|
||||
|
||||
/* Bump IMM to then next use in the list. */
|
||||
static inline use_operand_p
|
||||
next_readonly_imm_use (imm_use_iterator *imm)
|
||||
{
|
||||
use_operand_p old = imm->imm_use;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
/* If this assertion fails, it indicates the 'next' pointer has changed
|
||||
since we the last bump. This indicates that the list is being modified
|
||||
via stmt changes, or SET_USE, or somesuch thing, and you need to be
|
||||
using the SAFE version of the iterator. */
|
||||
gcc_assert (imm->iter_node.next == old->next);
|
||||
imm->iter_node.next = old->next->next;
|
||||
#endif
|
||||
|
||||
imm->imm_use = old->next;
|
||||
if (end_readonly_imm_use_p (imm))
|
||||
return old;
|
||||
return imm->imm_use;
|
||||
}
|
||||
|
||||
/* Return true if VAR has no uses. */
|
||||
static inline bool
|
||||
has_zero_uses (tree var)
|
||||
{
|
||||
ssa_imm_use_t *ptr;
|
||||
ptr = &(SSA_NAME_IMM_USE_NODE (var));
|
||||
/* A single use means there is no items in the list. */
|
||||
return (ptr == ptr->next);
|
||||
}
|
||||
|
||||
/* Return true if VAR has a single use. */
|
||||
static inline bool
|
||||
has_single_use (tree var)
|
||||
{
|
||||
ssa_imm_use_t *ptr;
|
||||
ptr = &(SSA_NAME_IMM_USE_NODE (var));
|
||||
/* A single use means there is one item in the list. */
|
||||
return (ptr != ptr->next && ptr == ptr->next->next);
|
||||
}
|
||||
|
||||
/* If VAR has only a single immediate use, return true, and set USE_P and STMT
|
||||
to the use pointer and stmt of occurence. */
|
||||
static inline bool
|
||||
single_imm_use (tree var, use_operand_p *use_p, tree *stmt)
|
||||
{
|
||||
ssa_imm_use_t *ptr;
|
||||
|
||||
ptr = &(SSA_NAME_IMM_USE_NODE (var));
|
||||
if (ptr != ptr->next && ptr == ptr->next->next)
|
||||
{
|
||||
*use_p = ptr->next;
|
||||
*stmt = ptr->next->stmt;
|
||||
return true;
|
||||
}
|
||||
*use_p = NULL_USE_OPERAND_P;
|
||||
*stmt = NULL_TREE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return the number of immediate uses of VAR. */
|
||||
static inline unsigned int
|
||||
num_imm_uses (tree var)
|
||||
{
|
||||
ssa_imm_use_t *ptr, *start;
|
||||
unsigned int num;
|
||||
|
||||
start = &(SSA_NAME_IMM_USE_NODE (var));
|
||||
num = 0;
|
||||
for (ptr = start->next; ptr != start; ptr = ptr->next)
|
||||
num++;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Return the definitions present in ANN, a statement annotation.
|
||||
Return NULL if this annotation contains no definitions. */
|
||||
static inline def_optype
|
||||
|
@ -218,7 +525,7 @@ get_v_must_def_ops (stmt_ann_t ann)
|
|||
static inline tree
|
||||
get_use_from_ptr (use_operand_p use)
|
||||
{
|
||||
return *(use.use);
|
||||
return *(use->use);
|
||||
}
|
||||
|
||||
/* Return the tree pointer to by DEF. */
|
||||
|
@ -233,7 +540,7 @@ static inline use_operand_p
|
|||
get_use_op_ptr (use_optype uses, unsigned int index)
|
||||
{
|
||||
gcc_assert (index < uses->num_uses);
|
||||
return uses->uses[index];
|
||||
return &(uses->uses[index]);
|
||||
}
|
||||
|
||||
/* Return a def_operand_p pointer for element INDEX of DEFS. */
|
||||
|
@ -244,7 +551,6 @@ get_def_op_ptr (def_optype defs, unsigned int index)
|
|||
return defs->defs[index];
|
||||
}
|
||||
|
||||
|
||||
/* Return the def_operand_p that is the V_MAY_DEF_RESULT for the V_MAY_DEF
|
||||
at INDEX in the V_MAY_DEFS array. */
|
||||
static inline def_operand_p
|
||||
|
@ -261,20 +567,16 @@ get_v_may_def_result_ptr(v_may_def_optype v_may_defs, unsigned int index)
|
|||
static inline use_operand_p
|
||||
get_v_may_def_op_ptr(v_may_def_optype v_may_defs, unsigned int index)
|
||||
{
|
||||
use_operand_p op;
|
||||
gcc_assert (index < v_may_defs->num_v_may_defs);
|
||||
op.use = &(v_may_defs->v_may_defs[index].use);
|
||||
return op;
|
||||
return &(v_may_defs->v_may_defs[index].imm_use);
|
||||
}
|
||||
|
||||
/* Return a use_operand_p that is at INDEX in the VUSES array. */
|
||||
static inline use_operand_p
|
||||
get_vuse_op_ptr(vuse_optype vuses, unsigned int index)
|
||||
{
|
||||
use_operand_p op;
|
||||
gcc_assert (index < vuses->num_vuses);
|
||||
op.use = &(vuses->vuses[index]);
|
||||
return op;
|
||||
return &(vuses->vuses[index].imm_use);
|
||||
}
|
||||
|
||||
/* Return a def_operand_p that is the V_MUST_DEF_RESULT for the
|
||||
|
@ -293,10 +595,8 @@ get_v_must_def_result_ptr (v_must_def_optype v_must_defs, unsigned int index)
|
|||
static inline use_operand_p
|
||||
get_v_must_def_kill_ptr (v_must_def_optype v_must_defs, unsigned int index)
|
||||
{
|
||||
use_operand_p op;
|
||||
gcc_assert (index < v_must_defs->num_v_must_defs);
|
||||
op.use = &(v_must_defs->v_must_defs[index].use);
|
||||
return op;
|
||||
return &(v_must_defs->v_must_defs[index].imm_use);
|
||||
}
|
||||
|
||||
/* Return a def_operand_p pointer for the result of PHI. */
|
||||
|
@ -312,11 +612,33 @@ get_phi_result_ptr (tree phi)
|
|||
static inline use_operand_p
|
||||
get_phi_arg_def_ptr (tree phi, int i)
|
||||
{
|
||||
use_operand_p op;
|
||||
op.use = &(PHI_ARG_DEF_TREE (phi, i));
|
||||
return op;
|
||||
return &(PHI_ARG_IMM_USE_NODE (phi,i));
|
||||
}
|
||||
|
||||
|
||||
/* Delink all immediate_use information for STMT. */
|
||||
static inline void
|
||||
delink_stmt_imm_use (tree stmt)
|
||||
{
|
||||
unsigned int x;
|
||||
use_optype uses = STMT_USE_OPS (stmt);
|
||||
vuse_optype vuses = STMT_VUSE_OPS (stmt);
|
||||
v_may_def_optype v_may_defs = STMT_V_MAY_DEF_OPS (stmt);
|
||||
v_must_def_optype v_must_defs = STMT_V_MUST_DEF_OPS (stmt);
|
||||
|
||||
for (x = 0; x < NUM_USES (uses); x++)
|
||||
delink_imm_use (&(uses->uses[x]));
|
||||
|
||||
for (x = 0; x < NUM_VUSES (vuses); x++)
|
||||
delink_imm_use (&(vuses->vuses[x].imm_use));
|
||||
|
||||
for (x = 0; x < NUM_V_MAY_DEFS (v_may_defs); x++)
|
||||
delink_imm_use (&(v_may_defs->v_may_defs[x].imm_use));
|
||||
|
||||
for (x = 0; x < NUM_V_MUST_DEFS (v_must_defs); x++)
|
||||
delink_imm_use (&(v_must_defs->v_must_defs[x].imm_use));
|
||||
}
|
||||
|
||||
|
||||
/* Return the bitmap of addresses taken by STMT, or NULL if it takes
|
||||
no addresses. */
|
||||
static inline bitmap
|
||||
|
@ -326,52 +648,6 @@ addresses_taken (tree stmt)
|
|||
return ann ? ann->addresses_taken : NULL;
|
||||
}
|
||||
|
||||
/* Return the immediate uses of STMT, or NULL if this information is
|
||||
not computed. */
|
||||
static dataflow_t
|
||||
get_immediate_uses (tree stmt)
|
||||
{
|
||||
stmt_ann_t ann;
|
||||
|
||||
if (TREE_CODE (stmt) == PHI_NODE)
|
||||
return PHI_DF (stmt);
|
||||
|
||||
ann = stmt_ann (stmt);
|
||||
return ann ? ann->df : NULL;
|
||||
}
|
||||
|
||||
/* Return the number of immediate uses present in the dataflow
|
||||
information at DF. */
|
||||
static inline int
|
||||
num_immediate_uses (dataflow_t df)
|
||||
{
|
||||
varray_type imm;
|
||||
|
||||
if (!df)
|
||||
return 0;
|
||||
|
||||
imm = df->immediate_uses;
|
||||
if (!imm)
|
||||
return df->uses[1] ? 2 : 1;
|
||||
|
||||
return VARRAY_ACTIVE_SIZE (imm) + 2;
|
||||
}
|
||||
|
||||
/* Return the tree that is at NUM in the immediate use DF array. */
|
||||
static inline tree
|
||||
immediate_use (dataflow_t df, int num)
|
||||
{
|
||||
if (!df)
|
||||
return NULL_TREE;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (num < num_immediate_uses (df));
|
||||
#endif
|
||||
if (num < 2)
|
||||
return df->uses[num];
|
||||
return VARRAY_TREE (df->immediate_uses, num - 2);
|
||||
}
|
||||
|
||||
/* Return the basic_block annotation for BB. */
|
||||
static inline bb_ann_t
|
||||
bb_ann (basic_block bb)
|
||||
|
@ -399,6 +675,37 @@ set_phi_nodes (basic_block bb, tree l)
|
|||
set_bb_for_stmt (phi, bb);
|
||||
}
|
||||
|
||||
/* Return the phi argument which contains the specified use. */
|
||||
|
||||
static inline int
|
||||
phi_arg_index_from_use (use_operand_p use)
|
||||
{
|
||||
struct phi_arg_d *element, *root;
|
||||
int index;
|
||||
tree phi;
|
||||
|
||||
/* Since the use is the first thing in a PHI arguemnt element, we can
|
||||
calculate its index based on casting it to an argument, and performing
|
||||
pointer arithmetic. */
|
||||
|
||||
phi = USE_STMT (use);
|
||||
gcc_assert (TREE_CODE (phi) == PHI_NODE);
|
||||
|
||||
element = (struct phi_arg_d *)use;
|
||||
root = &(PHI_ARG_ELT (phi, 0));
|
||||
index = element - root;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
/* Make sure the calculation doesn't have any leftover bytes. If it does,
|
||||
then imm_use is liekly not the first element in phi_arg_d. */
|
||||
gcc_assert (
|
||||
(((char *)element - (char *)root) % sizeof (struct phi_arg_d)) == 0);
|
||||
gcc_assert (index >= 0 && index < PHI_ARG_CAPACITY (phi));
|
||||
#endif
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* Mark VAR as used, so that it'll be preserved during rtl expansion. */
|
||||
|
||||
static inline void
|
||||
|
|
|
@ -235,43 +235,33 @@ struct var_ann_d GTY(())
|
|||
};
|
||||
|
||||
|
||||
struct dataflow_d GTY(())
|
||||
typedef struct immediate_use_iterator_d
|
||||
{
|
||||
/* Immediate uses. This is a list of all the statements and PHI nodes
|
||||
that are immediately reached by the definitions made in this
|
||||
statement. */
|
||||
varray_type immediate_uses;
|
||||
ssa_imm_use_t *imm_use;
|
||||
ssa_imm_use_t *end_p;
|
||||
ssa_imm_use_t iter_node;
|
||||
} imm_use_iterator;
|
||||
|
||||
/* Use this array for very small numbers of uses instead of the varray. */
|
||||
tree uses[2];
|
||||
|
||||
/* Reached uses. This is a list of all the possible program statements
|
||||
that may be reached directly or indirectly by definitions made in this
|
||||
statement. Notice that this is a superset of IMMEDIATE_USES.
|
||||
For instance, given the following piece of code:
|
||||
/* Use this iterator when simply looking at stmts. Adding, deleteing or
|
||||
modifying stmts will cause this iterator to malfunction. */
|
||||
|
||||
1 a1 = 10;
|
||||
2 if (a1 > 3)
|
||||
3 a2 = a1 + 5;
|
||||
4 a3 = PHI (a1, a2)
|
||||
5 b1 = a3 - 2;
|
||||
#define FOR_EACH_IMM_USE_FAST(DEST, ITER, SSAVAR) \
|
||||
for ((DEST) = first_readonly_imm_use (&(ITER), (SSAVAR)); \
|
||||
!end_readonly_imm_use_p (&(ITER)); \
|
||||
(DEST) = next_readonly_imm_use (&(ITER)))
|
||||
|
||||
|
||||
IMMEDIATE_USES for statement #1 are all those statements that use a1
|
||||
directly (i.e., #2, #3 and #4). REACHED_USES for statement #1 also
|
||||
includes statement #5 because 'a1' could reach 'a3' via the PHI node
|
||||
at statement #4. The set of REACHED_USES is then the transitive
|
||||
closure over all the PHI nodes in the IMMEDIATE_USES set. */
|
||||
|
||||
/* Reaching definitions. Similarly to REACHED_USES, the set
|
||||
REACHING_DEFS is the set of all the statements that make definitions
|
||||
that may reach this statement. Notice that we don't need to have a
|
||||
similar entry for immediate definitions, as these are represented by
|
||||
the SSA_NAME nodes themselves (each SSA_NAME node contains a pointer
|
||||
to the statement that makes that definition). */
|
||||
};
|
||||
|
||||
typedef struct dataflow_d *dataflow_t;
|
||||
#define FOR_EACH_IMM_USE_SAFE(DEST, ITER, SSAVAR) \
|
||||
for ((DEST) = first_safe_imm_use (&(ITER), (SSAVAR)); \
|
||||
!end_safe_imm_use_p (&(ITER)); \
|
||||
(DEST) = next_safe_imm_use (&(ITER)))
|
||||
|
||||
#define BREAK_FROM_SAFE_IMM_USE(ITER) \
|
||||
{ \
|
||||
end_safe_imm_use_traverse (&(ITER)); \
|
||||
break; \
|
||||
}
|
||||
|
||||
struct stmt_ann_d GTY(())
|
||||
{
|
||||
|
@ -297,11 +287,9 @@ struct stmt_ann_d GTY(())
|
|||
/* Basic block that contains this statement. */
|
||||
basic_block GTY ((skip (""))) bb;
|
||||
|
||||
/* Operand cache for stmt. */
|
||||
struct stmt_operands_d operands;
|
||||
|
||||
/* Dataflow information. */
|
||||
dataflow_t df;
|
||||
|
||||
/* Set of variables that have had their address taken in the statement. */
|
||||
bitmap addresses_taken;
|
||||
|
||||
|
@ -340,8 +328,7 @@ static inline enum tree_ann_type ann_type (tree_ann_t);
|
|||
static inline basic_block bb_for_stmt (tree);
|
||||
extern void set_bb_for_stmt (tree, basic_block);
|
||||
static inline bool noreturn_call_p (tree);
|
||||
static inline void modify_stmt (tree);
|
||||
static inline void unmodify_stmt (tree);
|
||||
static inline void update_stmt (tree);
|
||||
static inline bool stmt_modified_p (tree);
|
||||
static inline varray_type may_aliases (tree);
|
||||
static inline int get_lineno (tree);
|
||||
|
@ -353,9 +340,6 @@ static inline vuse_optype get_vuse_ops (stmt_ann_t);
|
|||
static inline use_optype get_use_ops (stmt_ann_t);
|
||||
static inline def_optype get_def_ops (stmt_ann_t);
|
||||
static inline bitmap addresses_taken (tree);
|
||||
static inline int num_immediate_uses (dataflow_t);
|
||||
static inline tree immediate_use (dataflow_t, int);
|
||||
static inline dataflow_t get_immediate_uses (tree);
|
||||
static inline void set_default_def (tree, tree);
|
||||
static inline tree default_def (tree);
|
||||
|
||||
|
@ -435,7 +419,6 @@ extern bool aliases_computed_p;
|
|||
|
||||
#define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y))
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Block iterators
|
||||
---------------------------------------------------------------------------*/
|
||||
|
@ -559,13 +542,6 @@ extern void debug_referenced_vars (void);
|
|||
extern void dump_referenced_vars (FILE *);
|
||||
extern void dump_variable (FILE *, tree);
|
||||
extern void debug_variable (tree);
|
||||
extern void dump_immediate_uses (FILE *);
|
||||
extern void debug_immediate_uses (void);
|
||||
extern void dump_immediate_uses_for (FILE *, tree);
|
||||
extern void debug_immediate_uses_for (tree);
|
||||
extern void compute_immediate_uses (int, bool (*)(tree));
|
||||
extern void free_df (void);
|
||||
extern void free_df_for_stmt (tree);
|
||||
extern tree get_virtual_var (tree);
|
||||
extern void add_referenced_tmp_var (tree);
|
||||
extern void mark_new_vars_to_rename (tree, bitmap);
|
||||
|
@ -621,7 +597,7 @@ extern edge ssa_redirect_edge (edge, basic_block);
|
|||
extern void flush_pending_stmts (edge);
|
||||
extern bool tree_ssa_useless_type_conversion (tree);
|
||||
extern bool tree_ssa_useless_type_conversion_1 (tree, tree);
|
||||
extern void verify_ssa (void);
|
||||
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);
|
||||
|
|
|
@ -160,7 +160,6 @@ tree_if_conversion (struct loop *loop, bool for_vectorizer)
|
|||
ifc_bbs = NULL;
|
||||
}
|
||||
free_dominance_info (CDI_POST_DOMINATORS);
|
||||
free_df ();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -205,7 +204,6 @@ tree_if_conversion (struct loop *loop, bool for_vectorizer)
|
|||
clean_predicate_lists (loop);
|
||||
free (ifc_bbs);
|
||||
ifc_bbs = NULL;
|
||||
free_df ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -343,13 +341,11 @@ if_convertible_phi_p (struct loop *loop, basic_block bb, tree phi)
|
|||
|
||||
if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi))))
|
||||
{
|
||||
int j;
|
||||
dataflow_t df = get_immediate_uses (phi);
|
||||
int num_uses = num_immediate_uses (df);
|
||||
for (j = 0; j < num_uses; j++)
|
||||
imm_use_iterator imm_iter;
|
||||
use_operand_p use_p;
|
||||
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, PHI_RESULT (phi))
|
||||
{
|
||||
tree use = immediate_use (df, j);
|
||||
if (TREE_CODE (use) == PHI_NODE)
|
||||
if (TREE_CODE (USE_STMT (use_p)) == PHI_NODE)
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "Difficult to handle this virtual phi.\n");
|
||||
|
@ -559,8 +555,6 @@ if_convertible_loop_p (struct loop *loop, bool for_vectorizer ATTRIBUTE_UNUSED)
|
|||
return false;
|
||||
}
|
||||
|
||||
compute_immediate_uses (TDFA_USE_OPS|TDFA_USE_VOPS, NULL);
|
||||
|
||||
calculate_dominance_info (CDI_DOMINATORS);
|
||||
calculate_dominance_info (CDI_POST_DOMINATORS);
|
||||
|
||||
|
@ -798,7 +792,7 @@ replace_phi_with_cond_modify_expr (tree phi, tree cond, basic_block true_bb,
|
|||
bsi_insert_after (bsi, new_stmt, BSI_SAME_STMT);
|
||||
bsi_next (bsi);
|
||||
|
||||
modify_stmt (new_stmt);
|
||||
update_stmt (new_stmt);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
|
|
|
@ -438,7 +438,7 @@ mark_def_sites (struct dom_walk_data *walk_data,
|
|||
/* Mark all the blocks that have definitions for each variable in the
|
||||
VARS_TO_RENAME bitmap. */
|
||||
stmt = bsi_stmt (bsi);
|
||||
get_stmt_operands (stmt);
|
||||
update_stmt_if_modified (stmt);
|
||||
|
||||
REWRITE_THIS_STMT (stmt) = 0;
|
||||
|
||||
|
@ -1346,6 +1346,7 @@ rewrite_into_ssa (bool all)
|
|||
static void
|
||||
rewrite_all_into_ssa (void)
|
||||
{
|
||||
init_ssa_operands ();
|
||||
rewrite_into_ssa (true);
|
||||
}
|
||||
|
||||
|
@ -1583,7 +1584,7 @@ ssa_mark_def_sites (struct dom_walk_data *walk_data,
|
|||
/* Mark all the blocks that have definitions for each variable in the
|
||||
names_to_rename bitmap. */
|
||||
stmt = bsi_stmt (bsi);
|
||||
get_stmt_operands (stmt);
|
||||
update_stmt_if_modified (stmt);
|
||||
|
||||
/* If a variable is used before being set, then the variable is live
|
||||
across a block boundary, so mark it live-on-entry to BB. */
|
||||
|
|
|
@ -244,7 +244,6 @@ linear_transform_loops (struct loops *loops)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
compute_immediate_uses (TDFA_USE_OPS | TDFA_USE_VOPS, NULL);
|
||||
for (i = 1; i < loops->num; i++)
|
||||
{
|
||||
unsigned int depth = 0;
|
||||
|
@ -371,7 +370,6 @@ linear_transform_loops (struct loops *loops)
|
|||
free_dependence_relations (dependence_relations);
|
||||
free_data_refs (datarefs);
|
||||
}
|
||||
free_df ();
|
||||
scev_reset ();
|
||||
rewrite_into_ssa (false);
|
||||
rewrite_into_loop_closed_ssa (NULL);
|
||||
|
|
|
@ -438,8 +438,11 @@ static void execute_pass_list (struct tree_opt_pass *);
|
|||
static unsigned int last_verified;
|
||||
|
||||
static void
|
||||
execute_todo (int properties, unsigned int flags)
|
||||
execute_todo (struct tree_opt_pass *pass, unsigned int flags, bool use_required)
|
||||
{
|
||||
int properties
|
||||
= use_required ? pass->properties_required : pass->properties_provided;
|
||||
|
||||
if (flags & TODO_rename_vars)
|
||||
{
|
||||
rewrite_into_ssa (false);
|
||||
|
@ -475,11 +478,15 @@ execute_todo (int properties, unsigned int flags)
|
|||
}
|
||||
|
||||
if (flags & TODO_ggc_collect)
|
||||
ggc_collect ();
|
||||
{
|
||||
ggc_collect ();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
if (flags & TODO_verify_ssa)
|
||||
verify_ssa ();
|
||||
if ((pass->properties_required & PROP_ssa)
|
||||
&& !(pass->properties_destroyed & PROP_ssa))
|
||||
verify_ssa (true);
|
||||
|
||||
if (flags & TODO_verify_flow)
|
||||
verify_flow_info ();
|
||||
if (flags & TODO_verify_stmts)
|
||||
|
@ -503,7 +510,7 @@ execute_one_pass (struct tree_opt_pass *pass)
|
|||
/* Run pre-pass verification. */
|
||||
todo = pass->todo_flags_start & ~last_verified;
|
||||
if (todo)
|
||||
execute_todo (pass->properties_required, todo);
|
||||
execute_todo (pass, todo, true);
|
||||
|
||||
/* If a dump file name is present, open it if enabled. */
|
||||
if (pass->static_pass_number != -1)
|
||||
|
@ -553,7 +560,7 @@ execute_one_pass (struct tree_opt_pass *pass)
|
|||
todo = pass->todo_flags_finish;
|
||||
last_verified = todo & TODO_verify_all;
|
||||
if (todo)
|
||||
execute_todo (pass->properties_provided, todo);
|
||||
execute_todo (pass, todo, false);
|
||||
|
||||
/* Flush and close dump file. */
|
||||
if (dump_file_name)
|
||||
|
|
|
@ -1928,8 +1928,6 @@ rewrite_trees (var_map map, tree *values)
|
|||
&& (DEF_FROM_PTR (def_p) == USE_OP (uses, 0)))
|
||||
remove = 1;
|
||||
}
|
||||
if (changed & !remove)
|
||||
modify_stmt (stmt);
|
||||
}
|
||||
|
||||
/* Remove any stmts marked for removal. */
|
||||
|
@ -2370,6 +2368,9 @@ remove_ssa_form (FILE *dump, var_map map, int flags)
|
|||
}
|
||||
}
|
||||
|
||||
/* we no longer maintain the SSA operand cache at this point. */
|
||||
fini_ssa_operands ();
|
||||
|
||||
/* If any copies were inserted on edges, analyze and insert them now. */
|
||||
perform_edge_inserts (dump_file);
|
||||
|
||||
|
@ -2457,7 +2458,6 @@ insert_backedge_copies (void)
|
|||
bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
|
||||
else
|
||||
bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
|
||||
modify_stmt (stmt);
|
||||
SET_PHI_ARG_DEF (phi, i, name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ static tree
|
|||
make_phi_node (tree var, int len)
|
||||
{
|
||||
tree phi;
|
||||
int capacity;
|
||||
int capacity, i;
|
||||
|
||||
capacity = ideal_phi_node_len (len);
|
||||
|
||||
|
@ -226,6 +226,15 @@ make_phi_node (tree var, int len)
|
|||
else
|
||||
SET_PHI_RESULT (phi, make_ssa_name (var, phi));
|
||||
|
||||
for (i = 0; i < capacity; i++)
|
||||
{
|
||||
ssa_imm_use_t * imm;
|
||||
imm = &(PHI_ARG_IMM_USE_NODE (phi, i));
|
||||
imm->use = &(PHI_ARG_DEF_TREE (phi, i));
|
||||
imm->prev = NULL;
|
||||
imm->next = NULL;
|
||||
imm->stmt = phi;
|
||||
}
|
||||
return phi;
|
||||
}
|
||||
|
||||
|
@ -236,6 +245,14 @@ release_phi_node (tree phi)
|
|||
{
|
||||
int bucket;
|
||||
int len = PHI_ARG_CAPACITY (phi);
|
||||
int x;
|
||||
|
||||
for (x = 0; x < PHI_NUM_ARGS (phi); x++)
|
||||
{
|
||||
ssa_imm_use_t * imm;
|
||||
imm = &(PHI_ARG_IMM_USE_NODE (phi, x));
|
||||
delink_imm_use (imm);
|
||||
}
|
||||
|
||||
bucket = len > NUM_BUCKETS - 1 ? NUM_BUCKETS - 1 : len;
|
||||
bucket -= 2;
|
||||
|
@ -250,7 +267,7 @@ release_phi_node (tree phi)
|
|||
static void
|
||||
resize_phi_node (tree *phi, int len)
|
||||
{
|
||||
int old_size;
|
||||
int old_size, i;
|
||||
tree new_phi;
|
||||
|
||||
gcc_assert (len > PHI_ARG_CAPACITY (*phi));
|
||||
|
@ -265,8 +282,28 @@ resize_phi_node (tree *phi, int len)
|
|||
|
||||
memcpy (new_phi, *phi, old_size);
|
||||
|
||||
for (i = 0; i < PHI_NUM_ARGS (new_phi); i++)
|
||||
{
|
||||
ssa_imm_use_t *imm, *old_imm;
|
||||
imm = &(PHI_ARG_IMM_USE_NODE (new_phi, i));
|
||||
old_imm = &(PHI_ARG_IMM_USE_NODE (*phi, i));
|
||||
imm->use = &(PHI_ARG_DEF_TREE (new_phi, i));
|
||||
relink_imm_use_stmt (imm, old_imm, new_phi);
|
||||
}
|
||||
|
||||
PHI_ARG_CAPACITY (new_phi) = len;
|
||||
|
||||
for (i = PHI_NUM_ARGS (new_phi); i < len; i++)
|
||||
{
|
||||
ssa_imm_use_t * imm;
|
||||
imm = &(PHI_ARG_IMM_USE_NODE (new_phi, i));
|
||||
imm->use = &(PHI_ARG_DEF_TREE (new_phi, i));
|
||||
imm->prev = NULL;
|
||||
imm->next = NULL;
|
||||
imm->stmt = new_phi;
|
||||
}
|
||||
|
||||
|
||||
*phi = new_phi;
|
||||
}
|
||||
|
||||
|
@ -372,6 +409,9 @@ remove_phi_arg_num (tree phi, int i)
|
|||
|
||||
gcc_assert (i < num_elem);
|
||||
|
||||
/* Delink the last item, which is being removed. */
|
||||
delink_imm_use (&(PHI_ARG_IMM_USE_NODE (phi, num_elem - 1)));
|
||||
|
||||
/* If we are not at the last element, switch the last element
|
||||
with the element we want to delete. */
|
||||
if (i != num_elem - 1)
|
||||
|
@ -423,8 +463,8 @@ remove_phi_node (tree phi, tree prev)
|
|||
|
||||
/* If we are deleting the PHI node, then we should release the
|
||||
SSA_NAME node so that it can be reused. */
|
||||
release_ssa_name (PHI_RESULT (phi));
|
||||
release_phi_node (phi);
|
||||
release_ssa_name (PHI_RESULT (phi));
|
||||
}
|
||||
|
||||
|
||||
|
@ -461,8 +501,8 @@ remove_all_phi_nodes_for (bitmap vars)
|
|||
{
|
||||
/* If we are deleting the PHI node, then we should release the
|
||||
SSA_NAME node so that it can be reused. */
|
||||
release_ssa_name (PHI_RESULT (phi));
|
||||
release_phi_node (phi);
|
||||
release_ssa_name (PHI_RESULT (phi));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -271,6 +271,9 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
|
|||
&& stmt_ann (node))
|
||||
dump_vops (buffer, node, spc, flags);
|
||||
|
||||
if (is_stmt && (flags & TDF_STMTADDR))
|
||||
pp_printf (buffer, "<&0x%x> ", (unsigned int)node);
|
||||
|
||||
if (dumping_stmts
|
||||
&& (flags & TDF_LINENO)
|
||||
&& EXPR_HAS_LOCATION (node))
|
||||
|
|
|
@ -1444,7 +1444,7 @@ mark_all_v_defs (tree stmt)
|
|||
tree sym;
|
||||
ssa_op_iter iter;
|
||||
|
||||
get_stmt_operands (stmt);
|
||||
update_stmt_if_modified (stmt);
|
||||
|
||||
FOR_EACH_SSA_TREE_OPERAND (sym, stmt, iter, SSA_OP_ALL_VIRTUALS)
|
||||
{
|
||||
|
@ -1800,7 +1800,7 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
|
|||
if (is_output)
|
||||
mark_all_v_defs (stmt);
|
||||
*expr_p = elt->replacement;
|
||||
modify_stmt (stmt);
|
||||
update_stmt (stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1848,7 +1848,7 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
|
|||
|
||||
TREE_OPERAND (stmt, 0) = lhs_elt->replacement;
|
||||
TREE_OPERAND (stmt, 1) = rhs_elt->replacement;
|
||||
modify_stmt (stmt);
|
||||
update_stmt (stmt);
|
||||
}
|
||||
else if (lhs_elt->use_block_copy || rhs_elt->use_block_copy)
|
||||
{
|
||||
|
|
|
@ -343,6 +343,19 @@ compute_may_aliases (void)
|
|||
|
||||
/* Deallocate memory used by aliasing data structures. */
|
||||
delete_alias_info (ai);
|
||||
|
||||
{
|
||||
block_stmt_iterator bsi;
|
||||
basic_block bb;
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
|
||||
{
|
||||
update_stmt_if_modified (bsi_stmt (bsi));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct tree_opt_pass pass_may_alias =
|
||||
|
@ -766,7 +779,7 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
|
|||
need to re-scan most statements. FIXME: Try to minimize the
|
||||
number of statements re-scanned. It's not really necessary to
|
||||
re-scan *all* statements. */
|
||||
modify_stmt (stmt);
|
||||
mark_stmt_modified (stmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -331,16 +331,6 @@ likely_value (tree stmt)
|
|||
}
|
||||
|
||||
|
||||
/* Function indicating whether we ought to include information for VAR
|
||||
when calculating immediate uses. */
|
||||
|
||||
static bool
|
||||
need_imm_uses_for (tree var)
|
||||
{
|
||||
return get_value (var)->lattice_val != VARYING;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize local data structures for CCP. */
|
||||
|
||||
static void
|
||||
|
@ -430,9 +420,6 @@ ccp_initialize (void)
|
|||
}
|
||||
|
||||
sbitmap_free (is_may_def);
|
||||
|
||||
/* Compute immediate uses for variables we care about. */
|
||||
compute_immediate_uses (TDFA_USE_OPS | TDFA_USE_VOPS, need_imm_uses_for);
|
||||
}
|
||||
|
||||
|
||||
|
@ -591,7 +578,7 @@ substitute_and_fold (void)
|
|||
if (maybe_clean_eh_stmt (stmt))
|
||||
tree_purge_dead_eh_edges (bb);
|
||||
|
||||
modify_stmt (stmt);
|
||||
update_stmt (stmt);
|
||||
}
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
|
@ -2211,7 +2198,7 @@ execute_fold_all_builtins (void)
|
|||
gcc_assert (ok);
|
||||
}
|
||||
}
|
||||
modify_stmt (*stmtp);
|
||||
update_stmt (*stmtp);
|
||||
if (maybe_clean_eh_stmt (*stmtp)
|
||||
&& tree_purge_dead_eh_edges (bb))
|
||||
cfg_changed = true;
|
||||
|
|
|
@ -450,6 +450,17 @@ tree_ssa_dominator_optimize (void)
|
|||
|
||||
free_all_edge_infos ();
|
||||
|
||||
{
|
||||
block_stmt_iterator bsi;
|
||||
basic_block bb;
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
|
||||
{
|
||||
update_stmt_if_modified (bsi_stmt (bsi));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Thread jumps, creating duplicate blocks as needed. */
|
||||
cfg_altered |= thread_through_all_blocks ();
|
||||
|
||||
|
@ -2097,7 +2108,7 @@ simplify_cond_and_lookup_avail_expr (tree stmt,
|
|||
/* If this is not a real stmt, ann will be NULL and we
|
||||
avoid processing the operands. */
|
||||
if (ann)
|
||||
modify_stmt (stmt);
|
||||
mark_stmt_modified (stmt);
|
||||
|
||||
/* Lookup the condition and return its known value if it
|
||||
exists. */
|
||||
|
@ -2349,7 +2360,7 @@ simplify_switch_and_lookup_avail_expr (tree stmt, int insert)
|
|||
if (!fail)
|
||||
{
|
||||
SWITCH_COND (stmt) = def;
|
||||
modify_stmt (stmt);
|
||||
mark_stmt_modified (stmt);
|
||||
|
||||
return lookup_avail_expr (stmt, insert);
|
||||
}
|
||||
|
@ -2709,7 +2720,7 @@ eliminate_redundant_computations (struct dom_walk_data *walk_data,
|
|||
retval = true;
|
||||
|
||||
propagate_tree_value (expr_p, cached_lhs);
|
||||
modify_stmt (stmt);
|
||||
mark_stmt_modified (stmt);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@ -2946,7 +2957,7 @@ cprop_operand (tree stmt, use_operand_p op_p)
|
|||
/* And note that we modified this statement. This is now
|
||||
safe, even if we changed virtual operands since we will
|
||||
rescan the statement and rewrite its operands again. */
|
||||
modify_stmt (stmt);
|
||||
mark_stmt_modified (stmt);
|
||||
}
|
||||
return may_have_exposed_new_symbols;
|
||||
}
|
||||
|
@ -3008,7 +3019,7 @@ optimize_stmt (struct dom_walk_data *walk_data, basic_block bb,
|
|||
|
||||
stmt = bsi_stmt (si);
|
||||
|
||||
get_stmt_operands (stmt);
|
||||
update_stmt_if_modified (stmt);
|
||||
ann = stmt_ann (stmt);
|
||||
opt_stats.num_stmts++;
|
||||
may_have_exposed_new_symbols = false;
|
||||
|
@ -3178,7 +3189,7 @@ update_rhs_and_lookup_avail_expr (tree stmt, tree new_rhs, bool insert)
|
|||
|
||||
/* And make sure we record the fact that we modified this
|
||||
statement. */
|
||||
modify_stmt (stmt);
|
||||
mark_stmt_modified (stmt);
|
||||
|
||||
return cached_lhs;
|
||||
}
|
||||
|
|
|
@ -94,8 +94,6 @@ static void dse_optimize_stmt (struct dom_walk_data *,
|
|||
block_stmt_iterator);
|
||||
static void dse_record_phis (struct dom_walk_data *, basic_block);
|
||||
static void dse_finalize_block (struct dom_walk_data *, basic_block);
|
||||
static void fix_phi_uses (tree, tree);
|
||||
static void fix_stmt_v_may_defs (tree, tree);
|
||||
static void record_voperand_set (bitmap, bitmap *, unsigned int);
|
||||
|
||||
static unsigned max_stmt_uid; /* Maximal uid of a statement. Uids to phi
|
||||
|
@ -124,83 +122,6 @@ need_imm_uses_for (tree var)
|
|||
}
|
||||
|
||||
|
||||
/* Replace uses in PHI which match V_MAY_DEF_RESULTs in STMT with the
|
||||
corresponding V_MAY_DEF_OP in STMT. */
|
||||
|
||||
static void
|
||||
fix_phi_uses (tree phi, tree stmt)
|
||||
{
|
||||
use_operand_p use_p;
|
||||
def_operand_p def_p;
|
||||
ssa_op_iter iter;
|
||||
int i;
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
|
||||
FOR_EACH_EDGE (e, ei, PHI_BB (phi)->preds)
|
||||
if (e->flags & EDGE_ABNORMAL)
|
||||
break;
|
||||
|
||||
get_stmt_operands (stmt);
|
||||
|
||||
FOR_EACH_SSA_MAYDEF_OPERAND (def_p, use_p, stmt, iter)
|
||||
{
|
||||
tree v_may_def = DEF_FROM_PTR (def_p);
|
||||
tree v_may_use = USE_FROM_PTR (use_p);
|
||||
|
||||
/* Find any uses in the PHI which match V_MAY_DEF and replace
|
||||
them with the appropriate V_MAY_DEF_OP. */
|
||||
for (i = 0; i < PHI_NUM_ARGS (phi); i++)
|
||||
if (v_may_def == PHI_ARG_DEF (phi, i))
|
||||
{
|
||||
SET_PHI_ARG_DEF (phi, i, v_may_use);
|
||||
/* Update if the new phi argument is an abnormal phi. */
|
||||
if (e != NULL)
|
||||
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (v_may_use) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace the V_MAY_DEF_OPs in STMT1 which match V_MAY_DEF_RESULTs
|
||||
in STMT2 with the appropriate V_MAY_DEF_OPs from STMT2. */
|
||||
|
||||
static void
|
||||
fix_stmt_v_may_defs (tree stmt1, tree stmt2)
|
||||
{
|
||||
bool found = false;
|
||||
ssa_op_iter iter1;
|
||||
ssa_op_iter iter2;
|
||||
use_operand_p use1_p, use2_p;
|
||||
def_operand_p def1_p, def2_p;
|
||||
|
||||
get_stmt_operands (stmt1);
|
||||
get_stmt_operands (stmt2);
|
||||
|
||||
/* Walk each V_MAY_DEF_OP in stmt1. */
|
||||
FOR_EACH_SSA_MAYDEF_OPERAND (def1_p, use1_p, stmt1, iter1)
|
||||
{
|
||||
tree use = USE_FROM_PTR (use1_p);
|
||||
|
||||
/* Find the appropriate V_MAY_DEF_RESULT in STMT2. */
|
||||
FOR_EACH_SSA_MAYDEF_OPERAND (def2_p, use2_p, stmt2, iter2)
|
||||
{
|
||||
tree def = DEF_FROM_PTR (def2_p);
|
||||
if (use == def)
|
||||
{
|
||||
/* Update. */
|
||||
SET_USE (use1_p, USE_FROM_PTR (use2_p));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we did not find a corresponding V_MAY_DEF_RESULT,
|
||||
then something has gone terribly wrong. */
|
||||
gcc_assert (found);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Set bit UID in bitmaps GLOBAL and *LOCAL, creating *LOCAL as needed. */
|
||||
static void
|
||||
record_voperand_set (bitmap global, bitmap *local, unsigned int uid)
|
||||
|
@ -275,57 +196,66 @@ dse_optimize_stmt (struct dom_walk_data *walk_data,
|
|||
|
||||
if (TREE_CODE (stmt) == MODIFY_EXPR)
|
||||
{
|
||||
dataflow_t df = get_immediate_uses (stmt);
|
||||
unsigned int num_uses = num_immediate_uses (df);
|
||||
tree use;
|
||||
tree skipped_phi;
|
||||
unsigned int num_uses = 0, count = 0;
|
||||
use_operand_p first_use_p = NULL_USE_OPERAND_P;
|
||||
use_operand_p use_p;
|
||||
tree use, use_stmt;
|
||||
tree defvar = NULL_TREE, usevar = NULL_TREE;
|
||||
use_operand_p var2;
|
||||
def_operand_p var1;
|
||||
ssa_op_iter op_iter;
|
||||
|
||||
/* If there are no uses then there is nothing left to do. */
|
||||
if (num_uses == 0)
|
||||
FOR_EACH_SSA_MAYDEF_OPERAND (var1, var2, stmt, op_iter)
|
||||
{
|
||||
defvar = DEF_FROM_PTR (var1);
|
||||
usevar = USE_FROM_PTR (var2);
|
||||
num_uses += num_imm_uses (defvar);
|
||||
count++;
|
||||
if (num_uses > 1 || count > 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (count == 1 && num_uses == 1)
|
||||
{
|
||||
single_imm_use (defvar, &use_p, &use_stmt);
|
||||
gcc_assert (use_p != NULL_USE_OPERAND_P);
|
||||
first_use_p = use_p;
|
||||
use = USE_FROM_PTR (use_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
record_voperand_set (dse_gd->stores, &bd->stores, ann->uid);
|
||||
return;
|
||||
}
|
||||
|
||||
use = immediate_use (df, 0);
|
||||
skipped_phi = NULL;
|
||||
|
||||
/* Skip through any PHI nodes we have already seen if the PHI
|
||||
represents the only use of this store.
|
||||
|
||||
Note this does not handle the case where the store has
|
||||
multiple V_MAY_DEFs which all reach a set of PHI nodes in the
|
||||
same block. */
|
||||
while (num_uses == 1
|
||||
&& TREE_CODE (use) == PHI_NODE
|
||||
&& bitmap_bit_p (dse_gd->stores, get_stmt_uid (use)))
|
||||
while (use_p != NULL_USE_OPERAND_P
|
||||
&& TREE_CODE (use_stmt) == PHI_NODE
|
||||
&& bitmap_bit_p (dse_gd->stores, get_stmt_uid (use_stmt)))
|
||||
{
|
||||
/* Record the first PHI we skip so that we can fix its
|
||||
uses if we find that STMT is a dead store. */
|
||||
if (!skipped_phi)
|
||||
skipped_phi = use;
|
||||
|
||||
/* Skip past this PHI and loop again in case we had a PHI
|
||||
chain. */
|
||||
df = get_immediate_uses (use);
|
||||
num_uses = num_immediate_uses (df);
|
||||
use = immediate_use (df, 0);
|
||||
if (single_imm_use (PHI_RESULT (use_stmt), &use_p, &use_stmt))
|
||||
use = USE_FROM_PTR (use_p);
|
||||
}
|
||||
|
||||
/* If we have precisely one immediate use at this point, then we may
|
||||
have found redundant store. */
|
||||
if (num_uses == 1
|
||||
&& bitmap_bit_p (dse_gd->stores, get_stmt_uid (use))
|
||||
if (use_p != NULL_USE_OPERAND_P
|
||||
&& bitmap_bit_p (dse_gd->stores, get_stmt_uid (use_stmt))
|
||||
&& operand_equal_p (TREE_OPERAND (stmt, 0),
|
||||
TREE_OPERAND (use, 0), 0))
|
||||
TREE_OPERAND (use_stmt, 0), 0))
|
||||
{
|
||||
/* We need to fix the operands if either the first PHI we
|
||||
skipped, or the store which we are not deleting if we did
|
||||
not skip any PHIs. */
|
||||
if (skipped_phi)
|
||||
fix_phi_uses (skipped_phi, stmt);
|
||||
else
|
||||
fix_stmt_v_may_defs (use, stmt);
|
||||
/* 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;
|
||||
/* Then we need to fix the operand of the consuming stmt. */
|
||||
SET_USE (first_use_p, usevar);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
|
@ -334,21 +264,12 @@ dse_optimize_stmt (struct dom_walk_data *walk_data,
|
|||
fprintf (dump_file, "'\n");
|
||||
}
|
||||
|
||||
/* Any immediate uses which reference STMT need to instead
|
||||
reference the new consumer, either SKIPPED_PHI or USE.
|
||||
This allows us to cascade dead stores. */
|
||||
redirect_immediate_uses (stmt, skipped_phi ? skipped_phi : use);
|
||||
|
||||
/* Be sure to remove any dataflow information attached to
|
||||
this statement. */
|
||||
free_df_for_stmt (stmt);
|
||||
/* Remove the dead store. */
|
||||
bsi_remove (&bsi);
|
||||
|
||||
/* And release any SSA_NAMEs set in this statement back to the
|
||||
SSA_NAME manager. */
|
||||
release_defs (stmt);
|
||||
|
||||
/* Finally remove the dead store. */
|
||||
bsi_remove (&bsi);
|
||||
}
|
||||
|
||||
record_voperand_set (dse_gd->stores, &bd->stores, ann->uid);
|
||||
|
@ -415,9 +336,6 @@ tree_ssa_dse (void)
|
|||
dominators. */
|
||||
calculate_dominance_info (CDI_POST_DOMINATORS);
|
||||
|
||||
/* We also need immediate use information for virtual operands. */
|
||||
compute_immediate_uses (TDFA_USE_VOPS, need_imm_uses_for);
|
||||
|
||||
/* Dead store elimination is fundamentally a walk of the post-dominator
|
||||
tree and a backwards walk of statements within each block. */
|
||||
walk_data.walk_stmts_backward = true;
|
||||
|
@ -448,9 +366,6 @@ tree_ssa_dse (void)
|
|||
/* Release the main bitmap. */
|
||||
BITMAP_FREE (dse_gd.stores);
|
||||
|
||||
/* Free dataflow information. It's probably out of date now anyway. */
|
||||
free_df ();
|
||||
|
||||
/* For now, just wipe the post-dominator information. */
|
||||
free_dominance_info (CDI_POST_DOMINATORS);
|
||||
}
|
||||
|
|
|
@ -113,22 +113,12 @@ Boston, MA 02111-1307, USA. */
|
|||
by record_single_argument_cond_exprs and tested in need_imm_uses_for. */
|
||||
static bitmap vars;
|
||||
|
||||
static bool need_imm_uses_for (tree);
|
||||
static void tree_ssa_forward_propagate_single_use_vars (void);
|
||||
static void record_single_argument_cond_exprs (varray_type,
|
||||
varray_type *,
|
||||
bitmap);
|
||||
static void substitute_single_use_vars (varray_type *, varray_type);
|
||||
|
||||
/* Function indicating whether we ought to include information for 'var'
|
||||
when calculating immediate uses. */
|
||||
|
||||
static bool
|
||||
need_imm_uses_for (tree var)
|
||||
{
|
||||
return bitmap_bit_p (vars, SSA_NAME_VERSION (var));
|
||||
}
|
||||
|
||||
/* Find all COND_EXPRs with a condition that is a naked SSA_NAME or
|
||||
an equality comparison against a constant.
|
||||
|
||||
|
@ -323,27 +313,32 @@ static void
|
|||
substitute_single_use_vars (varray_type *cond_worklist,
|
||||
varray_type vars_worklist)
|
||||
{
|
||||
use_operand_p use_p;
|
||||
while (VARRAY_ACTIVE_SIZE (vars_worklist) > 0)
|
||||
{
|
||||
tree test_var = VARRAY_TOP_TREE (vars_worklist);
|
||||
tree def = SSA_NAME_DEF_STMT (test_var);
|
||||
dataflow_t df;
|
||||
int j, num_uses, propagated_uses;
|
||||
tree def_stmt = SSA_NAME_DEF_STMT (test_var);
|
||||
tree def;
|
||||
int num_uses, propagated_uses;
|
||||
imm_use_iterator imm_iter;
|
||||
|
||||
VARRAY_POP (vars_worklist);
|
||||
|
||||
/* Now compute the immediate uses of TEST_VAR. */
|
||||
df = get_immediate_uses (def);
|
||||
num_uses = num_immediate_uses (df);
|
||||
propagated_uses = 0;
|
||||
num_uses = 0;
|
||||
|
||||
if (NUM_DEFS (STMT_DEF_OPS (def_stmt)) != 1)
|
||||
continue;
|
||||
|
||||
def = DEF_OP (STMT_DEF_OPS (def_stmt), 0);
|
||||
|
||||
/* If TEST_VAR is used more than once and is not a boolean set
|
||||
via TRUTH_NOT_EXPR with another SSA_NAME as its argument, then
|
||||
we can not optimize. */
|
||||
if (num_uses == 1
|
||||
if (has_single_use (def)
|
||||
|| (TREE_CODE (TREE_TYPE (test_var)) == BOOLEAN_TYPE
|
||||
&& TREE_CODE (TREE_OPERAND (def, 1)) == TRUTH_NOT_EXPR
|
||||
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (def, 1), 0))
|
||||
&& TREE_CODE (TREE_OPERAND (def_stmt, 1)) == TRUTH_NOT_EXPR
|
||||
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0))
|
||||
== SSA_NAME)))
|
||||
;
|
||||
else
|
||||
|
@ -351,7 +346,7 @@ substitute_single_use_vars (varray_type *cond_worklist,
|
|||
|
||||
/* Walk over each use and try to forward propagate the RHS of
|
||||
DEF into the use. */
|
||||
for (j = 0; j < num_uses; j++)
|
||||
FOR_EACH_IMM_USE_SAFE (use_p, imm_iter, def)
|
||||
{
|
||||
tree cond_stmt;
|
||||
tree cond;
|
||||
|
@ -360,7 +355,8 @@ substitute_single_use_vars (varray_type *cond_worklist,
|
|||
enum tree_code def_rhs_code;
|
||||
tree new_cond;
|
||||
|
||||
cond_stmt = immediate_use (df, j);
|
||||
cond_stmt = USE_STMT (use_p);
|
||||
num_uses++;
|
||||
|
||||
/* For now we can only propagate into COND_EXPRs. */
|
||||
if (TREE_CODE (cond_stmt) != COND_EXPR)
|
||||
|
@ -368,7 +364,7 @@ substitute_single_use_vars (varray_type *cond_worklist,
|
|||
|
||||
cond = COND_EXPR_COND (cond_stmt);
|
||||
cond_code = TREE_CODE (cond);
|
||||
def_rhs = TREE_OPERAND (def, 1);
|
||||
def_rhs = TREE_OPERAND (def_stmt, 1);
|
||||
def_rhs_code = TREE_CODE (def_rhs);
|
||||
|
||||
/* If the definition of the single use variable was from an
|
||||
|
@ -456,7 +452,7 @@ substitute_single_use_vars (varray_type *cond_worklist,
|
|||
|
||||
/* Replace the condition. */
|
||||
COND_EXPR_COND (cond_stmt) = new_cond;
|
||||
modify_stmt (cond_stmt);
|
||||
update_stmt (cond_stmt);
|
||||
propagated_uses++;
|
||||
VARRAY_PUSH_TREE (*cond_worklist, cond_stmt);
|
||||
}
|
||||
|
@ -466,7 +462,7 @@ substitute_single_use_vars (varray_type *cond_worklist,
|
|||
whatever block it might be in. */
|
||||
if (num_uses && num_uses == propagated_uses)
|
||||
{
|
||||
block_stmt_iterator bsi = bsi_for_stmt (def);
|
||||
block_stmt_iterator bsi = bsi_for_stmt (def_stmt);
|
||||
bsi_remove (&bsi);
|
||||
}
|
||||
}
|
||||
|
@ -502,9 +498,6 @@ tree_ssa_forward_propagate_single_use_vars (void)
|
|||
|
||||
if (VARRAY_ACTIVE_SIZE (vars_worklist) > 0)
|
||||
{
|
||||
/* Now compute immediate uses for all the variables we care about. */
|
||||
compute_immediate_uses (TDFA_USE_OPS, need_imm_uses_for);
|
||||
|
||||
/* We've computed immediate uses, so we can/must clear the VARS
|
||||
bitmap for the next iteration. */
|
||||
bitmap_clear (vars);
|
||||
|
@ -512,12 +505,6 @@ tree_ssa_forward_propagate_single_use_vars (void)
|
|||
/* And optimize. This will drain VARS_WORKLIST and initialize
|
||||
COND_WORKLIST for the next iteration. */
|
||||
substitute_single_use_vars (&cond_worklist, vars_worklist);
|
||||
|
||||
/* We do not incrementally update the dataflow information
|
||||
so we must free it here and recompute the necessary bits
|
||||
on the next iteration. If this turns out to be expensive,
|
||||
methods for incrementally updating the dataflow are known. */
|
||||
free_df ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -971,12 +971,13 @@ single_reachable_address (struct loop *loop, tree stmt,
|
|||
tree *queue = xmalloc (sizeof (tree) * max_uid);
|
||||
sbitmap seen = sbitmap_alloc (max_uid);
|
||||
unsigned in_queue = 1;
|
||||
dataflow_t df;
|
||||
unsigned i, n;
|
||||
unsigned i;
|
||||
struct sra_data sra_data;
|
||||
tree call;
|
||||
tree val;
|
||||
ssa_op_iter iter;
|
||||
imm_use_iterator imm_iter;
|
||||
use_operand_p use_p;
|
||||
|
||||
sbitmap_zero (seen);
|
||||
|
||||
|
@ -1034,22 +1035,40 @@ single_reachable_address (struct loop *loop, tree stmt,
|
|||
}
|
||||
|
||||
/* Find uses of virtual names. */
|
||||
df = get_immediate_uses (stmt);
|
||||
n = num_immediate_uses (df);
|
||||
if (TREE_CODE (stmt) == PHI_NODE)
|
||||
{
|
||||
if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (stmt))))
|
||||
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, PHI_RESULT (stmt))
|
||||
{
|
||||
tree imm_stmt = USE_STMT (use_p);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
stmt = immediate_use (df, i);
|
||||
if (TEST_BIT (seen, get_stmt_uid (imm_stmt)))
|
||||
continue;
|
||||
|
||||
if (!flow_bb_inside_loop_p (loop, bb_for_stmt (stmt)))
|
||||
continue;
|
||||
if (!flow_bb_inside_loop_p (loop, bb_for_stmt (imm_stmt)))
|
||||
continue;
|
||||
|
||||
if (TEST_BIT (seen, get_stmt_uid (stmt)))
|
||||
continue;
|
||||
SET_BIT (seen, get_stmt_uid (stmt));
|
||||
SET_BIT (seen, get_stmt_uid (imm_stmt));
|
||||
|
||||
queue[in_queue++] = stmt;
|
||||
queue[in_queue++] = imm_stmt;
|
||||
}
|
||||
}
|
||||
else
|
||||
FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_VIRTUAL_DEFS)
|
||||
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, val)
|
||||
{
|
||||
tree imm_stmt = USE_STMT (use_p);
|
||||
|
||||
if (TEST_BIT (seen, get_stmt_uid (imm_stmt)))
|
||||
continue;
|
||||
|
||||
if (!flow_bb_inside_loop_p (loop, bb_for_stmt (imm_stmt)))
|
||||
continue;
|
||||
|
||||
SET_BIT (seen, get_stmt_uid (imm_stmt));
|
||||
|
||||
queue[in_queue++] = imm_stmt;
|
||||
}
|
||||
}
|
||||
|
||||
free (queue);
|
||||
|
@ -1083,7 +1102,7 @@ rewrite_mem_refs (tree tmp_var, struct mem_ref *mem_refs)
|
|||
}
|
||||
|
||||
*mem_refs->ref = tmp_var;
|
||||
modify_stmt (mem_refs->stmt);
|
||||
update_stmt (mem_refs->stmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1337,8 +1356,6 @@ determine_lsm (struct loops *loops)
|
|||
stmt_ann (bsi_stmt (bsi))->uid = max_stmt_uid++;
|
||||
}
|
||||
|
||||
compute_immediate_uses (TDFA_USE_VOPS, NULL);
|
||||
|
||||
/* Pass the loops from the outermost. For each virtual operand loop phi node
|
||||
check whether all the references inside the loop correspond to a single
|
||||
address, and if so, move them. */
|
||||
|
@ -1358,7 +1375,6 @@ determine_lsm (struct loops *loops)
|
|||
loop = loop->outer;
|
||||
if (loop == loops->tree_root)
|
||||
{
|
||||
free_df ();
|
||||
loop_commit_inserts ();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ create_canonical_iv (struct loop *loop, edge exit, tree niter)
|
|||
COND_EXPR_COND (cond) = build2 (cmp, boolean_type_node,
|
||||
var,
|
||||
build_int_cst (type, 0));
|
||||
modify_stmt (cond);
|
||||
update_stmt (cond);
|
||||
}
|
||||
|
||||
/* Computes an estimated number of insns in LOOP. */
|
||||
|
@ -170,19 +170,20 @@ try_unroll_loop_completely (struct loops *loops ATTRIBUTE_UNUSED,
|
|||
{
|
||||
old_cond = COND_EXPR_COND (cond);
|
||||
COND_EXPR_COND (cond) = dont_exit;
|
||||
modify_stmt (cond);
|
||||
update_stmt (cond);
|
||||
|
||||
if (!tree_duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
|
||||
loops, n_unroll, NULL,
|
||||
NULL, NULL, NULL, 0))
|
||||
{
|
||||
COND_EXPR_COND (cond) = old_cond;
|
||||
update_stmt (cond);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
COND_EXPR_COND (cond) = do_exit;
|
||||
modify_stmt (cond);
|
||||
update_stmt (cond);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "Unrolled loop %d completely.\n", loop->num);
|
||||
|
|
|
@ -4835,6 +4835,7 @@ rewrite_address_base (block_stmt_iterator *bsi, tree *op, tree with)
|
|||
new_name = make_ssa_name (new_var, copy);
|
||||
}
|
||||
TREE_OPERAND (copy, 0) = new_name;
|
||||
update_stmt (copy);
|
||||
bsi_insert_before (bsi, copy, BSI_SAME_STMT);
|
||||
with = new_name;
|
||||
|
||||
|
@ -4898,7 +4899,7 @@ rewrite_use_compare (struct ivopts_data *data,
|
|||
bsi_insert_before (&bsi, stmts, BSI_SAME_STMT);
|
||||
|
||||
*use->op_p = build2 (compare, boolean_type_node, var, op);
|
||||
modify_stmt (use->stmt);
|
||||
update_stmt (use->stmt);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4999,19 +5000,24 @@ compute_phi_arg_on_exit (edge exit, tree stmts, tree op)
|
|||
if (!single_pred_p (exit->dest))
|
||||
split_loop_exit_edge (exit);
|
||||
|
||||
if (TREE_CODE (stmts) == STATEMENT_LIST)
|
||||
{
|
||||
for (tsi = tsi_start (stmts); !tsi_end_p (tsi); tsi_next (&tsi))
|
||||
protect_loop_closed_ssa_form (exit, tsi_stmt (tsi));
|
||||
}
|
||||
else
|
||||
protect_loop_closed_ssa_form (exit, stmts);
|
||||
|
||||
/* Ensure there is label in exit->dest, so that we can
|
||||
insert after it. */
|
||||
tree_block_label (exit->dest);
|
||||
bsi = bsi_after_labels (exit->dest);
|
||||
bsi_insert_after (&bsi, stmts, BSI_CONTINUE_LINKING);
|
||||
|
||||
if (TREE_CODE (stmts) == STATEMENT_LIST)
|
||||
{
|
||||
for (tsi = tsi_start (stmts); !tsi_end_p (tsi); tsi_next (&tsi))
|
||||
{
|
||||
bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_NEW_STMT);
|
||||
protect_loop_closed_ssa_form (exit, bsi_stmt (bsi));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bsi_insert_after (&bsi, stmts, BSI_NEW_STMT);
|
||||
protect_loop_closed_ssa_form (exit, bsi_stmt (bsi));
|
||||
}
|
||||
|
||||
if (!op)
|
||||
return;
|
||||
|
@ -5130,7 +5136,7 @@ rewrite_use (struct ivopts_data *data,
|
|||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
modify_stmt (use->stmt);
|
||||
update_stmt (use->stmt);
|
||||
}
|
||||
|
||||
/* Rewrite the uses using the selected induction variables. */
|
||||
|
|
|
@ -415,7 +415,7 @@ verify_loop_closed_ssa (void)
|
|||
tree phi;
|
||||
unsigned i;
|
||||
|
||||
verify_ssa ();
|
||||
verify_ssa (false);
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
|
|
|
@ -249,7 +249,7 @@ tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
|
|||
else
|
||||
break;
|
||||
|
||||
modify_stmt (stmt);
|
||||
update_stmt (stmt);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
|
|
@ -127,9 +127,9 @@ static GTY (()) varray_type ro_call_vuses;
|
|||
static bool clobbered_aliased_loads;
|
||||
static bool clobbered_aliased_stores;
|
||||
static bool ro_call_aliased_loads;
|
||||
static stmt_operands_p parse_old_ops = NULL;
|
||||
|
||||
def_operand_p NULL_DEF_OPERAND_P = { NULL };
|
||||
use_operand_p NULL_USE_OPERAND_P = { NULL };
|
||||
|
||||
static void note_addressable (tree, stmt_ann_t);
|
||||
static void get_expr_operands (tree, tree *, int);
|
||||
|
@ -165,7 +165,7 @@ allocate_use_optype (unsigned num)
|
|||
{
|
||||
use_optype use_ops;
|
||||
unsigned size;
|
||||
size = sizeof (struct use_optype_d) + sizeof (tree *) * (num - 1);
|
||||
size = sizeof (struct use_optype_d) + sizeof (use_operand_type_t) * (num - 1);
|
||||
use_ops = ggc_alloc (size);
|
||||
use_ops->num_uses = num;
|
||||
return use_ops;
|
||||
|
@ -194,7 +194,8 @@ allocate_vuse_optype (unsigned num)
|
|||
{
|
||||
vuse_optype vuse_ops;
|
||||
unsigned size;
|
||||
size = sizeof (struct vuse_optype_d) + sizeof (tree) * (num - 1);
|
||||
size = sizeof (struct vuse_optype_d)
|
||||
+ sizeof (vuse_operand_type_t) * (num - 1);
|
||||
vuse_ops = ggc_alloc (size);
|
||||
vuse_ops->num_vuses = num;
|
||||
return vuse_ops;
|
||||
|
@ -222,6 +223,10 @@ free_uses (use_optype *uses)
|
|||
{
|
||||
if (*uses)
|
||||
{
|
||||
unsigned int x;
|
||||
use_optype use = *uses;
|
||||
for (x = 0; x < use->num_uses; x++)
|
||||
delink_imm_use (&(use->uses[x]));
|
||||
ggc_free (*uses);
|
||||
*uses = NULL;
|
||||
}
|
||||
|
@ -248,6 +253,10 @@ free_vuses (vuse_optype *vuses)
|
|||
{
|
||||
if (*vuses)
|
||||
{
|
||||
unsigned int x;
|
||||
vuse_optype vuse = *vuses;
|
||||
for (x = 0; x < vuse->num_vuses; x++)
|
||||
delink_imm_use (&(vuse->vuses[x].imm_use));
|
||||
ggc_free (*vuses);
|
||||
*vuses = NULL;
|
||||
}
|
||||
|
@ -261,6 +270,10 @@ free_v_may_defs (v_may_def_optype *v_may_defs)
|
|||
{
|
||||
if (*v_may_defs)
|
||||
{
|
||||
unsigned int x;
|
||||
v_may_def_optype v_may_def = *v_may_defs;
|
||||
for (x = 0; x < v_may_def->num_v_may_defs; x++)
|
||||
delink_imm_use (&(v_may_def->v_may_defs[x].imm_use));
|
||||
ggc_free (*v_may_defs);
|
||||
*v_may_defs = NULL;
|
||||
}
|
||||
|
@ -274,6 +287,10 @@ free_v_must_defs (v_must_def_optype *v_must_defs)
|
|||
{
|
||||
if (*v_must_defs)
|
||||
{
|
||||
unsigned int x;
|
||||
v_must_def_optype v_must_def = *v_must_defs;
|
||||
for (x = 0; x < v_must_def->num_v_must_defs; x++)
|
||||
delink_imm_use (&(v_must_def->v_must_defs[x].imm_use));
|
||||
ggc_free (*v_must_defs);
|
||||
*v_must_defs = NULL;
|
||||
}
|
||||
|
@ -322,6 +339,62 @@ fini_ssa_operands (void)
|
|||
}
|
||||
}
|
||||
|
||||
/* Initialize V_USES index INDEX to VAL for STMT. If OLD is present, preserve
|
||||
the position of the may-def in the immediate_use list. */
|
||||
|
||||
static inline void
|
||||
initialize_vuse_operand (vuse_optype vuses, unsigned int index, tree val,
|
||||
tree stmt, ssa_imm_use_t *old)
|
||||
{
|
||||
vuse_operand_type_t *ptr;
|
||||
ptr = &(vuses->vuses[index]);
|
||||
ptr->use = val;
|
||||
ptr->imm_use.use = &(ptr->use);
|
||||
if (old)
|
||||
relink_imm_use_stmt (&(ptr->imm_use), old, stmt);
|
||||
else
|
||||
link_imm_use_stmt (&(ptr->imm_use), ptr->use, stmt);
|
||||
}
|
||||
|
||||
|
||||
/* Initialize V_MAY_DEF_OPS index X to be DEF = MAY_DEF <USE> for STMT. If
|
||||
OLD is present, preserve the position of the may-def in the immediate_use
|
||||
list. */
|
||||
|
||||
static inline void
|
||||
initialize_v_may_def_operand (v_may_def_optype v_may_def_ops, unsigned int x,
|
||||
tree def, tree use, tree stmt, ssa_imm_use_t *old)
|
||||
{
|
||||
v_def_use_operand_type_t *ptr;
|
||||
ptr = &(v_may_def_ops->v_may_defs[x]);
|
||||
ptr->def = def;
|
||||
ptr->use = use;
|
||||
ptr->imm_use.use = &(ptr->use);
|
||||
if (old)
|
||||
relink_imm_use_stmt (&(ptr->imm_use), old, stmt);
|
||||
else
|
||||
link_imm_use_stmt (&(ptr->imm_use), ptr->use, stmt);
|
||||
}
|
||||
|
||||
|
||||
/* Initialize V_MUST_DEF_OPS index X to be DEF = MUST_DEF <USE> for STMT. If
|
||||
OLD is present, preserve the position of the may-def in the immediate_use
|
||||
list. */
|
||||
|
||||
static inline void
|
||||
initialize_v_must_def_operand (v_must_def_optype v_must_def_ops, unsigned int x,
|
||||
tree def, tree use, tree stmt, ssa_imm_use_t *old)
|
||||
{
|
||||
v_def_use_operand_type_t *ptr;
|
||||
ptr = &(v_must_def_ops->v_must_defs[x]);
|
||||
ptr->def = def;
|
||||
ptr->use = use;
|
||||
ptr->imm_use.use = &(ptr->use);
|
||||
if (old)
|
||||
relink_imm_use_stmt (&(ptr->imm_use), old, stmt);
|
||||
else
|
||||
link_imm_use_stmt (&(ptr->imm_use), ptr->use, stmt);
|
||||
}
|
||||
|
||||
/* All the finalize_ssa_* routines do the work required to turn the build_
|
||||
VARRAY into an operand_vector of the appropriate type. The original vector,
|
||||
|
@ -332,7 +405,7 @@ fini_ssa_operands (void)
|
|||
/* Return a new def operand vector for STMT, comparing to OLD_OPS_P. */
|
||||
|
||||
static def_optype
|
||||
finalize_ssa_defs (def_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED)
|
||||
finalize_ssa_defs (def_optype *old_ops_p, tree stmt)
|
||||
{
|
||||
unsigned num, x;
|
||||
def_optype def_ops, old_ops;
|
||||
|
@ -343,13 +416,13 @@ finalize_ssa_defs (def_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED)
|
|||
return NULL;
|
||||
|
||||
/* There should only be a single real definition per assignment. */
|
||||
gcc_assert (TREE_CODE (stmt) != MODIFY_EXPR || num <= 1);
|
||||
gcc_assert ((stmt && TREE_CODE (stmt) != MODIFY_EXPR) || num <= 1);
|
||||
|
||||
old_ops = *old_ops_p;
|
||||
|
||||
/* Compare old vector and new array. */
|
||||
build_diff = true;
|
||||
if (old_ops && old_ops->num_defs == num)
|
||||
if (stmt && old_ops && old_ops->num_defs == num)
|
||||
{
|
||||
build_diff = false;
|
||||
for (x = 0; x < num; x++)
|
||||
|
@ -378,12 +451,45 @@ finalize_ssa_defs (def_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED)
|
|||
}
|
||||
|
||||
|
||||
/* Make sure PTR is inn the correct immediate use list. Since uses are simply
|
||||
pointers into the stmt TREE, there is no way of telling if anyone has
|
||||
changed what this pointer points to via TREE_OPERANDS (exp, 0) = <...>.
|
||||
THe contents are different, but the the pointer is still the same. This
|
||||
routine will check to make sure PTR is in the correct list, and if it isn't
|
||||
put it in the correct list. */
|
||||
|
||||
static inline void
|
||||
correct_use_link (ssa_imm_use_t *ptr, tree stmt)
|
||||
{
|
||||
ssa_imm_use_t *prev;
|
||||
tree root;
|
||||
|
||||
/* Fold_stmt () may have changed the stmt pointers. */
|
||||
if (ptr->stmt != stmt)
|
||||
ptr->stmt = stmt;
|
||||
|
||||
prev = ptr->prev;
|
||||
if (prev)
|
||||
{
|
||||
/* find the root, which has a non-NULL stmt, and a NULL use. */
|
||||
while (prev->stmt == NULL || prev->use != NULL)
|
||||
prev = prev->prev;
|
||||
root = prev->stmt;
|
||||
if (root == *(ptr->use))
|
||||
return;
|
||||
}
|
||||
/* Its in the wrong list if we reach here. */
|
||||
delink_imm_use (ptr);
|
||||
link_imm_use (ptr, *(ptr->use));
|
||||
}
|
||||
|
||||
|
||||
/* Return a new use operand vector for STMT, comparing to OLD_OPS_P. */
|
||||
|
||||
static use_optype
|
||||
finalize_ssa_uses (use_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED)
|
||||
finalize_ssa_uses (use_optype *old_ops_p, tree stmt)
|
||||
{
|
||||
unsigned num, x;
|
||||
unsigned num, x, num_old, i;
|
||||
use_optype use_ops, old_ops;
|
||||
bool build_diff;
|
||||
|
||||
|
@ -403,30 +509,53 @@ finalize_ssa_uses (use_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED)
|
|||
}
|
||||
#endif
|
||||
old_ops = *old_ops_p;
|
||||
num_old = ((stmt && old_ops) ? old_ops->num_uses : 0);
|
||||
|
||||
/* Check if the old vector and the new array are the same. */
|
||||
build_diff = true;
|
||||
if (old_ops && old_ops->num_uses == num)
|
||||
if (stmt && old_ops && num_old == num)
|
||||
{
|
||||
build_diff = false;
|
||||
for (x = 0; x < num; x++)
|
||||
if (old_ops->uses[x].use != VARRAY_TREE_PTR (build_uses, x))
|
||||
{
|
||||
build_diff = true;
|
||||
break;
|
||||
}
|
||||
{
|
||||
tree *var_p = VARRAY_TREE_PTR (build_uses, x);
|
||||
tree *node = old_ops->uses[x].use;
|
||||
/* Check the pointer values to see if they are the same. */
|
||||
if (node != var_p)
|
||||
{
|
||||
build_diff = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!build_diff)
|
||||
{
|
||||
use_ops = old_ops;
|
||||
*old_ops_p = NULL;
|
||||
for (i = 0; i < num_old; i++)
|
||||
correct_use_link (&(use_ops->uses[i]), stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
use_ops = allocate_use_optype (num);
|
||||
for (x = 0; x < num ; x++)
|
||||
use_ops->uses[x].use = VARRAY_TREE_PTR (build_uses, x);
|
||||
{
|
||||
tree *var = VARRAY_TREE_PTR (build_uses, x);
|
||||
use_ops->uses[x].use = var;
|
||||
for (i = 0; i < num_old; i++)
|
||||
{
|
||||
ssa_imm_use_t *ptr = &(old_ops->uses[i]);
|
||||
if (ptr->use == var)
|
||||
{
|
||||
relink_imm_use_stmt (&(use_ops->uses[x]), ptr, stmt);
|
||||
correct_use_link (&(use_ops->uses[x]), stmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == num_old)
|
||||
link_imm_use_stmt (&(use_ops->uses[x]), *var, stmt);
|
||||
}
|
||||
}
|
||||
VARRAY_POP_ALL (build_uses);
|
||||
|
||||
|
@ -437,7 +566,7 @@ finalize_ssa_uses (use_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED)
|
|||
/* Return a new v_may_def operand vector for STMT, comparing to OLD_OPS_P. */
|
||||
|
||||
static v_may_def_optype
|
||||
finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p)
|
||||
finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p, tree stmt)
|
||||
{
|
||||
unsigned num, x, i, old_num;
|
||||
v_may_def_optype v_may_def_ops, old_ops;
|
||||
|
@ -452,7 +581,7 @@ finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p)
|
|||
|
||||
/* Check if the old vector and the new array are the same. */
|
||||
build_diff = true;
|
||||
if (old_ops && old_ops->num_v_may_defs == num)
|
||||
if (stmt && old_ops && old_ops->num_v_may_defs == num)
|
||||
{
|
||||
old_num = num;
|
||||
build_diff = false;
|
||||
|
@ -475,6 +604,8 @@ finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p)
|
|||
{
|
||||
v_may_def_ops = old_ops;
|
||||
*old_ops_p = NULL;
|
||||
for (x = 0; x < num; x++)
|
||||
correct_use_link (&(v_may_def_ops->v_may_defs[x].imm_use), stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -490,14 +621,18 @@ finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p)
|
|||
result = SSA_NAME_VAR (result);
|
||||
if (result == var)
|
||||
{
|
||||
v_may_def_ops->v_may_defs[x] = old_ops->v_may_defs[i];
|
||||
initialize_v_may_def_operand (v_may_def_ops, x,
|
||||
old_ops->v_may_defs[i].def,
|
||||
old_ops->v_may_defs[i].use,
|
||||
stmt,
|
||||
&(old_ops->v_may_defs[i].imm_use));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == old_num)
|
||||
{
|
||||
v_may_def_ops->v_may_defs[x].def = var;
|
||||
v_may_def_ops->v_may_defs[x].use = var;
|
||||
initialize_v_may_def_operand (v_may_def_ops, x, var, var, stmt,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -528,7 +663,7 @@ cleanup_v_may_defs (void)
|
|||
/* Return a new vuse operand vector, comparing to OLD_OPS_P. */
|
||||
|
||||
static vuse_optype
|
||||
finalize_ssa_vuses (vuse_optype *old_ops_p)
|
||||
finalize_ssa_vuses (vuse_optype *old_ops_p, tree stmt)
|
||||
{
|
||||
unsigned num, x, i, num_v_may_defs, old_num;
|
||||
vuse_optype vuse_ops, old_ops;
|
||||
|
@ -613,14 +748,14 @@ finalize_ssa_vuses (vuse_optype *old_ops_p)
|
|||
|
||||
/* Determine whether vuses is the same as the old vector. */
|
||||
build_diff = true;
|
||||
if (old_ops && old_ops->num_vuses == num)
|
||||
if (stmt && old_ops && old_ops->num_vuses == num)
|
||||
{
|
||||
old_num = num;
|
||||
build_diff = false;
|
||||
for (x = 0; x < num ; x++)
|
||||
{
|
||||
tree v;
|
||||
v = old_ops->vuses[x];
|
||||
v = old_ops->vuses[x].use;
|
||||
if (TREE_CODE (v) == SSA_NAME)
|
||||
v = SSA_NAME_VAR (v);
|
||||
if (v != VARRAY_TREE (build_vuses, x))
|
||||
|
@ -637,6 +772,8 @@ finalize_ssa_vuses (vuse_optype *old_ops_p)
|
|||
{
|
||||
vuse_ops = old_ops;
|
||||
*old_ops_p = NULL;
|
||||
for (x = 0; x < num; x++)
|
||||
correct_use_link (&(vuse_ops->vuses[x].imm_use), stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -647,17 +784,18 @@ finalize_ssa_vuses (vuse_optype *old_ops_p)
|
|||
/* Look for VAR in the old vector, and use that SSA_NAME. */
|
||||
for (i = 0; i < old_num; i++)
|
||||
{
|
||||
result = old_ops->vuses[i];
|
||||
result = old_ops->vuses[i].use;
|
||||
if (TREE_CODE (result) == SSA_NAME)
|
||||
result = SSA_NAME_VAR (result);
|
||||
if (result == var)
|
||||
{
|
||||
vuse_ops->vuses[x] = old_ops->vuses[i];
|
||||
initialize_vuse_operand (vuse_ops, x, old_ops->vuses[i].use,
|
||||
stmt, &(old_ops->vuses[i].imm_use));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == old_num)
|
||||
vuse_ops->vuses[x] = var;
|
||||
initialize_vuse_operand (vuse_ops, x, var, stmt, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -672,11 +810,11 @@ finalize_ssa_vuses (vuse_optype *old_ops_p)
|
|||
/* Return a new v_must_def operand vector for STMT, comparing to OLD_OPS_P. */
|
||||
|
||||
static v_must_def_optype
|
||||
finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p,
|
||||
tree stmt ATTRIBUTE_UNUSED)
|
||||
finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p, tree stmt)
|
||||
{
|
||||
unsigned num, x, i, old_num = 0;
|
||||
v_must_def_optype v_must_def_ops, old_ops;
|
||||
tree result, var;
|
||||
bool build_diff;
|
||||
|
||||
num = VARRAY_ACTIVE_SIZE (build_v_must_defs);
|
||||
|
@ -694,7 +832,7 @@ finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p,
|
|||
|
||||
/* Check if the old vector and the new array are the same. */
|
||||
build_diff = true;
|
||||
if (old_ops && old_ops->num_v_must_defs == num)
|
||||
if (stmt && old_ops && old_ops->num_v_must_defs == num)
|
||||
{
|
||||
old_num = num;
|
||||
build_diff = false;
|
||||
|
@ -717,13 +855,15 @@ finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p,
|
|||
{
|
||||
v_must_def_ops = old_ops;
|
||||
*old_ops_p = NULL;
|
||||
for (x = 0; x < num; x++)
|
||||
correct_use_link (&(v_must_def_ops->v_must_defs[x].imm_use), stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
v_must_def_ops = allocate_v_must_def_optype (num);
|
||||
for (x = 0; x < num ; x++)
|
||||
{
|
||||
tree result, var = VARRAY_TREE (build_v_must_defs, x);
|
||||
var = VARRAY_TREE (build_v_must_defs, x);
|
||||
/* Look for VAR in the original vector. */
|
||||
for (i = 0; i < old_num; i++)
|
||||
{
|
||||
|
@ -732,15 +872,18 @@ finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p,
|
|||
result = SSA_NAME_VAR (result);
|
||||
if (result == var)
|
||||
{
|
||||
v_must_def_ops->v_must_defs[x].def = old_ops->v_must_defs[i].def;
|
||||
v_must_def_ops->v_must_defs[x].use = old_ops->v_must_defs[i].use;
|
||||
initialize_v_must_def_operand (v_must_def_ops, x,
|
||||
old_ops->v_must_defs[i].def,
|
||||
old_ops->v_must_defs[i].use,
|
||||
stmt,
|
||||
&(old_ops->v_must_defs[i].imm_use));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == old_num)
|
||||
{
|
||||
v_must_def_ops->v_must_defs[x].def = var;
|
||||
v_must_def_ops->v_must_defs[x].use = var;
|
||||
initialize_v_must_def_operand (v_must_def_ops, x, var, var, stmt,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -760,8 +903,9 @@ finalize_ssa_stmt_operands (tree stmt, stmt_operands_p old_ops,
|
|||
new_ops->use_ops = finalize_ssa_uses (&(old_ops->use_ops), stmt);
|
||||
new_ops->v_must_def_ops
|
||||
= finalize_ssa_v_must_defs (&(old_ops->v_must_def_ops), stmt);
|
||||
new_ops->v_may_def_ops = finalize_ssa_v_may_defs (&(old_ops->v_may_def_ops));
|
||||
new_ops->vuse_ops = finalize_ssa_vuses (&(old_ops->vuse_ops));
|
||||
new_ops->v_may_def_ops
|
||||
= finalize_ssa_v_may_defs (&(old_ops->v_may_def_ops), stmt);
|
||||
new_ops->vuse_ops = finalize_ssa_vuses (&(old_ops->vuse_ops), stmt);
|
||||
}
|
||||
|
||||
|
||||
|
@ -847,46 +991,15 @@ append_v_must_def (tree var)
|
|||
VARRAY_PUSH_TREE (build_v_must_defs, var);
|
||||
}
|
||||
|
||||
/* Create an operands cache for STMT, returning it in NEW_OPS. OLD_OPS are the
|
||||
original operands, and if ANN is non-null, appropriate stmt flags are set
|
||||
in the stmt's annotation. Note that some fields in old_ops may
|
||||
change to NULL, although none of the memory they originally pointed to
|
||||
will be destroyed. It is appropriate to call free_stmt_operands() on
|
||||
the value returned in old_ops.
|
||||
|
||||
The rationale for this: Certain optimizations wish to examine the difference
|
||||
between new_ops and old_ops after processing. If a set of operands don't
|
||||
change, new_ops will simply assume the pointer in old_ops, and the old_ops
|
||||
pointer will be set to NULL, indicating no memory needs to be cleared.
|
||||
Usage might appear something like:
|
||||
|
||||
old_ops_copy = old_ops = stmt_ann(stmt)->operands;
|
||||
build_ssa_operands (stmt, NULL, &old_ops, &new_ops);
|
||||
<* compare old_ops_copy and new_ops *>
|
||||
free_ssa_operands (old_ops); */
|
||||
|
||||
/* Parse STMT looking for operands. OLD_OPS is the original stmt operand
|
||||
cache for STMT, if it exested before. When fniished, the various build_*
|
||||
operand vectors will have potential operands. in them. */
|
||||
|
||||
static void
|
||||
build_ssa_operands (tree stmt, stmt_ann_t ann, stmt_operands_p old_ops,
|
||||
stmt_operands_p new_ops)
|
||||
parse_ssa_operands (tree stmt)
|
||||
{
|
||||
enum tree_code code;
|
||||
tree_ann_t saved_ann = stmt->common.ann;
|
||||
|
||||
/* Replace stmt's annotation with the one passed in for the duration
|
||||
of the operand building process. This allows "fake" stmts to be built
|
||||
and not be included in other data structures which can be built here. */
|
||||
stmt->common.ann = (tree_ann_t) ann;
|
||||
|
||||
/* Initially assume that the statement has no volatile operands, nor
|
||||
makes aliased loads or stores. */
|
||||
if (ann)
|
||||
{
|
||||
ann->has_volatile_ops = false;
|
||||
ann->makes_aliased_stores = false;
|
||||
ann->makes_aliased_loads = false;
|
||||
}
|
||||
|
||||
start_ssa_stmt_operands ();
|
||||
|
||||
code = TREE_CODE (stmt);
|
||||
switch (code)
|
||||
|
@ -963,8 +1076,62 @@ build_ssa_operands (tree stmt, stmt_ann_t ann, stmt_operands_p old_ops,
|
|||
get_expr_operands (stmt, &stmt, opf_none);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
finalize_ssa_stmt_operands (stmt, old_ops, new_ops);
|
||||
/* Create an operands cache for STMT, returning it in NEW_OPS. OLD_OPS are the
|
||||
original operands, and if ANN is non-null, appropriate stmt flags are set
|
||||
in the stmt's annotation. If ANN is NULL, this is not considered a "real"
|
||||
stmt, and none of the operands will be entered into their respective
|
||||
immediate uses tables. This is to allow stmts to be processed when they
|
||||
are not actually in the CFG.
|
||||
|
||||
Note that some fields in old_ops may change to NULL, although none of the
|
||||
memory they originally pointed to will be destroyed. It is appropriate
|
||||
to call free_stmt_operands() on the value returned in old_ops.
|
||||
|
||||
The rationale for this: Certain optimizations wish to examine the difference
|
||||
between new_ops and old_ops after processing. If a set of operands don't
|
||||
change, new_ops will simply assume the pointer in old_ops, and the old_ops
|
||||
pointer will be set to NULL, indicating no memory needs to be cleared.
|
||||
Usage might appear something like:
|
||||
|
||||
old_ops_copy = old_ops = stmt_ann(stmt)->operands;
|
||||
build_ssa_operands (stmt, NULL, &old_ops, &new_ops);
|
||||
<* compare old_ops_copy and new_ops *>
|
||||
free_ssa_operands (old_ops); */
|
||||
|
||||
static void
|
||||
build_ssa_operands (tree stmt, stmt_ann_t ann, stmt_operands_p old_ops,
|
||||
stmt_operands_p new_ops)
|
||||
{
|
||||
tree_ann_t saved_ann = stmt->common.ann;
|
||||
|
||||
/* Replace stmt's annotation with the one passed in for the duration
|
||||
of the operand building process. This allows "fake" stmts to be built
|
||||
and not be included in other data structures which can be built here. */
|
||||
stmt->common.ann = (tree_ann_t) ann;
|
||||
|
||||
parse_old_ops = old_ops;
|
||||
|
||||
/* Initially assume that the statement has no volatile operands, nor
|
||||
makes aliased loads or stores. */
|
||||
if (ann)
|
||||
{
|
||||
ann->has_volatile_ops = false;
|
||||
ann->makes_aliased_stores = false;
|
||||
ann->makes_aliased_loads = false;
|
||||
}
|
||||
|
||||
start_ssa_stmt_operands ();
|
||||
|
||||
parse_ssa_operands (stmt);
|
||||
|
||||
parse_old_ops = NULL;
|
||||
|
||||
if (ann)
|
||||
finalize_ssa_stmt_operands (stmt, old_ops, new_ops);
|
||||
else
|
||||
finalize_ssa_stmt_operands (NULL, old_ops, new_ops);
|
||||
stmt->common.ann = saved_ann;
|
||||
}
|
||||
|
||||
|
@ -987,25 +1154,73 @@ free_ssa_operands (stmt_operands_p ops)
|
|||
}
|
||||
|
||||
|
||||
/* Swap operands EXP0 and EXP1 in STMT. */
|
||||
|
||||
static void
|
||||
swap_tree_operands (tree *exp0, tree *exp1)
|
||||
{
|
||||
tree op0, op1;
|
||||
op0 = *exp0;
|
||||
op1 = *exp1;
|
||||
|
||||
/* If the operand cache is active, attempt to preserve the relative positions
|
||||
of these two operands in their respective immediate use lists. */
|
||||
if (build_defs != NULL && op0 != op1 && parse_old_ops != NULL)
|
||||
{
|
||||
unsigned x, use0, use1;
|
||||
use_optype uses = parse_old_ops->use_ops;
|
||||
use0 = use1 = NUM_USES (uses);
|
||||
/* Find the 2 operands in the cache, if they are there. */
|
||||
for (x = 0; x < NUM_USES (uses); x++)
|
||||
if (USE_OP_PTR (uses, x)->use == exp0)
|
||||
{
|
||||
use0 = x;
|
||||
break;
|
||||
}
|
||||
for (x = 0; x < NUM_USES (uses); x++)
|
||||
if (USE_OP_PTR (uses, x)->use == exp1)
|
||||
{
|
||||
use1 = x;
|
||||
break;
|
||||
}
|
||||
/* If both uses don't have operand entries, there isnt much we can do
|
||||
at this point. Presumably we dont need to worry about it. */
|
||||
if (use0 != NUM_USES (uses) && use1 != NUM_USES (uses))
|
||||
{
|
||||
tree *tmp = USE_OP_PTR (uses, use1)->use;
|
||||
gcc_assert (use0 != use1);
|
||||
|
||||
USE_OP_PTR (uses, use1)->use = USE_OP_PTR (uses, use0)->use;
|
||||
USE_OP_PTR (uses, use0)->use = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now swap the data. */
|
||||
*exp0 = op1;
|
||||
*exp1 = op0;
|
||||
}
|
||||
|
||||
/* Get the operands of statement STMT. Note that repeated calls to
|
||||
get_stmt_operands for the same statement will do nothing until the
|
||||
statement is marked modified by a call to modify_stmt(). */
|
||||
statement is marked modified by a call to mark_stmt_modified(). */
|
||||
|
||||
void
|
||||
get_stmt_operands (tree stmt)
|
||||
update_stmt_operands (tree stmt)
|
||||
{
|
||||
stmt_ann_t ann;
|
||||
stmt_operands_t old_operands;
|
||||
|
||||
/* If get_stmt_operands is called before SSA is initialized, dont
|
||||
do anything. */
|
||||
if (build_defs == NULL)
|
||||
return;
|
||||
/* The optimizers cannot handle statements that are nothing but a
|
||||
_DECL. This indicates a bug in the gimplifier. */
|
||||
gcc_assert (!SSA_VAR_P (stmt));
|
||||
|
||||
ann = get_stmt_ann (stmt);
|
||||
|
||||
/* If the statement has not been modified, the operands are still valid. */
|
||||
if (!ann->modified)
|
||||
return;
|
||||
gcc_assert (ann->modified);
|
||||
|
||||
timevar_push (TV_TREE_OPS);
|
||||
|
||||
|
@ -1017,7 +1232,7 @@ get_stmt_operands (tree stmt)
|
|||
|
||||
/* Clear the modified bit for STMT. Subsequent calls to
|
||||
get_stmt_operands for this statement will do nothing until the
|
||||
statement is marked modified by a call to modify_stmt(). */
|
||||
statement is marked modified by a call to mark_stmt_modified(). */
|
||||
ann->modified = 0;
|
||||
|
||||
timevar_pop (TV_TREE_OPS);
|
||||
|
@ -1239,15 +1454,15 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
|
|||
|| code == GE_EXPR)
|
||||
{
|
||||
TREE_SET_CODE (expr, swap_tree_comparison (code));
|
||||
TREE_OPERAND (expr, 0) = op1;
|
||||
TREE_OPERAND (expr, 1) = op0;
|
||||
swap_tree_operands (&TREE_OPERAND (expr, 0),
|
||||
&TREE_OPERAND (expr, 1));
|
||||
}
|
||||
|
||||
/* For a commutative operator we can just swap the operands. */
|
||||
else if (commutative_tree_code (code))
|
||||
{
|
||||
TREE_OPERAND (expr, 0) = op1;
|
||||
TREE_OPERAND (expr, 1) = op0;
|
||||
swap_tree_operands (&TREE_OPERAND (expr, 0),
|
||||
&TREE_OPERAND (expr, 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1884,7 +2099,7 @@ copy_virtual_operands (tree dst, tree src)
|
|||
{
|
||||
*vuses_new = allocate_vuse_optype (NUM_VUSES (vuses));
|
||||
for (i = 0; i < NUM_VUSES (vuses); i++)
|
||||
SET_VUSE_OP (*vuses_new, i, VUSE_OP (vuses, i));
|
||||
initialize_vuse_operand (*vuses_new, i, VUSE_OP (vuses, i), dst, NULL);
|
||||
}
|
||||
|
||||
if (v_may_defs)
|
||||
|
@ -1892,19 +2107,23 @@ copy_virtual_operands (tree dst, tree src)
|
|||
*v_may_defs_new = allocate_v_may_def_optype (NUM_V_MAY_DEFS (v_may_defs));
|
||||
for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
|
||||
{
|
||||
SET_V_MAY_DEF_OP (*v_may_defs_new, i, V_MAY_DEF_OP (v_may_defs, i));
|
||||
SET_V_MAY_DEF_RESULT (*v_may_defs_new, i,
|
||||
V_MAY_DEF_RESULT (v_may_defs, i));
|
||||
initialize_v_may_def_operand (*v_may_defs_new, i,
|
||||
V_MAY_DEF_RESULT (v_may_defs, i),
|
||||
V_MAY_DEF_OP (v_may_defs, i), dst,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (v_must_defs)
|
||||
{
|
||||
*v_must_defs_new = allocate_v_must_def_optype (NUM_V_MUST_DEFS (v_must_defs));
|
||||
*v_must_defs_new
|
||||
= allocate_v_must_def_optype (NUM_V_MUST_DEFS (v_must_defs));
|
||||
for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
|
||||
{
|
||||
SET_V_MUST_DEF_RESULT (*v_must_defs_new, i, V_MUST_DEF_RESULT (v_must_defs, i));
|
||||
SET_V_MUST_DEF_KILL (*v_must_defs_new, i, V_MUST_DEF_KILL (v_must_defs, i));
|
||||
initialize_v_must_def_operand (*v_must_defs_new, i,
|
||||
V_MUST_DEF_RESULT (v_must_defs, i),
|
||||
V_MUST_DEF_KILL (v_must_defs, i), dst,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1951,7 +2170,173 @@ create_ssa_artficial_load_stmt (stmt_operands_p old_ops, tree new_stmt)
|
|||
}
|
||||
|
||||
/* Now set the vuses for this new stmt. */
|
||||
ann->operands.vuse_ops = finalize_ssa_vuses (&(tmp.vuse_ops));
|
||||
ann->operands.vuse_ops = finalize_ssa_vuses (&(tmp.vuse_ops), NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Issue immediate use error for VAR to debug file F. */
|
||||
static void
|
||||
verify_abort (FILE *f, ssa_imm_use_t *var)
|
||||
{
|
||||
tree stmt;
|
||||
stmt = var->stmt;
|
||||
if (stmt)
|
||||
{
|
||||
if (stmt_modified_p(stmt))
|
||||
{
|
||||
fprintf (f, " STMT MODIFIED. - <0x%x> ", (unsigned int)stmt);
|
||||
print_generic_stmt (f, stmt, TDF_SLIM);
|
||||
}
|
||||
}
|
||||
fprintf (f, " IMM ERROR : (use_p : tree: 0x%X:0x%x)", (unsigned int)var,
|
||||
(unsigned int)var->use);
|
||||
print_generic_expr (f, USE_FROM_PTR (var), TDF_SLIM);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
|
||||
/* Scan the immediate_use list for VAR making sure its linked properly.
|
||||
return RTUE iof there is a problem. */
|
||||
|
||||
bool
|
||||
verify_imm_links (FILE *f, tree var)
|
||||
{
|
||||
ssa_imm_use_t *ptr, *prev;
|
||||
ssa_imm_use_t *list;
|
||||
int count;
|
||||
|
||||
gcc_assert (TREE_CODE (var) == SSA_NAME);
|
||||
|
||||
list = &(SSA_NAME_IMM_USE_NODE (var));
|
||||
gcc_assert (list->use == NULL);
|
||||
|
||||
if (list->prev == NULL)
|
||||
{
|
||||
gcc_assert (list->next == NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
prev = list;
|
||||
count = 0;
|
||||
for (ptr = list->next; ptr != list; )
|
||||
{
|
||||
if (prev != ptr->prev)
|
||||
{
|
||||
verify_abort (f, ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ptr->use == NULL)
|
||||
{
|
||||
verify_abort (f, ptr); /* 2 roots, or SAFE guard node. */
|
||||
return true;
|
||||
}
|
||||
else
|
||||
if (*(ptr->use) != var)
|
||||
{
|
||||
verify_abort (f, ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
/* Avoid infinite loops. */
|
||||
if (count++ > 30000)
|
||||
{
|
||||
verify_abort (f, ptr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify list in the other direction. */
|
||||
prev = list;
|
||||
for (ptr = list->prev; ptr != list; )
|
||||
{
|
||||
if (prev != ptr->next)
|
||||
{
|
||||
verify_abort (f, ptr);
|
||||
return true;
|
||||
}
|
||||
prev = ptr;
|
||||
ptr = ptr->prev;
|
||||
if (count-- < 0)
|
||||
{
|
||||
verify_abort (f, ptr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
verify_abort (f, ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Dump all the immediate uses to FILE. */
|
||||
|
||||
void
|
||||
dump_immediate_uses_for (FILE *file, tree var)
|
||||
{
|
||||
imm_use_iterator iter;
|
||||
use_operand_p use_p;
|
||||
|
||||
gcc_assert (var && TREE_CODE (var) == SSA_NAME);
|
||||
|
||||
print_generic_expr (file, var, TDF_SLIM);
|
||||
fprintf (file, " : -->");
|
||||
if (has_zero_uses (var))
|
||||
fprintf (file, " no uses.\n");
|
||||
else
|
||||
if (has_single_use (var))
|
||||
fprintf (file, " single use.\n");
|
||||
else
|
||||
fprintf (file, "%d uses.\n", num_imm_uses (var));
|
||||
|
||||
FOR_EACH_IMM_USE_FAST (use_p, iter, var)
|
||||
{
|
||||
print_generic_stmt (file, USE_STMT (use_p), TDF_SLIM);
|
||||
}
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
||||
/* Dump all the immediate uses to FILE. */
|
||||
|
||||
void
|
||||
dump_immediate_uses (FILE *file)
|
||||
{
|
||||
tree var;
|
||||
unsigned int x;
|
||||
|
||||
fprintf (file, "Immediate_uses: \n\n");
|
||||
for (x = 1; x < num_ssa_names; x++)
|
||||
{
|
||||
var = ssa_name(x);
|
||||
if (!var)
|
||||
continue;
|
||||
dump_immediate_uses_for (file, var);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Dump def-use edges on stderr. */
|
||||
|
||||
void
|
||||
debug_immediate_uses (void)
|
||||
{
|
||||
dump_immediate_uses (stderr);
|
||||
}
|
||||
|
||||
/* Dump def-use edges on stderr. */
|
||||
|
||||
void
|
||||
debug_immediate_uses_for (tree var)
|
||||
{
|
||||
dump_immediate_uses_for (stderr, var);
|
||||
}
|
||||
|
||||
#include "gt-tree-ssa-operands.h"
|
||||
|
|
|
@ -31,13 +31,10 @@ typedef struct def_operand_ptr GTY(())
|
|||
} def_operand_p;
|
||||
|
||||
/* This represents a pointer to a USE operand. */
|
||||
typedef struct use_operand_ptr GTY(())
|
||||
{
|
||||
tree * GTY((skip(""))) use;
|
||||
} use_operand_p;
|
||||
typedef ssa_imm_use_t *use_operand_p;
|
||||
|
||||
#define NULL_USE_OPERAND_P NULL
|
||||
extern def_operand_p NULL_DEF_OPERAND_P;
|
||||
extern use_operand_p NULL_USE_OPERAND_P;
|
||||
|
||||
/* This represents the DEF operands of a stmt. */
|
||||
typedef struct def_optype_d GTY(())
|
||||
|
@ -48,20 +45,24 @@ typedef struct def_optype_d GTY(())
|
|||
|
||||
typedef def_optype_t *def_optype;
|
||||
|
||||
/* Operand type which uses a pointer to a tree ihn an immediate use. */
|
||||
typedef ssa_imm_use_t use_operand_type_t;
|
||||
|
||||
/* This represents the USE operands of a stmt. */
|
||||
typedef struct use_optype_d GTY(())
|
||||
{
|
||||
unsigned num_uses;
|
||||
struct use_operand_ptr GTY((length("%h.num_uses"))) uses[1];
|
||||
struct ssa_imm_use_d GTY((length("%h.num_uses"))) uses[1];
|
||||
} use_optype_t;
|
||||
|
||||
typedef use_optype_t *use_optype;
|
||||
|
||||
/* Operand type which stores a def and a use tree. */
|
||||
/* Operand type which stores a def a use, and an immediate use. */
|
||||
typedef struct v_def_use_operand_type GTY(())
|
||||
{
|
||||
tree def;
|
||||
tree use;
|
||||
ssa_imm_use_t imm_use;
|
||||
} v_def_use_operand_type_t;
|
||||
|
||||
/* This represents the MAY_DEFS for a stmt. */
|
||||
|
@ -74,11 +75,18 @@ typedef struct v_may_def_optype_d GTY(())
|
|||
|
||||
typedef v_may_def_optype_t *v_may_def_optype;
|
||||
|
||||
/* Operand type which stores a tree and an immeidate_use. */
|
||||
typedef struct vuse_operand_type GTY(())
|
||||
{
|
||||
tree use;
|
||||
ssa_imm_use_t imm_use;
|
||||
} vuse_operand_type_t;
|
||||
|
||||
/* This represents the VUSEs for a stmt. */
|
||||
typedef struct vuse_optype_d GTY(())
|
||||
{
|
||||
unsigned num_vuses;
|
||||
tree GTY((length ("%h.num_vuses"))) vuses[1];
|
||||
struct vuse_operand_type GTY((length ("%h.num_vuses"))) vuses[1];
|
||||
} vuse_optype_t;
|
||||
|
||||
typedef vuse_optype_t *vuse_optype;
|
||||
|
@ -109,9 +117,10 @@ typedef stmt_operands_t *stmt_operands_p;
|
|||
|
||||
#define USE_FROM_PTR(OP) get_use_from_ptr (OP)
|
||||
#define DEF_FROM_PTR(OP) get_def_from_ptr (OP)
|
||||
#define SET_USE(OP, V) ((*((OP).use)) = (V))
|
||||
#define SET_USE(OP, V) set_ssa_use_from_ptr (OP, V)
|
||||
#define SET_DEF(OP, V) ((*((OP).def)) = (V))
|
||||
|
||||
#define USE_STMT(OP) (OP)->stmt
|
||||
|
||||
#define USE_OPS(ANN) get_use_ops (ANN)
|
||||
#define STMT_USE_OPS(STMT) get_use_ops (stmt_ann (STMT))
|
||||
|
@ -178,14 +187,22 @@ typedef stmt_operands_t *stmt_operands_p;
|
|||
PHI_ARG_DEF ((PHI), (E)->dest_idx)
|
||||
#define PHI_ARG_DEF_PTR_FROM_EDGE(PHI, E) \
|
||||
PHI_ARG_DEF_PTR ((PHI), (E)->dest_idx)
|
||||
#define PHI_ARG_INDEX_FROM_USE(USE) phi_arg_index_from_use (USE)
|
||||
|
||||
|
||||
extern void init_ssa_operands (void);
|
||||
extern void fini_ssa_operands (void);
|
||||
extern void get_stmt_operands (tree);
|
||||
extern void update_stmt_operands (tree);
|
||||
extern bool verify_imm_links (FILE *f, tree var);
|
||||
|
||||
extern void copy_virtual_operands (tree, tree);
|
||||
extern void create_ssa_artficial_load_stmt (stmt_operands_p, tree);
|
||||
|
||||
extern void dump_immediate_uses (FILE *file);
|
||||
extern void dump_immediate_uses_for (FILE *file, tree var);
|
||||
extern void debug_immediate_uses (void);
|
||||
extern void debug_immediate_uses_for (tree var);
|
||||
|
||||
extern bool ssa_call_clobbered_cache_valid;
|
||||
extern bool ssa_ro_call_cache_valid;
|
||||
|
||||
|
|
|
@ -313,7 +313,7 @@ replace_phi_edge_with_variable (basic_block cond_block, basic_block bb,
|
|||
block_stmt_iterator bsi;
|
||||
|
||||
/* Change the PHI argument to new. */
|
||||
PHI_ARG_DEF_TREE (phi, e->dest_idx) = new;
|
||||
SET_USE (PHI_ARG_DEF_PTR (phi, e->dest_idx), new);
|
||||
|
||||
/* Remove the empty basic block. */
|
||||
if (EDGE_SUCC (cond_block, 0)->dest == bb)
|
||||
|
|
|
@ -2056,7 +2056,7 @@ eliminate (void)
|
|||
NECESSARY (SSA_NAME_DEF_STMT (sprime)) = 1;
|
||||
pre_stats.eliminations++;
|
||||
propagate_tree_value (rhs_p, sprime);
|
||||
modify_stmt (stmt);
|
||||
update_stmt (stmt);
|
||||
|
||||
/* If we removed EH side effects from the statement, clean
|
||||
its EH information. */
|
||||
|
|
|
@ -232,14 +232,12 @@ cfg_blocks_get (void)
|
|||
static void
|
||||
add_ssa_edge (tree var, bool is_varying)
|
||||
{
|
||||
tree stmt = SSA_NAME_DEF_STMT (var);
|
||||
dataflow_t df = get_immediate_uses (stmt);
|
||||
int num_uses = num_immediate_uses (df);
|
||||
int i;
|
||||
imm_use_iterator iter;
|
||||
use_operand_p use_p;
|
||||
|
||||
for (i = 0; i < num_uses; i++)
|
||||
FOR_EACH_IMM_USE_FAST (use_p, iter, var)
|
||||
{
|
||||
tree use_stmt = immediate_use (df, i);
|
||||
tree use_stmt = USE_STMT (use_p);
|
||||
|
||||
if (!DONT_SIMULATE_AGAIN (use_stmt)
|
||||
&& !STMT_IN_SSA_EDGE_WORKLIST (use_stmt))
|
||||
|
@ -507,7 +505,6 @@ ssa_prop_fini (void)
|
|||
cfg_blocks = NULL;
|
||||
sbitmap_free (bb_in_list);
|
||||
sbitmap_free (executable_blocks);
|
||||
free_df ();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -109,21 +109,26 @@ find_bb_for_arg (tree phi, tree def)
|
|||
used in, so that you only have one place you can sink it to. */
|
||||
|
||||
static bool
|
||||
all_immediate_uses_same_place (dataflow_t imm)
|
||||
all_immediate_uses_same_place (tree stmt)
|
||||
{
|
||||
int i;
|
||||
tree firstuse;
|
||||
tree firstuse = NULL_TREE;
|
||||
ssa_op_iter op_iter;
|
||||
imm_use_iterator imm_iter;
|
||||
use_operand_p use_p;
|
||||
tree var;
|
||||
|
||||
if (imm == NULL || num_immediate_uses (imm) < 2)
|
||||
return true;
|
||||
firstuse = immediate_use (imm, 0);
|
||||
|
||||
for (i = 1; i < num_immediate_uses (imm); i++)
|
||||
FOR_EACH_SSA_TREE_OPERAND (var, stmt, op_iter, SSA_OP_ALL_DEFS)
|
||||
{
|
||||
tree immuse = immediate_use (imm, i);
|
||||
if (immuse != firstuse)
|
||||
return false;
|
||||
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
|
||||
{
|
||||
if (firstuse == NULL_TREE)
|
||||
firstuse = USE_STMT (use_p);
|
||||
else
|
||||
if (firstuse != USE_STMT (use_p))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -215,24 +220,43 @@ is_hidden_global_store (tree stmt)
|
|||
/* Find the nearest common dominator of all of the immediate uses in IMM. */
|
||||
|
||||
static basic_block
|
||||
nearest_common_dominator_of_uses (dataflow_t imm)
|
||||
nearest_common_dominator_of_uses (tree stmt)
|
||||
{
|
||||
bitmap blocks = BITMAP_ALLOC (NULL);
|
||||
basic_block commondom;
|
||||
int i;
|
||||
unsigned int j;
|
||||
bitmap_iterator bi;
|
||||
ssa_op_iter op_iter;
|
||||
imm_use_iterator imm_iter;
|
||||
use_operand_p use_p;
|
||||
tree var;
|
||||
|
||||
bitmap_clear (blocks);
|
||||
for (i = 0; i < num_immediate_uses (imm); i++)
|
||||
FOR_EACH_SSA_TREE_OPERAND (var, stmt, op_iter, SSA_OP_ALL_DEFS)
|
||||
{
|
||||
tree usestmt = immediate_use (imm, i);
|
||||
basic_block useblock;
|
||||
if (TREE_CODE (usestmt) == PHI_NODE)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < PHI_NUM_ARGS (usestmt); j++)
|
||||
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
|
||||
{
|
||||
tree usestmt = USE_STMT (use_p);
|
||||
basic_block useblock;
|
||||
if (TREE_CODE (usestmt) == PHI_NODE)
|
||||
{
|
||||
useblock = PHI_ARG_EDGE (usestmt, j)->src;
|
||||
int j;
|
||||
for (j = 0; j < PHI_NUM_ARGS (usestmt); j++)
|
||||
{
|
||||
useblock = PHI_ARG_EDGE (usestmt, j)->src;
|
||||
/* Short circuit. Nothing dominates the entry block. */
|
||||
if (useblock == ENTRY_BLOCK_PTR)
|
||||
{
|
||||
BITMAP_FREE (blocks);
|
||||
return NULL;
|
||||
}
|
||||
bitmap_set_bit (blocks, useblock->index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
useblock = bb_for_stmt (usestmt);
|
||||
|
||||
/* Short circuit. Nothing dominates the entry block. */
|
||||
if (useblock == ENTRY_BLOCK_PTR)
|
||||
{
|
||||
|
@ -242,18 +266,6 @@ nearest_common_dominator_of_uses (dataflow_t imm)
|
|||
bitmap_set_bit (blocks, useblock->index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
useblock = bb_for_stmt (usestmt);
|
||||
|
||||
/* Short circuit. Nothing dominates the entry block. */
|
||||
if (useblock == ENTRY_BLOCK_PTR)
|
||||
{
|
||||
BITMAP_FREE (blocks);
|
||||
return NULL;
|
||||
}
|
||||
bitmap_set_bit (blocks, useblock->index);
|
||||
}
|
||||
}
|
||||
commondom = BASIC_BLOCK (bitmap_first_set_bit (blocks));
|
||||
EXECUTE_IF_SET_IN_BITMAP (blocks, 0, j, bi)
|
||||
|
@ -271,16 +283,28 @@ nearest_common_dominator_of_uses (dataflow_t imm)
|
|||
static tree
|
||||
statement_sink_location (tree stmt, basic_block frombb)
|
||||
{
|
||||
dataflow_t imm = get_immediate_uses (stmt);
|
||||
tree use, def;
|
||||
use_operand_p one_use = NULL_USE_OPERAND_P;
|
||||
basic_block sinkbb;
|
||||
use_operand_p use_p;
|
||||
def_operand_p def_p;
|
||||
ssa_op_iter iter;
|
||||
stmt_ann_t ann;
|
||||
tree rhs;
|
||||
imm_use_iterator imm_iter;
|
||||
|
||||
if (imm == NULL)
|
||||
FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
|
||||
{
|
||||
FOR_EACH_IMM_USE_FAST (one_use, imm_iter, def)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (one_use != NULL_USE_OPERAND_P)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return if there are no immediate uses of this stmt. */
|
||||
if (one_use == NULL_USE_OPERAND_P)
|
||||
return NULL;
|
||||
|
||||
if (TREE_CODE (stmt) != MODIFY_EXPR)
|
||||
|
@ -314,8 +338,7 @@ statement_sink_location (tree stmt, basic_block frombb)
|
|||
|| TREE_CODE (rhs) == EXC_PTR_EXPR
|
||||
|| TREE_CODE (rhs) == FILTER_EXPR
|
||||
|| is_hidden_global_store (stmt)
|
||||
|| ann->has_volatile_ops
|
||||
|| num_immediate_uses (imm) == 0)
|
||||
|| ann->has_volatile_ops)
|
||||
return NULL;
|
||||
|
||||
FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_ALL_DEFS)
|
||||
|
@ -337,9 +360,9 @@ statement_sink_location (tree stmt, basic_block frombb)
|
|||
common dominator of all the immediate uses. For PHI nodes, we have to
|
||||
find the nearest common dominator of all of the predecessor blocks, since
|
||||
that is where insertion would have to take place. */
|
||||
if (!all_immediate_uses_same_place (imm))
|
||||
if (!all_immediate_uses_same_place (stmt))
|
||||
{
|
||||
basic_block commondom = nearest_common_dominator_of_uses (imm);
|
||||
basic_block commondom = nearest_common_dominator_of_uses (stmt);
|
||||
|
||||
if (commondom == frombb)
|
||||
return NULL;
|
||||
|
@ -371,7 +394,7 @@ statement_sink_location (tree stmt, basic_block frombb)
|
|||
return first_stmt (commondom);
|
||||
}
|
||||
|
||||
use = immediate_use (imm, 0);
|
||||
use = USE_STMT (one_use);
|
||||
if (TREE_CODE (use) != PHI_NODE)
|
||||
{
|
||||
sinkbb = bb_for_stmt (use);
|
||||
|
@ -527,13 +550,11 @@ execute_sink_code (void)
|
|||
connect_infinite_loops_to_exit ();
|
||||
memset (&sink_stats, 0, sizeof (sink_stats));
|
||||
calculate_dominance_info (CDI_DOMINATORS | CDI_POST_DOMINATORS);
|
||||
compute_immediate_uses (TDFA_USE_OPS | TDFA_USE_VOPS, NULL);
|
||||
sink_code_in_bb (EXIT_BLOCK_PTR);
|
||||
if (dump_file && (dump_flags & TDF_STATS))
|
||||
fprintf (dump_file, "Sunk statements:%d\n", sink_stats.sunk);
|
||||
free_dominance_info (CDI_POST_DOMINATORS);
|
||||
remove_fake_exit_edges ();
|
||||
free_df ();
|
||||
loop_optimizer_finalize (loops, dump_file);
|
||||
}
|
||||
|
||||
|
|
|
@ -306,7 +306,7 @@ create_edge_and_update_destination_phis (struct redirection_data *rd)
|
|||
for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
|
||||
{
|
||||
int indx = rd->outgoing_edge->dest_idx;
|
||||
add_phi_arg (phi, PHI_ARG_DEF_TREE (phi, indx), e);
|
||||
add_phi_arg (phi, PHI_ARG_DEF (phi, indx), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
160
gcc/tree-ssa.c
160
gcc/tree-ssa.c
|
@ -215,13 +215,19 @@ err:
|
|||
that are defined before STMT in basic block BB. */
|
||||
|
||||
static bool
|
||||
verify_use (basic_block bb, basic_block def_bb, tree ssa_name,
|
||||
verify_use (basic_block bb, basic_block def_bb, use_operand_p use_p,
|
||||
tree stmt, bool check_abnormal, bool is_virtual,
|
||||
bitmap names_defined_in_bb)
|
||||
{
|
||||
bool err = false;
|
||||
tree ssa_name = USE_FROM_PTR (use_p);
|
||||
|
||||
err = verify_ssa_name (ssa_name, is_virtual);
|
||||
|
||||
if (!TREE_VISITED (ssa_name))
|
||||
if (verify_imm_links (stderr, ssa_name))
|
||||
err = true;
|
||||
|
||||
TREE_VISITED (ssa_name) = 1;
|
||||
|
||||
if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (ssa_name))
|
||||
|
@ -254,6 +260,27 @@ verify_use (basic_block bb, basic_block def_bb, tree ssa_name,
|
|||
err = true;
|
||||
}
|
||||
|
||||
/* Make sure the use is in an appropriate list by checking the previous
|
||||
element to make sure its the same. */
|
||||
if (use_p->prev == NULL)
|
||||
{
|
||||
error ("No immediate_use list");
|
||||
err = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree listvar ;
|
||||
if (use_p->prev->use == NULL)
|
||||
listvar = use_p->prev->stmt;
|
||||
else
|
||||
listvar = USE_FROM_PTR (use_p->prev);
|
||||
if (listvar != ssa_name)
|
||||
{
|
||||
error ("Wrong immediate use list");
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
fprintf (stderr, "for SSA_NAME: ");
|
||||
|
@ -289,7 +316,9 @@ verify_phi_args (tree phi, basic_block bb, basic_block *definition_block)
|
|||
|
||||
for (i = 0; i < phi_num_args; i++)
|
||||
{
|
||||
tree op = PHI_ARG_DEF (phi, i);
|
||||
use_operand_p op_p = PHI_ARG_DEF_PTR (phi, i);
|
||||
tree op = USE_FROM_PTR (op_p);
|
||||
|
||||
|
||||
e = EDGE_PRED (bb, i);
|
||||
|
||||
|
@ -309,7 +338,7 @@ verify_phi_args (tree phi, basic_block bb, basic_block *definition_block)
|
|||
}
|
||||
|
||||
if (TREE_CODE (op) == SSA_NAME)
|
||||
err = verify_use (e->src, definition_block[SSA_NAME_VERSION (op)], op,
|
||||
err = verify_use (e->src, definition_block[SSA_NAME_VERSION (op)], op_p,
|
||||
phi, e->flags & EDGE_ABNORMAL,
|
||||
!is_gimple_reg (PHI_RESULT (phi)),
|
||||
NULL);
|
||||
|
@ -601,7 +630,7 @@ verify_alias_info (void)
|
|||
TODO: verify the variable annotations. */
|
||||
|
||||
void
|
||||
verify_ssa (void)
|
||||
verify_ssa (bool check_modified_stmt)
|
||||
{
|
||||
size_t i;
|
||||
basic_block bb;
|
||||
|
@ -668,8 +697,16 @@ verify_ssa (void)
|
|||
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
|
||||
{
|
||||
tree stmt = bsi_stmt (bsi);
|
||||
use_operand_p use_p;
|
||||
|
||||
if (check_modified_stmt && stmt_modified_p (stmt))
|
||||
{
|
||||
error ("Stmt (0x%x) marked modified after optimization pass : ",
|
||||
(unsigned long)stmt);
|
||||
print_generic_stmt (stderr, stmt, TDF_VOPS);
|
||||
goto err;
|
||||
}
|
||||
|
||||
get_stmt_operands (stmt);
|
||||
|
||||
if (stmt_ann (stmt)->makes_aliased_stores
|
||||
&& NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) == 0)
|
||||
|
@ -679,10 +716,11 @@ verify_ssa (void)
|
|||
goto err;
|
||||
}
|
||||
|
||||
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_ALL_USES | SSA_OP_ALL_KILLS)
|
||||
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES | SSA_OP_ALL_KILLS)
|
||||
{
|
||||
op = USE_FROM_PTR (use_p);
|
||||
if (verify_use (bb, definition_block[SSA_NAME_VERSION (op)],
|
||||
op, stmt, false, !is_gimple_reg (op),
|
||||
use_p, stmt, false, !is_gimple_reg (op),
|
||||
names_defined_in_bb))
|
||||
goto err;
|
||||
}
|
||||
|
@ -724,7 +762,6 @@ init_tree_ssa (void)
|
|||
VARRAY_TREE_INIT (referenced_vars, 20, "referenced_vars");
|
||||
call_clobbered_vars = BITMAP_ALLOC (NULL);
|
||||
addressable_vars = BITMAP_ALLOC (NULL);
|
||||
init_ssa_operands ();
|
||||
init_ssanames ();
|
||||
init_phinodes ();
|
||||
global_var = NULL_TREE;
|
||||
|
@ -765,7 +802,6 @@ delete_tree_ssa (void)
|
|||
|
||||
fini_ssanames ();
|
||||
fini_phinodes ();
|
||||
fini_ssa_operands ();
|
||||
|
||||
global_var = NULL_TREE;
|
||||
BITMAP_FREE (call_clobbered_vars);
|
||||
|
@ -994,10 +1030,10 @@ 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. */
|
||||
statement STMT at use location USE_P. Return TRUE if Anything was done. */
|
||||
|
||||
static void
|
||||
propagate_into_addr (tree stmt, tree var, tree *x, tree repl)
|
||||
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;
|
||||
|
@ -1005,7 +1041,7 @@ propagate_into_addr (tree stmt, tree var, tree *x, tree repl)
|
|||
|
||||
/* There is nothing special to handle in the other cases. */
|
||||
if (TREE_CODE (repl) != ADDR_EXPR)
|
||||
return;
|
||||
return false;
|
||||
addr_var = TREE_OPERAND (repl, 0);
|
||||
|
||||
while (handled_component_p (*x)
|
||||
|
@ -1013,22 +1049,24 @@ propagate_into_addr (tree stmt, tree var, tree *x, tree repl)
|
|||
|| 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) != var)
|
||||
return;
|
||||
|| &(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;
|
||||
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 (var, ass_stmt);
|
||||
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;
|
||||
|
||||
|
@ -1038,6 +1076,7 @@ propagate_into_addr (tree stmt, tree var, tree *x, tree repl)
|
|||
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. */
|
||||
|
@ -1045,58 +1084,53 @@ propagate_into_addr (tree stmt, tree var, tree *x, tree repl)
|
|||
static void
|
||||
replace_immediate_uses (tree var, tree repl)
|
||||
{
|
||||
int i, j, n;
|
||||
dataflow_t df;
|
||||
tree stmt;
|
||||
bool mark_new_vars;
|
||||
ssa_op_iter iter;
|
||||
use_operand_p use_p;
|
||||
use_operand_p imm_use;
|
||||
imm_use_iterator imm_iter;
|
||||
|
||||
df = get_immediate_uses (SSA_NAME_DEF_STMT (var));
|
||||
n = num_immediate_uses (df);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
FOR_EACH_IMM_USE_SAFE (imm_use, imm_iter, var)
|
||||
{
|
||||
stmt = immediate_use (df, i);
|
||||
stmt = USE_STMT (imm_use);
|
||||
|
||||
if (TREE_CODE (stmt) == PHI_NODE)
|
||||
{
|
||||
for (j = 0; j < PHI_NUM_ARGS (stmt); j++)
|
||||
if (PHI_ARG_DEF (stmt, j) == var)
|
||||
{
|
||||
SET_PHI_ARG_DEF (stmt, j, repl);
|
||||
if (TREE_CODE (repl) == SSA_NAME
|
||||
&& PHI_ARG_EDGE (stmt, j)->flags & EDGE_ABNORMAL)
|
||||
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (repl) = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
get_stmt_operands (stmt);
|
||||
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)
|
||||
{
|
||||
propagate_into_addr (stmt, var, &TREE_OPERAND (stmt, 0), repl);
|
||||
propagate_into_addr (stmt, var, &TREE_OPERAND (stmt, 1), repl);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
|
||||
if (USE_FROM_PTR (use_p) == var)
|
||||
{
|
||||
propagate_value (use_p, repl);
|
||||
mark_new_vars = POINTER_TYPE_P (TREE_TYPE (repl));
|
||||
}
|
||||
if (!propagated)
|
||||
propagate_value (imm_use, repl);
|
||||
mark_new_vars = POINTER_TYPE_P (TREE_TYPE (repl));
|
||||
}
|
||||
else
|
||||
{
|
||||
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter,
|
||||
SSA_OP_VIRTUAL_USES | SSA_OP_VIRTUAL_KILLS)
|
||||
if (USE_FROM_PTR (use_p) == var)
|
||||
propagate_value (use_p, repl);
|
||||
}
|
||||
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
|
||||
|
@ -1119,7 +1153,6 @@ replace_immediate_uses (tree var, tree repl)
|
|||
{
|
||||
block_stmt_iterator si = bsi_for_stmt (stmt);
|
||||
mark_new_vars_to_rename (tmp, vars_to_rename);
|
||||
redirect_immediate_uses (stmt, tmp);
|
||||
bsi_replace (&si, tmp, true);
|
||||
stmt = bsi_stmt (si);
|
||||
}
|
||||
|
@ -1133,8 +1166,9 @@ replace_immediate_uses (tree var, tree repl)
|
|||
if (mark_new_vars)
|
||||
mark_new_vars_to_rename (stmt, vars_to_rename);
|
||||
else
|
||||
modify_stmt (stmt);
|
||||
update_stmt (stmt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Gets the value VAR is equivalent to according to EQ_TO. */
|
||||
|
@ -1174,8 +1208,9 @@ 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), n;
|
||||
dataflow_t df;
|
||||
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)
|
||||
|
@ -1211,13 +1246,9 @@ check_phi_redundancy (tree phi, tree *eq_to)
|
|||
|
||||
eq_to[ver] = val;
|
||||
|
||||
df = get_immediate_uses (SSA_NAME_DEF_STMT (res));
|
||||
n = num_immediate_uses (df);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, res)
|
||||
{
|
||||
stmt = immediate_use (df, i);
|
||||
|
||||
stmt = USE_STMT (use_p);
|
||||
if (TREE_CODE (stmt) == PHI_NODE)
|
||||
check_phi_redundancy (stmt, eq_to);
|
||||
}
|
||||
|
@ -1257,12 +1288,6 @@ kill_redundant_phi_nodes (void)
|
|||
it safe). */
|
||||
eq_to = xcalloc (num_ssa_names, sizeof (tree));
|
||||
|
||||
/* We have had cases where computing immediate uses takes a
|
||||
significant amount of compile time. If we run into such
|
||||
problems here, we may want to only compute immediate uses for
|
||||
a subset of all the SSA_NAMEs instead of computing it for
|
||||
all of the SSA_NAMEs. */
|
||||
compute_immediate_uses (TDFA_USE_OPS | TDFA_USE_VOPS, NULL);
|
||||
old_num_ssa_names = num_ssa_names;
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
|
@ -1296,7 +1321,6 @@ kill_redundant_phi_nodes (void)
|
|||
}
|
||||
}
|
||||
|
||||
free_df ();
|
||||
free (eq_to);
|
||||
}
|
||||
|
||||
|
|
|
@ -172,6 +172,7 @@ tree
|
|||
make_ssa_name (tree var, tree stmt)
|
||||
{
|
||||
tree t;
|
||||
ssa_imm_use_t *imm;
|
||||
|
||||
gcc_assert (DECL_P (var)
|
||||
|| TREE_CODE (var) == INDIRECT_REF);
|
||||
|
@ -207,6 +208,11 @@ make_ssa_name (tree var, tree stmt)
|
|||
SSA_NAME_DEF_STMT (t) = stmt;
|
||||
SSA_NAME_PTR_INFO (t) = NULL;
|
||||
SSA_NAME_IN_FREE_LIST (t) = 0;
|
||||
imm = &(SSA_NAME_IMM_USE_NODE (t));
|
||||
imm->use = NULL;
|
||||
imm->prev = imm;
|
||||
imm->next = imm;
|
||||
imm->stmt = t;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
@ -248,10 +254,26 @@ release_ssa_name (tree var)
|
|||
{
|
||||
tree saved_ssa_name_var = SSA_NAME_VAR (var);
|
||||
int saved_ssa_name_version = SSA_NAME_VERSION (var);
|
||||
ssa_imm_use_t *imm = &(SSA_NAME_IMM_USE_NODE (var));
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_imm_links (stderr, var);
|
||||
#endif
|
||||
while (imm->next != imm)
|
||||
{
|
||||
delink_imm_use (imm->next);
|
||||
}
|
||||
#ifdef ENABLE_CHECKING
|
||||
if (imm->next != imm)
|
||||
abort();
|
||||
#endif
|
||||
|
||||
VARRAY_TREE (ssa_names, SSA_NAME_VERSION (var)) = NULL;
|
||||
memset (var, 0, tree_size (var));
|
||||
|
||||
imm->prev = imm;
|
||||
imm->next = imm;
|
||||
imm->stmt = var;
|
||||
/* First put back the right tree node so that the tree checking
|
||||
macros do not complain. */
|
||||
TREE_SET_CODE (var, SSA_NAME);
|
||||
|
|
|
@ -668,7 +668,7 @@ adjust_return_value (basic_block bb, tree m, tree a)
|
|||
}
|
||||
|
||||
TREE_OPERAND (ret_stmt, 0) = var;
|
||||
modify_stmt (ret_stmt);
|
||||
update_stmt (ret_stmt);
|
||||
}
|
||||
|
||||
/* Eliminates tail call described by T. TMP_VARS is a list of
|
||||
|
|
|
@ -2054,9 +2054,10 @@ vect_stmt_relevant_p (tree stmt, loop_vec_info loop_vinfo)
|
|||
v_may_def_optype v_may_defs;
|
||||
v_must_def_optype v_must_defs;
|
||||
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
|
||||
int i;
|
||||
dataflow_t df;
|
||||
int num_uses;
|
||||
ssa_op_iter op_iter;
|
||||
imm_use_iterator imm_iter;
|
||||
use_operand_p use_p;
|
||||
tree var;
|
||||
|
||||
/* cond stmt other than loop exit cond. */
|
||||
if (is_ctrl_stmt (stmt) && (stmt != LOOP_VINFO_EXIT_COND (loop_vinfo)))
|
||||
|
@ -2076,17 +2077,17 @@ vect_stmt_relevant_p (tree stmt, loop_vec_info loop_vinfo)
|
|||
}
|
||||
|
||||
/* uses outside the loop. */
|
||||
df = get_immediate_uses (stmt);
|
||||
num_uses = num_immediate_uses (df);
|
||||
for (i = 0; i < num_uses; i++)
|
||||
FOR_EACH_SSA_TREE_OPERAND (var, stmt, op_iter, SSA_OP_DEF)
|
||||
{
|
||||
tree use = immediate_use (df, i);
|
||||
basic_block bb = bb_for_stmt (use);
|
||||
if (!flow_bb_inside_loop_p (loop, bb))
|
||||
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
|
||||
{
|
||||
if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
|
||||
fprintf (vect_dump, "vec_stmt_relevant_p: used out of loop.");
|
||||
return true;
|
||||
basic_block bb = bb_for_stmt (USE_STMT (use_p));
|
||||
if (!flow_bb_inside_loop_p (loop, bb))
|
||||
{
|
||||
if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
|
||||
fprintf (vect_dump, "vec_stmt_relevant_p: used out of loop.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -170,7 +170,6 @@ static void rename_variables_in_loop (struct loop *);
|
|||
General Vectorization Utilities
|
||||
*************************************************************************/
|
||||
static void vect_set_dump_settings (void);
|
||||
static bool need_imm_uses_for (tree);
|
||||
|
||||
/* vect_dump will be set to stderr or dump_file if exist. */
|
||||
FILE *vect_dump;
|
||||
|
@ -1815,19 +1814,6 @@ vect_is_simple_iv_evolution (unsigned loop_nb, tree access_fn, tree * init,
|
|||
}
|
||||
|
||||
|
||||
/* Function need_imm_uses_for.
|
||||
|
||||
Return whether we ought to include information for 'var'
|
||||
when calculating immediate uses. For this pass we only want use
|
||||
information for non-virtual variables. */
|
||||
|
||||
static bool
|
||||
need_imm_uses_for (tree var)
|
||||
{
|
||||
return is_gimple_reg (var);
|
||||
}
|
||||
|
||||
|
||||
/* Function vectorize_loops.
|
||||
|
||||
Entry Point to loop vectorization phase. */
|
||||
|
@ -1854,8 +1840,6 @@ vectorize_loops (struct loops *loops)
|
|||
verify_loop_closed_ssa ();
|
||||
#endif
|
||||
|
||||
compute_immediate_uses (TDFA_USE_OPS, need_imm_uses_for);
|
||||
|
||||
/* ----------- Analyze loops. ----------- */
|
||||
|
||||
/* If some loop was duplicated, it gets bigger number
|
||||
|
@ -1886,7 +1870,6 @@ vectorize_loops (struct loops *loops)
|
|||
|
||||
/* ----------- Finalize. ----------- */
|
||||
|
||||
free_df ();
|
||||
for (i = 1; i < loops_num; i++)
|
||||
{
|
||||
struct loop *loop = loops->parray[i];
|
||||
|
|
32
gcc/tree.h
32
gcc/tree.h
|
@ -1348,6 +1348,21 @@ struct tree_exp GTY(())
|
|||
struct ptr_info_def;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Immediate use linking structure. THis structure is used for maintaining
|
||||
a doubly linked list of uses of an SSA_NAME. */
|
||||
typedef struct ssa_imm_use_d GTY(())
|
||||
{
|
||||
struct ssa_imm_use_d* GTY((skip(""))) prev;
|
||||
struct ssa_imm_use_d* GTY((skip(""))) next;
|
||||
tree GTY((skip(""))) stmt;
|
||||
tree *GTY((skip(""))) use;
|
||||
} ssa_imm_use_t;
|
||||
|
||||
/* Return the immediate_use information for an SSA_NAME. */
|
||||
#define SSA_NAME_IMM_USE_NODE(NODE) SSA_NAME_CHECK (NODE)->ssa_name.imm_uses
|
||||
|
||||
struct tree_ssa_name GTY(())
|
||||
{
|
||||
struct tree_common common;
|
||||
|
@ -1370,9 +1385,19 @@ struct tree_ssa_name GTY(())
|
|||
|
||||
/* Auxiliary information stored with the ssa name. */
|
||||
PTR GTY((skip)) aux;
|
||||
|
||||
/* Immediate uses list for this SSA_NAME. */
|
||||
struct ssa_imm_use_d imm_uses;
|
||||
};
|
||||
|
||||
/* In a PHI_NODE node. */
|
||||
|
||||
/* These 2 macros should be considered off limits for use by developers. If
|
||||
you wish to access the use or def fields of a PHI_NODE in the SSA
|
||||
optimizers, use the accessor macros found in tree-ssa-operands.h.
|
||||
These two macros are to be used only by those accessor macros, and other
|
||||
select places where we *absolutly* must take the address of the tree. */
|
||||
|
||||
#define PHI_RESULT_TREE(NODE) PHI_NODE_CHECK (NODE)->phi.result
|
||||
#define PHI_ARG_DEF_TREE(NODE, I) PHI_NODE_ELT_CHECK (NODE, I).def
|
||||
|
||||
|
@ -1390,12 +1415,13 @@ struct tree_ssa_name GTY(())
|
|||
#define PHI_ARG_EDGE(NODE, I) (EDGE_PRED (PHI_BB ((NODE)), (I)))
|
||||
#define PHI_ARG_NONZERO(NODE, I) PHI_NODE_ELT_CHECK (NODE, I).nonzero
|
||||
#define PHI_BB(NODE) PHI_NODE_CHECK (NODE)->phi.bb
|
||||
#define PHI_DF(NODE) PHI_NODE_CHECK (NODE)->phi.df
|
||||
#define PHI_ARG_IMM_USE_NODE(NODE, I) PHI_NODE_ELT_CHECK (NODE, I).imm_use
|
||||
|
||||
struct edge_def;
|
||||
|
||||
struct phi_arg_d GTY(())
|
||||
{
|
||||
struct ssa_imm_use_d imm_use; /* imm_use MUST be first element in struct. */
|
||||
tree def;
|
||||
bool nonzero;
|
||||
};
|
||||
|
@ -1414,9 +1440,6 @@ struct tree_phi_node GTY(())
|
|||
/* Basic block to that the phi node belongs. */
|
||||
struct basic_block_def *bb;
|
||||
|
||||
/* Dataflow information. */
|
||||
struct dataflow_d *df;
|
||||
|
||||
struct phi_arg_d GTY ((length ("((tree)&%h)->phi.num_args"))) a[1];
|
||||
};
|
||||
|
||||
|
@ -3895,6 +3918,7 @@ enum tree_dump_index
|
|||
#define TDF_TREE (1 << 9) /* is a tree dump */
|
||||
#define TDF_RTL (1 << 10) /* is a RTL dump */
|
||||
#define TDF_IPA (1 << 11) /* is an IPA dump */
|
||||
#define TDF_STMTADDR (1 << 12) /* Address of stmt. */
|
||||
|
||||
typedef struct dump_info *dump_info_p;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue