diff options
40 files changed, 1607 insertions, 979 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5d0e9562880..8b51e091efe 100644 --- a/gcc/ChangeLog +++ b/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 diff --git a/gcc/lambda-code.c b/gcc/lambda-code.c index 66745b6cb25..80e5478ec0d 100644 --- a/gcc/lambda-code.c +++ b/gcc/lambda-code.c @@ -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)) diff --git a/gcc/predict.c b/gcc/predict.c index 37b1f20e3b5..961a39526a1 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -1013,7 +1013,7 @@ strip_builtin_expect (void) && TREE_CHAIN (arglist)) { TREE_OPERAND (stmt, 1) = TREE_VALUE (arglist); - modify_stmt (stmt); + update_stmt (stmt); } } } diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 00325fc77df..bb8e256a50f 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -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); } diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c index a5708f39a8e..e673aed4fce 100644 --- a/gcc/tree-complex.c +++ b/gcc/tree-complex.c @@ -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 diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index 6bbec8f8d1e..38d60c0a136 100644 --- a/gcc/tree-dfa.c +++ b/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)); diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c index 87a283146e4..d636c0c45cc 100644 --- a/gcc/tree-dump.c +++ b/gcc/tree-dump.c @@ -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} }; diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index 4d6f5cb1485..d43812ef0fc 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -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,64 +612,40 @@ 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 the bitmap of addresses taken by STMT, or NULL if it takes - no addresses. */ -static inline bitmap -addresses_taken (tree stmt) -{ - stmt_ann_t ann = stmt_ann (stmt); - return ann ? ann->addresses_taken : NULL; + return &(PHI_ARG_IMM_USE_NODE (phi,i)); } -/* Return the immediate uses of STMT, or NULL if this information is - not computed. */ -static dataflow_t -get_immediate_uses (tree stmt) +/* Delink all immediate_use information for STMT. */ +static inline void +delink_stmt_imm_use (tree stmt) { - stmt_ann_t ann; + 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); - if (TREE_CODE (stmt) == PHI_NODE) - return PHI_DF (stmt); + for (x = 0; x < NUM_USES (uses); x++) + delink_imm_use (&(uses->uses[x])); - ann = stmt_ann (stmt); - return ann ? ann->df : NULL; -} + for (x = 0; x < NUM_VUSES (vuses); x++) + delink_imm_use (&(vuses->vuses[x].imm_use)); -/* 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; + for (x = 0; x < NUM_V_MAY_DEFS (v_may_defs); x++) + delink_imm_use (&(v_may_defs->v_may_defs[x].imm_use)); - if (!df) - return 0; - - imm = df->immediate_uses; - if (!imm) - return df->uses[1] ? 2 : 1; - - return VARRAY_ACTIVE_SIZE (imm) + 2; + 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 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 bitmap of addresses taken by STMT, or NULL if it takes + no addresses. */ +static inline bitmap +addresses_taken (tree stmt) +{ + stmt_ann_t ann = stmt_ann (stmt); + return ann ? ann->addresses_taken : NULL; } /* Return the basic_block annotation for 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 diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index ea08f7ad79e..ebc31ab27f6 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -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; - - /* 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: - - 1 a1 = 10; - 2 if (a1 > 3) - 3 a2 = a1 + 5; - 4 a3 = PHI (a1, a2) - 5 b1 = a3 - 2; - - 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). */ -}; + ssa_imm_use_t *imm_use; + ssa_imm_use_t *end_p; + ssa_imm_use_t iter_node; +} imm_use_iterator; + -typedef struct dataflow_d *dataflow_t; +/* Use this iterator when simply looking at stmts. Adding, deleteing or + modifying stmts will cause this iterator to malfunction. */ + +#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))) + +#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); diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index d22a6173559..fe446d9b0ab 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -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)) { diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c index 46470a407bb..09e6d1f51cc 100644 --- a/gcc/tree-into-ssa.c +++ b/gcc/tree-into-ssa.c @@ -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. */ diff --git a/gcc/tree-loop-linear.c b/gcc/tree-loop-linear.c index 860fafbd1de..0835a451dcb 100644 --- a/gcc/tree-loop-linear.c +++ b/gcc/tree-loop-linear.c @@ -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); diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c index 63131af1796..e6439151303 100644 --- a/gcc/tree-optimize.c +++ b/gcc/tree-optimize.c @@ -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) diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c index 5d34ca9bdf3..ecbee58504d 100644 --- a/gcc/tree-outof-ssa.c +++ b/gcc/tree-outof-ssa.c @@ -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); } } diff --git a/gcc/tree-phinodes.c b/gcc/tree-phinodes.c index dcf4ba078ab..963ef0a9578 100644 --- a/gcc/tree-phinodes.c +++ b/gcc/tree-phinodes.c @@ -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)); } } diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 743e1592e4d..c21766e7e5b 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -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)) diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 2fb23bd6022..b933fbc32e0 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -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) { diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 0dc48e3825f..8e1b63265f8 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -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); } } diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index d8a850d357b..26e1a2ea1b8 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -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; diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index ae259e3a8ca..ebb0aa3fbfa 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -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; } diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c index 249132d0f61..edea6382ce3 100644 --- a/gcc/tree-ssa-dse.c +++ b/gcc/tree-ssa-dse.c @@ -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; + + 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 there are no uses then there is nothing left to do. */ - if (num_uses == 0) + 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); } diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index fb079dd0e24..02b41b6e6c8 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -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 (); } } diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c index 98bc76babd4..7823e1711e7 100644 --- a/gcc/tree-ssa-loop-im.c +++ b/gcc/tree-ssa-loop-im.c @@ -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; } diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c index a15f0235d18..43f3c15f634 100644 --- a/gcc/tree-ssa-loop-ivcanon.c +++ b/gcc/tree-ssa-loop-ivcanon.c @@ -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); diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 494b41ec736..d1bdb7add8e 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -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); + /* 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); + 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)); + { + bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_NEW_STMT); + protect_loop_closed_ssa_form (exit, bsi_stmt (bsi)); + } } 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); + { + 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. */ diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c index 1bb4c4c3aa1..cbc1e69d430 100644 --- a/gcc/tree-ssa-loop-manip.c +++ b/gcc/tree-ssa-loop-manip.c @@ -415,7 +415,7 @@ verify_loop_closed_ssa (void) tree phi; unsigned i; - verify_ssa (); + verify_ssa (false); FOR_EACH_BB (bb) { diff --git a/gcc/tree-ssa-loop-unswitch.c b/gcc/tree-ssa-loop-unswitch.c index 03631b82636..9546342c9dc 100644 --- a/gcc/tree-ssa-loop-unswitch.c +++ b/gcc/tree-ssa-loop-unswitch.c @@ -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++; } diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index 916814dc4de..979337b12ae 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -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; } +} + +/* 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; - finalize_ssa_stmt_operands (stmt, old_ops, new_ops); + 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" diff --git a/gcc/tree-ssa-operands.h b/gcc/tree-ssa-operands.h index 92d10fd8521..e2a8a50a9de 100644 --- a/gcc/tree-ssa-operands.h +++ b/gcc/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; diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index 3eedf9974e4..41370ed114a 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -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) diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 6ca0b0ade9e..34b759cb880 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -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. */ diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index 481972acbdb..c57c9f8695a 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -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 (); } diff --git a/gcc/tree-ssa-sink.c b/gcc/tree-ssa-sink.c index 5984a5a3fcf..af72e17ae98 100644 --- a/gcc/tree-ssa-sink.c +++ b/gcc/tree-ssa-sink.c @@ -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; - - if (imm == NULL || num_immediate_uses (imm) < 2) - return true; - firstuse = immediate_use (imm, 0); + tree firstuse = NULL_TREE; + ssa_op_iter op_iter; + imm_use_iterator imm_iter; + use_operand_p use_p; + tree var; - 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) + { + 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 = PHI_ARG_EDGE (usestmt, j)->src; + 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; + + 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; + } - if (imm == NULL) + /* 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); } diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c index c0d5b47ec61..617467a4ef0 100644 --- a/gcc/tree-ssa-threadupdate.c +++ b/gcc/tree-ssa-threadupdate.c @@ -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); } } diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index a9564b86c4a..e23e665d42a 100644 --- a/gcc/tree-ssa.c +++ b/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); } diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c index a89d6087f38..79e1a764e73 100644 --- a/gcc/tree-ssanames.c +++ b/gcc/tree-ssanames.c @@ -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); diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c index 3c2036cdeac..3a9162ce4e0 100644 --- a/gcc/tree-tailcall.c +++ b/gcc/tree-tailcall.c @@ -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 diff --git a/gcc/tree-vect-analyze.c b/gcc/tree-vect-analyze.c index 97ad2314b65..9ee81c81e16 100644 --- a/gcc/tree-vect-analyze.c +++ b/gcc/tree-vect-analyze.c @@ -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; + } } } diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index be4d816c30e..f3551f8528d 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -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]; diff --git a/gcc/tree.h b/gcc/tree.h index d09034c167a..7c61e8fd8b4 100644 --- a/gcc/tree.h +++ b/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; |