aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-alias.c
diff options
context:
space:
mode:
authorRichard Guenther <rguenther@suse.de>2009-04-03 10:24:28 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2009-04-03 10:24:28 +0000
commit5006671f1aaa63cd3f14535e014faa3bca5d20cc (patch)
treec6c1826ba3cd971c15d66cb4b498f99ad646ed70 /gcc/tree-ssa-alias.c
parent95fe602ebea97abb5c5a303e7441fa055b65bb32 (diff)
downloadgcc-5006671f1aaa63cd3f14535e014faa3bca5d20cc.zip
gcc-5006671f1aaa63cd3f14535e014faa3bca5d20cc.tar.gz
gcc-5006671f1aaa63cd3f14535e014faa3bca5d20cc.tar.bz2
re PR middle-end/13146 (inheritance for nonoverlapping_component_refs_p)
2009-04-03 Richard Guenther <rguenther@suse.de> PR middle-end/13146 PR tree-optimization/23940 PR tree-optimization/33237 PR middle-end/33974 PR middle-end/34093 PR tree-optimization/36201 PR tree-optimization/36230 PR tree-optimization/38049 PR tree-optimization/38207 PR tree-optimization/38230 PR tree-optimization/38301 PR tree-optimization/38585 PR middle-end/38895 PR tree-optimization/38985 PR tree-optimization/39299 * tree-ssa-structalias.h: Remove. * tree-ssa-operands.h (NULL_USE_OPERAND_P): Make of type use_operand_p. (NULL_DEF_OPERAND_P): Make of type def_operand_p. (struct vuse_element_d): Remove. (struct vuse_vec_d): Likewise. (VUSE_VECT_NUM_ELEM, VUSE_VECT_ELEMENT_NC, VUSE_ELEMENT_PTR_NC, VUSE_ELEMENT_VAR_NC, VUSE_VECT_ELEMENT, VUSE_ELEMENT_PTR, SET_VUSE_VECT_ELEMENT, SET_VUSE_ELEMENT_VAR, SET_VUSE_ELEMENT_PTR, VUSE_ELEMENT_VAR): Likewise. (struct voptype_d): Likewise. (NUM_VOP_FREE_BUCKETS): Likewise. (struct ssa_operands): Remove vop_free_buckets and mpt_table fields. (struct stmt_operands_d): Remove. (VUSE_OP_PTR, VUSE_OP, SET_VUSE_OP, VUSE_NUM, VUSE_VECT, VDEF_RESULT_PTR, VDEF_RESULT, VDEF_OP_PTR, VDEF_OP, SET_VDEF_OP, VDEF_NUM, VDEF_VECT): Likewise. (copy_virtual_operands): Remove. (operand_build_cmp): Likewise. (create_ssa_artificial_load_stmt): Likewise. (enum ssa_op_iter_type): Remove ssa_op_iter_vdef. (struct ssa_operand_iterator_d): Remove vuses, vdefs, mayusesm vuse_index and mayuse_index members. Pack and move done and iter_type members to the front. (SSA_OP_VMAYUSE): Remove. (SSA_OP_VIRTUAL_USES): Adjust. (FOR_EACH_SSA_VDEF_OPERAND): Remove. (unlink_stmt_vdef): Declare. (add_to_addressable_set): Remove. * tree-vrp.c (stmt_interesting_for_vrp): Adjust. (vrp_visit_stmt): Likewise. * doc/tree-ssa.texi (Alias analysis): Update. * doc/invoke.texi (max-aliased-vops): Remove docs. (avg-aliased-vops): Likewise. * tree-into-ssa.c (syms_to_rename): Remove. (need_to_update_vops_p): Likewise. (need_to_initialize_update_ssa_p): Rename to ... (update_ssa_initialized_fn): ... this. Track function we are initialized for. (symbol_marked_for_renaming): Simplify. (add_new_name_mapping): Do not set need_to_update_vops_p. (dump_currdefs): Use SYMS_TO_RENAME. (rewrite_update_stmt): Always walk all uses/defs. (dump_update_ssa): Adjust. (init_update_ssa): Take function argument. Track what we are initialized for. (delete_update_ssa): Reset SYMS_TO_RENAME and update_ssa_initialized_fn. (create_new_def_for): Initialize for cfun, assert we are initialized for cfun. (mark_sym_for_renaming): Simplify. (mark_set_for_renaming): Do not initialize update-ssa. (need_ssa_update_p): Simplify. Take function argument. (name_mappings_registered_p): Assert we ask for the correct function. (name_registered_for_update_p): Likewise. (ssa_names_to_replace): Likewise. (release_ssa_name_after_update_ssa): Likewise. (update_ssa): Likewise. Use SYMS_TO_RENAME. (dump_decl_set): Do not print a newline. (debug_decl_set): Do it here. (dump_update_ssa): And here. * tree-ssa-loop-im.c (move_computations): Adjust. (movement_possibility): Likewise. (determine_max_movement): Likewise. (gather_mem_refs_stmt): Likewise. * tree-dump.c (dequeue_and_dump): Do not handle SYMBOL_MEMORY_TAG or NAME_MEMORY_TAG. * tree-complex.c (update_all_vops): Remove. (expand_complex_move): Adjust. * tree-ssa-loop-niter.c (chain_of_csts_start): Use NULL_TREE. Simplify test for memory referencing statement. Exclude non-invariant ADDR_EXPRs. * tree-pretty-print.c (dump_generic_node): Do not handle memory tags. * tree-loop-distribution.c (generate_memset_zero): Adjust. (rdg_flag_uses): Likewise. * tree-tailcall.c (suitable_for_tail_opt_p): Remove memory-tag related code. (tree_optimize_tail_calls_1): Also split the edge from the entry block if we have degenerate PHI nodes in the first basic block. * tree.c (init_ttree): Remove memory-tag related code. (tree_code_size): Likewise. (tree_node_structure): Likewise. (build7_stat): Re-write to be build6_stat. * tree.h (MTAG_P, TREE_MEMORY_TAG_CHECK, TMR_TAG): Remove. (SSA_VAR_P): Adjust. (struct tree_memory_tag): Remove. (struct tree_memory_partition_tag): Likewise. (union tree_node): Adjust. (build7): Re-write to be build6. * tree-pass.h (pass_reset_cc_flags): Remove. (TODO_update_address_taken): New flag. (pass_simple_dse): Remove. * ipa-cp.c (ipcp_update_callgraph): Update SSA form. * params.h (MAX_ALIASED_VOPS): Remove. (AVG_ALIASED_VOPS): Likewise. * omp-low.c (expand_omp_taskreg): Update SSA form. * tree-ssa-dse.c (dse_optimize_stmt): Properly query if the rhs aliases the lhs in a copy stmt. * tree-ssa-dse.c (struct address_walk_data): Remove. (memory_ssa_name_same): Likewise. (memory_address_same): Likewise. (get_kill_of_stmt_lhs): Likewise. (dse_possible_dead_store_p): Simplify, use the oracle. Handle unused stores. Look through PHI nodes into post-dominated regions. (dse_optimize_stmt): Simplify. Properly remove stores. (tree_ssa_dse): Compute dominators. (execute_simple_dse): Remove. (pass_simple_dse): Likewise. * ipa-reference.c (scan_stmt_for_static_refs): Open-code gimple_loaded_syms and gimple_stored_syms computation. * toplev.c (dump_memory_report): Dump alias and pta stats. * tree-ssa-sccvn.c (vn_reference_compute_hash): Simplify. (vn_reference_eq): Likewise. (vuses_to_vec, copy_vuses_from_stmt, vdefs_to_vec, copy_vdefs_from_stmt, shared_lookup_vops, shared_vuses_from_stmt, valueize_vuses): Remove. (get_def_ref_stmt_vuses): Simplify. Rename to ... (get_def_ref_stmt_vuse): ... this. (vn_reference_lookup_2): New function. (vn_reference_lookup_pieces): Use walk_non_aliased_vuses for walking equivalent vuses. Simplify. (vn_reference_lookup): Likewise. (vn_reference_insert): Likewise. (vn_reference_insert_pieces): Likewise. (visit_reference_op_call): Simplify. (visit_reference_op_load): Likewise. (visit_reference_op_store): Likewise. (init_scc_vn): Remove shared_lookup_vuses initialization. (free_scc_vn): Remove shared_lookup_vuses freeing. (sort_vuses, sort_vuses_heap): Remove. (get_ref_from_reference_ops): Export. * tree-ssa-sccvn.h (struct vn_reference_s): Replace vuses vector with single vuse pointer. (vn_reference_lookup_pieces, vn_reference_lookup, vn_reference_insert, vn_reference_insert_pieces): Adjust prototypes. (shared_vuses_from_stmt): Remove. (get_ref_from_reference_ops): Declare. * tree-ssa-loop-manip.c (slpeel_can_duplicate_loop_p): Adjust. * tree-ssa-copyrename.c (copy_rename_partition_coalesce): Remove memory-tag related code. * tree-ssa-ccp.c (get_symbol_constant_value): Remove memory-tag code. (likely_value): Add comment, skip static-chain of call statements. (surely_varying_stmt_p): Adjust. (gimplify_and_update_call_from_tree): Likewise. (execute_fold_all_builtins): Do not rebuild alias info. (gimplify_and_update_call_from_tree): Properly update VOPs. * tree-ssa-loop-ivopts.c (get_ref_tag): Remove. (copy_ref_info): Remove memory-tag related code. * tree-call-cdce.c (tree_call_cdce): Rename the VOP. * ipa-pure-const.c (check_decl): Remove memory-tag related code. (check_stmt): Open-code gimple_loaded_syms and gimple_stored_syms computation. * tree-ssa-dom.c (gimple_p): Remove typedef. (eliminate_redundant_computations): Adjust. (record_equivalences_from_stmt): Likewise. (avail_expr_hash): Likewise. (avail_expr_eq): Likewise. * tree-ssa-propagate.c (update_call_from_tree): Properly update VOPs. (stmt_makes_single_load): Likewise. (stmt_makes_single_store): Likewise. * tree-ssa-alias.c: Rewrite completely. (debug_memory_partitions, dump_mem_ref_stats, debug_mem_ref_stats, debug_mem_sym_stats, dump_mem_sym_stats_for_var, debug_all_mem_sym_stats, debug_mp_info, update_mem_sym_stats_from_stmt, delete_mem_ref_stats, create_tag_raw, dump_points_to_info, dump_may_aliases_for, debug_may_aliases_for, new_type_alias): Remove public functions. (pass_reset_cc_flags): Remove. (pass_build_alias): Move ... * tree-ssa-structalias.c (pass_build_alias): ... here. * tree-ssa-alias.c (may_be_aliased): Move ... * tree-flow-inline.h (may_be_aliased): ... here. tree-ssa-alias.c (struct count_ptr_d, count_ptr_derefs, count_uses_and_derefs): Move ... * gimple.c: ... here. * gimple.h (count_uses_and_derefs): Declare. * tree-ssa-alias.c (dump_alias_stats, ptr_deref_may_alias_global_p, ptr_deref_may_alias_decl_p, ptr_derefs_may_alias_p, same_type_for_tbaa, nonaliasing_component_refs_p, decl_refs_may_alias_p, indirect_ref_may_alias_decl_p, indirect_refs_may_alias_p, ref_maybe_used_by_call_p, ref_maybe_used_by_stmt_p, call_may_clobber_ref_p, stmt_may_clobber_ref_p, maybe_skip_until, get_continuation_for_phi, walk_non_aliased_vuses, walk_aliased_vdefs): New functions. * tree-dfa.c (refs_may_alias_p): Move ... * tree-ssa-alias.c (refs_may_alias_p): ... here. Extend. * tree-ssa-alias.h: New file. * tree-ssa-sink.c (is_hidden_global_store): Adjust. (statement_sink_location): Likewise. * opts.c (decode_options): Do not adjust max-aliased-vops or avg-aliased-vops values. * timevar.def (TV_TREE_MAY_ALIAS): Remove. (TV_CALL_CLOBBER): Likewise. (TV_FLOW_SENSITIVE): Likewise. (TV_FLOW_INSENSITIVE): Likewise. (TV_MEMORY_PARTITIONING): Likewise. (TV_ALIAS_STMT_WALK): New timevar. * tree-ssa-loop-ivcanon.c (empty_loop_p): Adjust. * tree-ssa-address.c (create_mem_ref_raw): Use build6. (get_address_description): Remove memory-tag related code. * tree-ssa-ifcombine.c (bb_no_side_effects_p): Adjust. * treestruct.def (TS_MEMORY_TAG, TS_MEMORY_PARTITION_TAG): Remove. * tree-eh.c (cleanup_empty_eh): Do not leave stale SSA_NAMEs and immediate uses in statements. Document. * gimple-pretty-print.c (dump_gimple_mem_ops): Adjust. (dump_symbols): Remove. (dump_gimple_mem_ops): Do not dump loaded or stored syms. * alias.c (get_deref_alias_set): New function split out from ... (get_alias_set): ... here. * alias.h (get_deref_alias_set): Declare. * tree-vect-data-refs.c (vect_create_data_ref_ptr): Remove unused type parameter. Remove restrict pointer handling. Create a ref-all pointer in case type-based alias sets do not conflict. (vect_analyze_data_refs): Remove SMT related code. * tree-vect-stmts.c (vectorizable_store): Re-instantiate TBAA assert. (vectorizable_load): Likewise. * tree-data-ref.h (struct dr_alias): Remove symbol_tag field. (DR_SYMBOL_TAG, DR_VOPS): Remove. * tree-data-ref.c (dr_may_alias_p): Use the alias-oracle. Ignore vops and SMTs. (dr_analyze_alias): Likewise.. (free_data_ref): Likewise. (create_data_ref): Likewise. (analyze_all_data_dependences): Likewise. (get_references_in_stmt): Adjust. * tree-flow-inline.h (gimple_aliases_computed_p, gimple_addressable_vars, gimple_call_clobbered_vars, gimple_call_used_vars, gimple_global_var, may_aliases, memory_partition, factoring_name_p, mark_call_clobbered, clear_call_clobbered, compare_ssa_operands_equal, symbol_mem_tag, set_symbol_mem_tag, gimple_mem_ref_stats): Remove. (gimple_vop): New function. (op_iter_next_use): Remove vuses and mayuses cases. (op_iter_next_def): Remove vdefs case. (op_iter_next_tree): Remove vuses, mayuses and vdefs cases. (clear_and_done_ssa_iter): Do not set removed fields. (op_iter_init): Likewise. Skip vuse and/or vdef if requested. Assert we are not iterating over vuses or vdefs if not also iterating over uses or defs. (op_iter_init_use): Likewise. (op_iter_init_def): Likewise. (op_iter_next_vdef): Remove. (op_iter_next_mustdef): Likewise. (op_iter_init_vdef): Likewise. (compare_ssa_operands_equal): Likewise. (link_use_stmts_after): Handle vuse operand. (is_call_used): Use is_call_clobbered. (is_call_clobbered): Global variables are always call clobbered, query the call-clobbers bitmap. (mark_call_clobbered): Ignore global variables. (clear_call_clobbered): Likewise. * tree-ssa-coalesce.c (create_outofssa_var_map): Adjust virtual operands sanity check. * tree.def (NAME_MEMORY_TAG, SYMBOL_MEMORY_TAG, MEMORY_PARTITION_TAG): Remove. (TARGET_MEM_REF): Remove TMR_TAG operand. * tree-dfa.c (add_referenced_var): Initialize call-clobber state. Remove call-clobber related code. (remove_referenced_var): Likewise. Do not clear mpt or symbol_mem_tag. (dump_variable): Do not dump SMTs, memory stats, may-aliases or partitions or escape reason. (get_single_def_stmt, get_single_def_stmt_from_phi, get_single_def_stmt_with_phi): Remove. (dump_referenced_vars): Tidy. (get_ref_base_and_extent): Allow bare decls. (collect_dfa_stats): Adjust. * graphite.c (rename_variables_in_stmt): Adjust. (graphite_copy_stmts_from_block): Likewise. (translate_clast): Likewise. * tree-ssa-pre.c (struct bb_bitmap_sets): Add expr_dies bitmap. (EXPR_DIES): New. (translate_vuse_through_block): Use the oracle. (phi_translate_1): Adjust. (value_dies_in_block_x): Use the oracle. Cache the outcome in EXPR_DIES. (valid_in_sets): Check if the VUSE for a REFERENCE is available. (eliminate): Do not remove stmts during elimination, instead queue and remove them afterwards. (do_pre): Do not rebuild alias info. (pass_pre): Run TODO_rebuild_alias before PRE. * tree-ssa-live.c (remove_unused_locals): Remove memory-tag code. * tree-sra.c (sra_walk_function): Use gimple_references_memory_p. (mark_all_v_defs_stmt): Remove. (mark_all_v_defs_seq): Adjust. (sra_replace): Likewise. (scalarize_use): Likewise. (scalarize_copy): Likewise. (scalarize_init): Likewise. (scalarize_ldst): Likewise. (todoflags): Remove. (tree_sra): Do not rebuild alias info. (tree_sra_early): Adjust. (pass_sra): Run TODO_update_address_taken before SRA. * tree-predcom.c (set_alias_info): Remove. (prepare_initializers_chain): Do not call it. (mark_virtual_ops_for_renaming): Adjust. (mark_virtual_ops_for_renaming_list): Remove. (initialize_root_vars): Adjust. (initialize_root_vars_lm): Likewise. (prepare_initializers_chain): Likewise. * tree-ssa-copy.c (may_propagate_copy): Remove memory-tag related code. (may_propagate_copy_into_stmt): Likewise. (merge_alias_info): Do nothing for now. (propagate_tree_value_into_stmt): Adjust. (stmt_may_generate_copy): Likewise. * tree-ssa-forwprop.c (tidy_after_forward_propagate_addr): Do not mark symbols for renaming. (forward_propagate_addr_expr): Match up push/pop_stmt_changes with the same statement, make sure to update the new pointed-to one. * tree-ssa-dce.c (eliminate_unnecessary_stmts): Do not copy call statements, do not mark symbols for renaming. (mark_operand_necessary): Dump something. (ref_may_be_aliased): New function. (mark_aliased_reaching_defs_necessary_1): New helper function. (mark_aliased_reaching_defs_necessary): Likewise. (mark_all_reaching_defs_necessary_1): Likewise. (mark_all_reaching_defs_necessary): Likewise. (propagate_necessity): Do not process virtual PHIs. For non-aliased loads mark all reaching definitions as necessary. For aliased loads and stores mark the immediate dominating aliased clobbers as necessary. (visited): New global static. (perform_tree_ssa_dce): Free visited bitmap after propagating necessity. (remove_dead_phis): Perform simple dead virtual PHI removal. (remove_dead_stmt): Properly unlink virtual operands when removing stores. (eliminate_unnecessary_stmts): Schedule PHI removal after stmt removal. * tree-ssa-ter.c (is_replaceable_p): Adjust. (process_replaceable): Likewise. (find_replaceable_in_bb): Likewise. * tree-ssa.c (verify_ssa_name): Verify all VOPs are based on the single gimple vop. (verify_flow_insensitive_alias_info): Remove. (verify_flow_sensitive_alias_info): Likewise. (verify_call_clobbering): Likewise. (verify_memory_partitions): Likewise. (verify_alias_info): Likewise. (verify_ssa): Adjust.. (execute_update_addresses_taken): Export. Update SSA manually. Optimize only when optimizing. Use a local bitmap. (pass_update_address_taken): Remove TODO_update_ssa, add TODO_dump_func. (pass_update_address_taken): Just use TODO_update_address_taken. (init_tree_ssa): Do not initialize addressable_vars. (verify_ssa): Verify new VUSE / VDEF properties. Verify that all stmts definitions have the stmt as SSA_NAME_DEF_STMT. Do not call verify_alias_info. (delete_tree_ssa): Clear the VUSE, VDEF operands. Do not free the loaded and stored syms bitmaps. Reset the escaped and callused solutions. Do not free addressable_vars. Remove memory-tag related code. (warn_uninitialized_var): Aliases are always available. * tree-ssa-loop-prefetch.c (gather_memory_references): Adjust. * lambda-code.c (can_put_in_inner_loop): Adjust. (can_put_after_inner_loop): Likewise. (perfect_nestify): Likewise. * tree-vect-stmts.c (vect_stmt_relevant_p): Adjust. (vect_gen_widened_results_half): Remove CALL_EXPR handling. (vectorizable_conversion): Do not mark symbols for renaming. * tree-inline.c (remap_gimple_stmt): Clear VUSE/VDEF. (expand_call_inline): Unlink the calls virtual operands before replacing it. (tree_function_versioning): Do not call update_ssa if we are not updating clones. Simplify. * tree-ssa-phiprop.c (phivn_valid_p): Adjust. (propagate_with_phi): Likewise.. * tree-outof-ssa.c (create_temp): Remove memory tag and call clobber code. Assert we are not aliased or global. * tree-flow.h: Include tree-ssa-alias.h (enum escape_type): Remove. (struct mem_sym_stats_d): Likewise. (struct mem_ref_stats_d): Likewise. (struct gimple_df): Add vop member. Remove global_var, call_clobbered_vars, call_used_vars, addressable_vars, aliases_compted_p and mem_ref_stats members. Add syms_to_rename, escaped and callused members. (struct ptr_info_def): Remove all members, add points-to solution member pt. (struct var_ann_d): Remove in_vuse_list, in_vdef_list, call_clobbered, escape_mask, mpt and symbol_mem_tag members. * Makefile.in (TREE_FLOW_H): Add tree-ssa-alias.h. (tree-ssa-structalias.o): Remove tree-ssa-structalias.h. (tree-ssa-alias.o): Likewise. (toplev.o): Add tree-ssa-alias.h (GTFILES): Remove tree-ssa-structalias.h, add tree-ssa-alias.h. * gimple.c (gimple_set_bb): Fix off-by-one error. (is_gimple_reg): Do not handle memory tags. (gimple_copy): Also copy virtual operands. Delay updating the statement. Do not reset loaded and stored syms. (gimple_set_stored_syms): Remove. (gimple_set_loaded_syms): Likewise. (gimple_call_copy_skip_args): Copy the virtual operands and mark the new statement modified. * tree-ssa-structalias.c (may_alias_p): Remove. (set_uids_in_ptset): Take the alias set to prune with as parameter. Fold in the alias test of may_alias_p. (compute_points_to_sets): Compute whether a ptr is dereferenced in a local sbitmap. (process_constraint): Deal with &ANYTHING on the lhs, reject all other ADDRESSOF constraints on the lhs. (get_constraint_for_component_ref): Assert that we don't get ADDRESSOF constraints from the base of the reference. Properly generate UNKNOWN_OFFSET for DEREF if needed. (struct variable_info): Remove collapsed_to member. (get_varinfo_fc): Remove. (new_var_info): Do not set collapsed_to. (dump_constraint): Do not follow cycles. (dump_constraint_graph): Likewise. (build_pred_graph): Likewise. (build_succ_graph): Likewise. (rewrite_constraints): Likewise. (do_simple_structure_copy): Remove. (do_rhs_deref_structure_copy): Remove. (do_lhs_deref_structure_copy): Remove. (collapse_rest_of_var): Remove. (do_structure_copy): Re-implement. (pta_stats): New global variable. (dump_pta_stats): New function. (struct constraint_expr): Make offset signed. (UNKNOWN_OFFSET): Define special value. (dump_constraint): Dump UNKNOWN_OFFSET as UNKNOWN. (solution_set_expand): New helper function split out from ... (do_sd_constraint): ... here. (solution_set_add): Handle UNKNOWN_OFFSET. Handle negative offsets. (do_ds_constraint): Likewise. (do_sd_constraint): Likewise. Do not special-case ESCAPED = *ESCAPED and CALLUSED = *CALLUSED. (set_union_with_increment): Make inc argument signed. (type_safe): Remove. (get_constraint_for_ptr_offset): Handle unknown and negative constant offsets. (first_vi_for_offset): Handle offsets before start. Bail out early for offsets beyond the variable extent. (first_or_preceding_vi_for_offset): New function. (init_base_vars): Add ESCAPED = ESCAPED + UNKNOWN_OFFSET constraint. Together with ESCAPED = *ESCAPED this properly computes reachability. (find_what_var_points_to): New function. (find_what_p_points_to): Implement in terms of find_what_var_points_to. (pt_solution_reset, pt_solution_empty_p, pt_solution_includes_global, pt_solution_includes_1, pt_solution_includes, pt_solutions_intersect_1, pt_solutions_intersect): New functions. (compute_call_used_vars): Remove. (compute_may_aliases): New main entry into PTA computation. * gimple.h (gimple_p): New typedef. (struct gimple_statement_base): Remove references_memory_p. (struct gimple_statement_with_memory_ops_base): Remove vdef_ops, vuse_ops, stores and loads members. Add vdef and vuse members. (gimple_vuse_ops, gimple_set_vuse_ops, gimple_vdef_ops, gimple_set_vdef_ops, gimple_loaded_syms, gimple_stored_syms, gimple_set_references_memory): Remove. (gimple_vuse_op, gimple_vdef_op, gimple_vuse, gimple_vdef, gimple_vuse_ptr, gimple_vdef_ptri, gimple_set_vuse, gimple_set_vdef): New functions. * tree-cfg.c (move_block_to_fn): Fix off-by-one error. (verify_expr): Allow RESULT_DECL. (gimple_duplicate_bb): Do not copy virtual operands. (gimple_duplicate_sese_region): Adjust. (gimple_duplicate_sese_tail): Likewise. (mark_virtual_ops_in_region): Remove. (move_sese_region_to_fn): Do not call it. * passes.c (init_optimization_passes): Remove pass_reset_cc_flags and pass_simple_dse. (execute_function_todo): Handle TODO_update_address_taken, call execute_update_addresses_taken for TODO_rebuild_alias. (execute_todo): Adjust. (execute_one_pass): Init dump files early. * ipa-struct-reorg.c (finalize_var_creation): Do not mark vars call-clobbered. (create_general_new_stmt): Clear vops. * tree-ssa-reassoc.c (get_rank): Adjust. * tree-vect-slp.c (vect_create_mask_and_perm): Do not mark symbols for renaming. * params.def (PARAM_MAX_ALIASED_VOPS): Remove. (PARAM_AVG_ALIASED_VOPS): Likewise. * tree-ssanames.c (init_ssanames): Allocate SYMS_TO_RENAME. (duplicate_ssa_name_ptr_info): No need to copy the shared bitmaps. * tree-ssa-operands.c: Simplify for new virtual operand representation. (operand_build_cmp, copy_virtual_operands, create_ssa_artificial_load_stmt, add_to_addressable_set, gimple_add_to_addresses_taken): Remove public functions. (unlink_stmt_vdef): New function. * gcc.dg/pr19633-1.c: Adjust. * gcc.dg/torture/pta-callused-1.c: Likewise. * gcc.dg/torture/pr39074-2.c: Likewise. * gcc.dg/torture/pr39074.c: Likewise. * gcc.dg/torture/pta-ptrarith-3.c: New testcase. * gcc.dg/torture/pr30375.c: Adjust. * gcc.dg/torture/pr33563.c: Likewise. * gcc.dg/torture/pr33870.c: Likewise. * gcc.dg/torture/pr33560.c: Likewise. * gcc.dg/torture/pta-structcopy-1.c: New testcase. * gcc.dg/torture/ssa-pta-fn-1.c: Likewise. * gcc.dg/tree-ssa/alias-15.c: Remove. * gcc.dg/tree-ssa/ssa-dce-4.c: New testcase. * gcc.dg/tree-ssa/pr26421.c: Adjust. * gcc.dg/tree-ssa/ssa-fre-10.c: XFAIL. * gcc.dg/tree-ssa/ssa-dce-5.c: New testcase. * gcc.dg/tree-ssa/pr23382.c: Adjust. * gcc.dg/tree-ssa/ssa-fre-20.c: New testcase. * gcc.dg/tree-ssa/alias-16.c: Adjust. * gcc.dg/tree-ssa/ssa-fre-13.c: Likewise. * gcc.dg/tree-ssa/ssa-fre-14.c: Likewise. * gcc.dg/tree-ssa/alias-18.c: Likewise. * gcc.dg/tree-ssa/ssa-fre-15.c: Likewise. * gcc.dg/tree-ssa/ssa-lim-3.c: Likewise. * gcc.dg/tree-ssa/alias-19.c: Likewise. * gcc.dg/tree-ssa/pta-ptrarith-1.c: New testcase. * gcc.dg/tree-ssa/pr13146.c: Likewise. * gcc.dg/tree-ssa/ssa-pre-23.c: Likewise. * gcc.dg/tree-ssa/pta-ptrarith-2.c: Likewise. * gcc.dg/tree-ssa/ssa-fre-18.c: Likewise. * gcc.dg/tree-ssa/ssa-pre-24.c: New XFAILed testcase. * gcc.dg/tree-ssa/ssa-fre-19.c: New testcase. * gcc.dg/tree-ssa/alias-20.c: Likewise. * gcc.dg/tree-ssa/ssa-dse-12.c: Likewise. * gcc.dg/tree-ssa/pr38895.c: Likewise. * gcc.dg/uninit-B.c: XFAIL. * gcc.dg/vect/no-vfa-vect-43.c: Adjust. * gcc.dg/uninit-pr19430.c: XFAIL. * g++.dg/tree-ssa/pr13146.C: New testcase. * g++.dg/opt/pr36187.C: Adjust. * g++.dg/torture/20090329-1.C: New testcase. From-SVN: r145494
Diffstat (limited to 'gcc/tree-ssa-alias.c')
-rw-r--r--gcc/tree-ssa-alias.c4252
1 files changed, 793 insertions, 3459 deletions
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 4dd4fb7..a85858e 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -40,7 +40,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree-flow.h"
#include "tree-inline.h"
#include "tree-pass.h"
-#include "tree-ssa-structalias.h"
#include "convert.h"
#include "params.h"
#include "ipa-type-escape.h"
@@ -49,3078 +48,183 @@ along with GCC; see the file COPYING3. If not see
#include "vecprim.h"
#include "pointer-set.h"
#include "alloc-pool.h"
+#include "tree-ssa-alias.h"
-/* Broad overview of how aliasing works:
-
- First we compute points-to sets, which is done in
- tree-ssa-structalias.c
-
- During points-to set constraint finding, a bunch of little bits of
- information is collected.
- This is not done because it is necessary for points-to, but because
- points-to has to walk every statement anyway. The function performing
- this collecting is update_alias_info.
-
- Bits update_alias_info collects include:
- 1. Directly escaping variables and variables whose value escapes
- (using is_escape_site). This is the set of variables and values that
- escape prior to transitive closure of the clobbers.
- 2. The set of variables dereferenced on the LHS (into
- dereferenced_ptr_stores)
- 3. The set of variables dereferenced on the RHS (into
- dereferenced_ptr_loads)
- 4. The set of all pointers we saw.
- 5. The number of loads and stores for each variable
- 6. The number of statements touching memory
- 7. The set of address taken variables.
-
-
- #1 is computed by a combination of is_escape_site, and counting the
- number of uses/deref operators. This function properly accounts for
- situations like &ptr->field, which is *not* a dereference.
-
- After points-to sets are computed, the sets themselves still
- contain points-to specific variables, such as a variable that says
- the pointer points to anything, a variable that says the pointer
- points to readonly memory, etc.
-
- These are eliminated in a later phase, as we will see.
-
- The rest of the phases are located in tree-ssa-alias.c
-
- The next phase after points-to set computation is called
- "setup_pointers_and_addressables"
-
- This pass does 3 main things:
-
- 1. All variables that can have TREE_ADDRESSABLE removed safely (IE
- non-globals whose address is not taken), have TREE_ADDRESSABLE
- removed.
- 2. All variables that may be aliased (which is the set of addressable
- variables and globals) at all, are marked for renaming, and have
- symbol memory tags created for them.
- 3. All variables which are stored into have their SMT's added to
- written vars.
-
-
- After this function is run, all variables that will ever have an
- SMT, have one, though its aliases are not filled in.
-
- The next phase is to compute flow-insensitive aliasing, which in
- our case, is a misnomer. it is really computing aliasing that
- requires no transitive closure to be correct. In particular, it
- uses stack vs non-stack, TBAA, etc, to determine whether two
- symbols could *ever* alias . This phase works by going through all
- the pointers we collected during update_alias_info, and for every
- addressable variable in the program, seeing if they alias. If so,
- the addressable variable is added to the symbol memory tag for the
- pointer.
-
- As part of this, we handle symbol memory tags that conflict but
- have no aliases in common, by forcing them to have a symbol in
- common (through unioning alias sets or adding one as an alias of
- the other), or by adding one as an alias of another. The case of
- conflicts with no aliases in common occurs mainly due to aliasing
- we cannot see. In particular, it generally means we have a load
- through a pointer whose value came from outside the function.
- Without an addressable symbol to point to, they would get the wrong
- answer.
-
- After flow insensitive aliasing is computed, we compute name tags
- (called compute_flow_sensitive_info). We walk each pointer we
- collected and see if it has a usable points-to set. If so, we
- generate a name tag using that pointer, and make an alias bitmap for
- it. Name tags are shared between all things with the same alias
- bitmap. The alias bitmap will be translated from what points-to
- computed. In particular, the "anything" variable in points-to will be
- transformed into a pruned set of SMT's and their aliases that
- compute_flow_insensitive_aliasing computed.
- Note that since 4.3, every pointer that points-to computed a solution for
- will get a name tag (whereas before 4.3, only those whose set did
- *not* include the anything variable would). At the point where name
- tags are all assigned, symbol memory tags are dead, and could be
- deleted, *except* on global variables. Global variables still use
- symbol memory tags as of right now.
-
- After name tags are computed, the set of clobbered variables is
- transitively closed. In particular, we compute the set of clobbered
- variables based on the initial set of clobbers, plus the aliases of
- pointers which either escape, or have their value escape.
-
- After this, maybe_create_global_var is run, which handles a corner
- case where we have no call clobbered variables, but have pure and
- non-pure functions.
-
- Staring at this function, I now remember it is a hack for the fact
- that we do not mark all globals in the program as call clobbered for a
- function unless they are actually used in that function. Instead, we
- only mark the set that is actually clobbered. As a result, you can
- end up with situations where you have no call clobbered vars set.
-
- After maybe_create_global_var, we set pointers with the REF_ALL flag
- to have alias sets that include all clobbered
- memory tags and variables.
-
- After this, memory partitioning is computed (by the function
- compute_memory_partitions) and alias sets are reworked accordingly.
-
- Lastly, we delete partitions with no symbols, and clean up after
- ourselves. */
-
-
-/* Alias information used by compute_may_aliases and its helpers. */
-struct alias_info
-{
- /* SSA names visited while collecting points-to information. If bit I
- is set, it means that SSA variable with version I has already been
- visited. */
- sbitmap ssa_names_visited;
-
- /* Array of SSA_NAME pointers processed by the points-to collector. */
- VEC(tree,heap) *processed_ptrs;
-
- /* ADDRESSABLE_VARS contains all the global variables and locals that
- have had their address taken. */
- struct alias_map_d **addressable_vars;
- size_t num_addressable_vars;
-
- /* POINTERS contains all the _DECL pointers with unique memory tags
- that have been referenced in the program. */
- struct alias_map_d **pointers;
- size_t num_pointers;
-
- /* Pointers that have been used in an indirect load/store operation. */
- struct pointer_set_t *dereferenced_ptrs;
-};
-
-
-/* Structure to map a variable to its alias set. */
-struct alias_map_d
-{
- /* Variable and its alias set. */
- tree var;
- alias_set_type set;
-};
-
-
-/* Counters used to display statistics on alias analysis. */
-struct alias_stats_d
-{
- unsigned int alias_queries;
- unsigned int alias_mayalias;
- unsigned int alias_noalias;
- unsigned int simple_queries;
- unsigned int simple_resolved;
- unsigned int tbaa_queries;
- unsigned int tbaa_resolved;
- unsigned int structnoaddress_queries;
- unsigned int structnoaddress_resolved;
-};
-
-
-/* Local variables. */
-static struct alias_stats_d alias_stats;
-static bitmap_obstack alias_bitmap_obstack;
-
-/* Local functions. */
-static void compute_flow_insensitive_aliasing (struct alias_info *);
-static void dump_alias_stats (FILE *);
-static tree create_memory_tag (tree type, bool is_type_tag);
-static tree get_smt_for (tree, struct alias_info *);
-static tree get_nmt_for (tree);
-static void add_may_alias (tree, tree);
-static struct alias_info *init_alias_info (void);
-static void delete_alias_info (struct alias_info *);
-static void compute_flow_sensitive_aliasing (struct alias_info *);
-static void setup_pointers_and_addressables (struct alias_info *);
-static void update_alias_info (struct alias_info *);
-static void create_global_var (void);
-static void maybe_create_global_var (void);
-static void set_pt_anything (tree);
-
-void debug_mp_info (VEC(mem_sym_stats_t,heap) *);
-
-static alloc_pool mem_sym_stats_pool;
-
-/* Return memory reference stats for symbol VAR. Create a new slot in
- cfun->gimple_df->mem_sym_stats if needed. */
-
-static struct mem_sym_stats_d *
-get_mem_sym_stats_for (tree var)
-{
- void **slot;
- struct mem_sym_stats_d *stats;
- struct pointer_map_t *map = gimple_mem_ref_stats (cfun)->mem_sym_stats;
-
- gcc_assert (map);
-
- slot = pointer_map_insert (map, var);
- if (*slot == NULL)
- {
- stats = (struct mem_sym_stats_d *) pool_alloc (mem_sym_stats_pool);
- memset (stats, 0, sizeof (*stats));
- stats->var = var;
- *slot = (void *) stats;
- }
- else
- stats = (struct mem_sym_stats_d *) *slot;
+/* Broad overview of how alias analysis on gimple works:
- return stats;
-}
+ Statements clobbering or using memory are linked through the
+ virtual operand factored use-def chain. The virtual operand
+ is unique per function, its symbol is accessible via gimple_vop (cfun).
+ Virtual operands are used for efficiently walking memory statements
+ in the gimple IL and are useful for things like value-numbering as
+ a generation count for memory references.
+ SSA_NAME pointers may have associated points-to information
+ accessible via the SSA_NAME_PTR_INFO macro. Flow-insensitive
+ points-to information is (re-)computed by the TODO_rebuild_alias
+ pass manager todo. Points-to information is also used for more
+ precise tracking of call-clobbered and call-used variables and
+ related disambiguations.
-/* Return memory reference statistics for variable VAR in function FN.
- This is computed by alias analysis, but it is not kept
- incrementally up-to-date. So, these stats are only accurate if
- pass_may_alias has been run recently. If no alias information
- exists, this function returns NULL. */
+ This file contains functions for disambiguating memory references,
+ the so called alias-oracle and tools for walking of the gimple IL.
-static mem_sym_stats_t
-mem_sym_stats (struct function *fn, tree var)
-{
- void **slot;
- struct pointer_map_t *stats_map = gimple_mem_ref_stats (fn)->mem_sym_stats;
+ The main alias-oracle entry-points are
- if (stats_map == NULL)
- return NULL;
+ bool stmt_may_clobber_ref_p (gimple, tree)
- slot = pointer_map_contains (stats_map, var);
- if (slot == NULL)
- return NULL;
+ This function queries if a statement may invalidate (parts of)
+ the memory designated by the reference tree argument.
- return (mem_sym_stats_t) *slot;
-}
+ bool ref_maybe_used_by_stmt_p (gimple, tree)
+ This function queries if a statement may need (parts of) the
+ memory designated by the reference tree argument.
-/* Set MPT to be the memory partition associated with symbol SYM. */
-
-static inline void
-set_memory_partition (tree sym, tree mpt)
-{
-#if defined ENABLE_CHECKING
- if (mpt)
- gcc_assert (TREE_CODE (mpt) == MEMORY_PARTITION_TAG
- && !is_gimple_reg (sym));
-#endif
-
- var_ann (sym)->mpt = mpt;
- if (mpt)
- {
- if (MPT_SYMBOLS (mpt) == NULL)
- MPT_SYMBOLS (mpt) = BITMAP_ALLOC (&alias_bitmap_obstack);
-
- bitmap_set_bit (MPT_SYMBOLS (mpt), DECL_UID (sym));
+ There are variants of these functions that only handle the call
+ part of a statement, call_may_clobber_ref_p and ref_maybe_used_by_call_p.
+ Note that these do not disambiguate against a possible call lhs.
- /* MPT inherits the call-clobbering attributes from SYM. */
- if (is_call_clobbered (sym))
- {
- MTAG_GLOBAL (mpt) = 1;
- mark_call_clobbered (mpt, ESCAPE_IS_GLOBAL);
- }
- }
-}
-
-
-/* Mark variable VAR as being non-addressable. */
-
-static void
-mark_non_addressable (tree var)
-{
- tree mpt;
+ bool refs_may_alias_p (tree, tree)
- if (!TREE_ADDRESSABLE (var))
- return;
+ This function tries to disambiguate two reference trees.
- mpt = memory_partition (var);
+ bool ptr_deref_may_alias_global_p (tree)
- clear_call_clobbered (var);
- TREE_ADDRESSABLE (var) = 0;
-
- if (mpt)
- {
- /* Note that it's possible for a symbol to have an associated
- MPT and the MPT have a NULL empty set. During
- init_alias_info, all MPTs get their sets cleared out, but the
- symbols still point to the old MPTs that used to hold them.
- This is done so that compute_memory_partitions can now which
- symbols are losing or changing partitions and mark them for
- renaming. */
- if (MPT_SYMBOLS (mpt))
- bitmap_clear_bit (MPT_SYMBOLS (mpt), DECL_UID (var));
- set_memory_partition (var, NULL_TREE);
- }
-}
-
-
-/* qsort comparison function to sort type/name tags by DECL_UID. */
-
-static int
-sort_tags_by_id (const void *pa, const void *pb)
-{
- const_tree const a = *(const_tree const *)pa;
- const_tree const b = *(const_tree const *)pb;
-
- return DECL_UID (a) - DECL_UID (b);
-}
-
-/* Initialize WORKLIST to contain those memory tags that are marked call
- clobbered. Initialized WORKLIST2 to contain the reasons these
- memory tags escaped. */
-
-static void
-init_transitive_clobber_worklist (VEC (tree, heap) **worklist,
- VEC (int, heap) **worklist2,
- bitmap on_worklist)
-{
- referenced_var_iterator rvi;
- tree curr;
-
- FOR_EACH_REFERENCED_VAR (curr, rvi)
- {
- if (MTAG_P (curr) && is_call_clobbered (curr))
- {
- VEC_safe_push (tree, heap, *worklist, curr);
- VEC_safe_push (int, heap, *worklist2,
- var_ann (curr)->escape_mask);
- bitmap_set_bit (on_worklist, DECL_UID (curr));
- }
- }
-}
-
-/* Add ALIAS to WORKLIST (and the reason for escaping REASON to WORKLIST2) if
- ALIAS is not already marked call clobbered, and is a memory
- tag. */
-
-static void
-add_to_worklist (tree alias, VEC (tree, heap) **worklist,
- VEC (int, heap) **worklist2, int reason,
- bitmap on_worklist)
-{
- if (MTAG_P (alias) && !is_call_clobbered (alias)
- && !bitmap_bit_p (on_worklist, DECL_UID (alias)))
- {
- VEC_safe_push (tree, heap, *worklist, alias);
- VEC_safe_push (int, heap, *worklist2, reason);
- bitmap_set_bit (on_worklist, DECL_UID (alias));
- }
-}
-
-/* Mark aliases of TAG as call clobbered, and place any tags on the
- alias list that were not already call clobbered on WORKLIST. */
-
-static void
-mark_aliases_call_clobbered (tree tag, VEC (tree, heap) **worklist,
- VEC (int, heap) **worklist2, bitmap on_worklist)
-{
- bitmap aliases;
- bitmap_iterator bi;
- unsigned int i;
- tree entry;
- var_ann_t ta = var_ann (tag);
-
- if (!MTAG_P (tag))
- return;
- aliases = may_aliases (tag);
- if (!aliases)
- return;
-
- EXECUTE_IF_SET_IN_BITMAP (aliases, 0, i, bi)
- {
- entry = referenced_var (i);
- /* If you clobber one part of a structure, you
- clobber the entire thing. While this does not make
- the world a particularly nice place, it is necessary
- in order to allow C/C++ tricks that involve
- pointer arithmetic to work. */
- if (!unmodifiable_var_p (entry))
- {
- add_to_worklist (entry, worklist, worklist2, ta->escape_mask,
- on_worklist);
- mark_call_clobbered (entry, ta->escape_mask);
- }
- }
-}
+ This function queries if dereferencing a pointer variable may
+ alias global memory.
-/* Tags containing global vars need to be marked as global.
- Tags containing call clobbered vars need to be marked as call
- clobbered. */
+ More low-level disambiguators are available and documented in
+ this file. Low-level disambiguators dealing with points-to
+ information are in tree-ssa-structalias.c. */
-static void
-compute_tag_properties (void)
-{
- referenced_var_iterator rvi;
- tree tag;
- bool changed = true;
- VEC (tree, heap) *taglist = NULL;
-
- FOR_EACH_REFERENCED_VAR (tag, rvi)
- {
- if (!MTAG_P (tag))
- continue;
- VEC_safe_push (tree, heap, taglist, tag);
- }
-
- /* We sort the taglist by DECL_UID, for two reasons.
- 1. To get a sequential ordering to make the bitmap accesses
- faster.
- 2. Because of the way we compute aliases, it's more likely that
- an earlier tag is included in a later tag, and this will reduce
- the number of iterations.
-
- If we had a real tag graph, we would just topo-order it and be
- done with it. */
- qsort (VEC_address (tree, taglist),
- VEC_length (tree, taglist),
- sizeof (tree),
- sort_tags_by_id);
-
- /* Go through each tag not marked as global, and if it aliases
- global vars, mark it global.
-
- If the tag contains call clobbered vars, mark it call
- clobbered.
-
- This loop iterates because tags may appear in the may-aliases
- list of other tags when we group. */
-
- while (changed)
- {
- unsigned int k;
-
- changed = false;
- for (k = 0; VEC_iterate (tree, taglist, k, tag); k++)
- {
- bitmap ma;
- bitmap_iterator bi;
- unsigned int i;
- tree entry;
- bool tagcc = is_call_clobbered (tag);
- bool tagglobal = MTAG_GLOBAL (tag);
-
- if (tagcc && tagglobal)
- continue;
-
- ma = may_aliases (tag);
- if (!ma)
- continue;
-
- EXECUTE_IF_SET_IN_BITMAP (ma, 0, i, bi)
- {
- entry = referenced_var (i);
- /* Call clobbered entries cause the tag to be marked
- call clobbered. */
- if (!tagcc && is_call_clobbered (entry))
- {
- mark_call_clobbered (tag, var_ann (entry)->escape_mask);
- tagcc = true;
- changed = true;
- }
-
- /* Global vars cause the tag to be marked global. */
- if (!tagglobal && is_global_var (entry))
- {
- MTAG_GLOBAL (tag) = true;
- changed = true;
- tagglobal = true;
- }
-
- /* Early exit once both global and cc are set, since the
- loop can't do any more than that. */
- if (tagcc && tagglobal)
- break;
- }
- }
- }
- VEC_free (tree, heap, taglist);
-}
-
-/* Set up the initial variable clobbers, call-uses and globalness.
- When this function completes, only tags whose aliases need to be
- clobbered will be set clobbered. Tags clobbered because they
- contain call clobbered vars are handled in compute_tag_properties. */
-
-static void
-set_initial_properties (struct alias_info *ai)
-{
- unsigned int i;
- referenced_var_iterator rvi;
- tree var;
- tree ptr;
- bool any_pt_anything = false;
- enum escape_type pt_anything_mask = 0;
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (is_global_var (var))
- {
- if (!unmodifiable_var_p (var))
- mark_call_clobbered (var, ESCAPE_IS_GLOBAL);
- }
- else if (TREE_CODE (var) == PARM_DECL
- && gimple_default_def (cfun, var)
- && POINTER_TYPE_P (TREE_TYPE (var)))
- {
- tree def = gimple_default_def (cfun, var);
- get_ptr_info (def)->value_escapes_p = 1;
- get_ptr_info (def)->escape_mask |= ESCAPE_IS_PARM;
- }
- }
-
- if (!clobber_what_escaped ())
- {
- any_pt_anything = true;
- pt_anything_mask |= ESCAPE_TO_CALL;
- }
-
- compute_call_used_vars ();
-
- for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
- tree tag = symbol_mem_tag (SSA_NAME_VAR (ptr));
-
- /* A pointer that only escapes via a function return does not
- add to the call clobber or call used solution.
- To exclude ESCAPE_TO_PURE_CONST we would need to track
- call used variables separately or compute those properly
- in the operand scanner. */
- if (pi->value_escapes_p
- && pi->escape_mask & ~ESCAPE_TO_RETURN)
- {
- /* If PTR escapes then its associated memory tags and
- pointed-to variables are call-clobbered. */
- if (pi->name_mem_tag)
- mark_call_clobbered (pi->name_mem_tag, pi->escape_mask);
-
- if (tag)
- mark_call_clobbered (tag, pi->escape_mask);
- }
-
- /* If the name tag is call clobbered, so is the symbol tag
- associated with the base VAR_DECL. */
- if (pi->name_mem_tag
- && tag
- && is_call_clobbered (pi->name_mem_tag))
- mark_call_clobbered (tag, pi->escape_mask);
-
- /* Name tags and symbol tags that we don't know where they point
- to, might point to global memory, and thus, are clobbered.
-
- FIXME: This is not quite right. They should only be
- clobbered if value_escapes_p is true, regardless of whether
- they point to global memory or not.
- So removing this code and fixing all the bugs would be nice.
- It is the cause of a bunch of clobbering. */
- if ((pi->pt_global_mem || pi->pt_anything)
- && pi->memory_tag_needed && pi->name_mem_tag)
- {
- mark_call_clobbered (pi->name_mem_tag, ESCAPE_IS_GLOBAL);
- MTAG_GLOBAL (pi->name_mem_tag) = true;
- }
-
- if ((pi->pt_global_mem || pi->pt_anything)
- && pi->memory_tag_needed
- && tag)
- {
- mark_call_clobbered (tag, ESCAPE_IS_GLOBAL);
- MTAG_GLOBAL (tag) = true;
- }
- }
-
- /* If a pt_anything pointer escaped we need to mark all addressable
- variables call clobbered. */
- if (any_pt_anything)
- {
- bitmap_iterator bi;
- unsigned int j;
-
- EXECUTE_IF_SET_IN_BITMAP (gimple_addressable_vars (cfun), 0, j, bi)
- {
- tree var = referenced_var (j);
- if (!unmodifiable_var_p (var))
- mark_call_clobbered (var, pt_anything_mask);
- }
- }
-}
-
-/* Compute which variables need to be marked call clobbered because
- their tag is call clobbered, and which tags need to be marked
- global because they contain global variables. */
-
-static void
-compute_call_clobbered (struct alias_info *ai)
-{
- VEC (tree, heap) *worklist = NULL;
- VEC (int,heap) *worklist2 = NULL;
- bitmap on_worklist;
-
- timevar_push (TV_CALL_CLOBBER);
- on_worklist = BITMAP_ALLOC (NULL);
-
- set_initial_properties (ai);
- init_transitive_clobber_worklist (&worklist, &worklist2, on_worklist);
- while (VEC_length (tree, worklist) != 0)
- {
- tree curr = VEC_pop (tree, worklist);
- int reason = VEC_pop (int, worklist2);
-
- bitmap_clear_bit (on_worklist, DECL_UID (curr));
- mark_call_clobbered (curr, reason);
- mark_aliases_call_clobbered (curr, &worklist, &worklist2, on_worklist);
- }
- VEC_free (tree, heap, worklist);
- VEC_free (int, heap, worklist2);
- BITMAP_FREE (on_worklist);
- compute_tag_properties ();
- timevar_pop (TV_CALL_CLOBBER);
-}
-
-
-/* Dump memory partition information to FILE. */
-
-static void
-dump_memory_partitions (FILE *file)
-{
- unsigned i, npart;
- unsigned long nsyms;
- tree mpt;
-
- fprintf (file, "\nMemory partitions\n\n");
- for (i = 0, npart = 0, nsyms = 0;
- VEC_iterate (tree, gimple_ssa_operands (cfun)->mpt_table, i, mpt);
- i++)
- {
- if (mpt)
- {
- bitmap syms = MPT_SYMBOLS (mpt);
- unsigned long n = (syms) ? bitmap_count_bits (syms) : 0;
-
- fprintf (file, "#%u: ", i);
- print_generic_expr (file, mpt, 0);
- fprintf (file, ": %lu elements: ", n);
- dump_decl_set (file, syms);
- npart++;
- nsyms += n;
- }
- }
-
- fprintf (file, "\n%u memory partitions holding %lu symbols\n", npart, nsyms);
-}
+/* Query statistics for the different low-level disambiguators.
+ A high-level query may trigger multiple of them. */
-/* Dump memory partition information to stderr. */
+static struct {
+ unsigned HOST_WIDE_INT refs_may_alias_p_may_alias;
+ unsigned HOST_WIDE_INT refs_may_alias_p_no_alias;
+ unsigned HOST_WIDE_INT ref_maybe_used_by_call_p_may_alias;
+ unsigned HOST_WIDE_INT ref_maybe_used_by_call_p_no_alias;
+ unsigned HOST_WIDE_INT call_may_clobber_ref_p_may_alias;
+ unsigned HOST_WIDE_INT call_may_clobber_ref_p_no_alias;
+} alias_stats;
void
-debug_memory_partitions (void)
-{
- dump_memory_partitions (stderr);
-}
-
-
-/* Return true if memory partitioning is required given the memory
- reference estimates in STATS. */
-
-static inline bool
-need_to_partition_p (struct mem_ref_stats_d *stats)
-{
- long num_vops = stats->num_vuses + stats->num_vdefs;
- long avg_vops = CEIL (num_vops, stats->num_mem_stmts);
- return (num_vops > (long) MAX_ALIASED_VOPS
- && avg_vops > (long) AVG_ALIASED_VOPS);
-}
-
-
-/* Count the actual number of virtual operators in CFUN. Note that
- this is only meaningful after virtual operands have been populated,
- so it should be invoked at the end of compute_may_aliases.
-
- The number of virtual operators are stored in *NUM_VDEFS_P and
- *NUM_VUSES_P, the number of partitioned symbols in
- *NUM_PARTITIONED_P and the number of unpartitioned symbols in
- *NUM_UNPARTITIONED_P.
-
- If any of these pointers is NULL the corresponding count is not
- computed. */
-
-static void
-count_mem_refs (long *num_vuses_p, long *num_vdefs_p,
- long *num_partitioned_p, long *num_unpartitioned_p)
-{
- gimple_stmt_iterator gsi;
- basic_block bb;
- long num_vdefs, num_vuses, num_partitioned, num_unpartitioned;
- referenced_var_iterator rvi;
- tree sym;
-
- num_vuses = num_vdefs = num_partitioned = num_unpartitioned = 0;
-
- if (num_vuses_p || num_vdefs_p)
- FOR_EACH_BB (bb)
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple stmt = gsi_stmt (gsi);
- if (gimple_references_memory_p (stmt))
- {
- num_vuses += NUM_SSA_OPERANDS (stmt, SSA_OP_VUSE);
- num_vdefs += NUM_SSA_OPERANDS (stmt, SSA_OP_VDEF);
- }
- }
-
- if (num_partitioned_p || num_unpartitioned_p)
- FOR_EACH_REFERENCED_VAR (sym, rvi)
- {
- if (is_gimple_reg (sym))
- continue;
-
- if (memory_partition (sym))
- num_partitioned++;
- else
- num_unpartitioned++;
- }
-
- if (num_vdefs_p)
- *num_vdefs_p = num_vdefs;
-
- if (num_vuses_p)
- *num_vuses_p = num_vuses;
-
- if (num_partitioned_p)
- *num_partitioned_p = num_partitioned;
-
- if (num_unpartitioned_p)
- *num_unpartitioned_p = num_unpartitioned;
-}
-
-
-/* The list is sorted by increasing partitioning score (PSCORE).
- This score is computed such that symbols with high scores are
- those that are least likely to be partitioned. Given a symbol
- MP->VAR, PSCORE(S) is the result of the following weighted sum
-
- PSCORE(S) = FW * 64 + FR * 32
- + DW * 16 + DR * 8
- + IW * 4 + IR * 2
- + NO_ALIAS
-
- where
-
- FW Execution frequency of writes to S
- FR Execution frequency of reads from S
- DW Number of direct writes to S
- DR Number of direct reads from S
- IW Number of indirect writes to S
- IR Number of indirect reads from S
- NO_ALIAS State of the NO_ALIAS* flags
-
- The basic idea here is that symbols that are frequently
- written-to in hot paths of the code are the last to be considered
- for partitioning. */
-
-static inline long
-mem_sym_score (mem_sym_stats_t mp)
-{
- return mp->frequency_writes * 64 + mp->frequency_reads * 32
- + mp->num_direct_writes * 16 + mp->num_direct_reads * 8
- + mp->num_indirect_writes * 4 + mp->num_indirect_reads * 2
- + var_ann (mp->var)->noalias_state;
-}
-
-
-/* Dump memory reference stats for function CFUN to FILE. */
-
-void
-dump_mem_ref_stats (FILE *file)
-{
- long actual_num_vuses, actual_num_vdefs;
- long num_partitioned, num_unpartitioned;
- struct mem_ref_stats_d *stats;
-
- stats = gimple_mem_ref_stats (cfun);
-
- count_mem_refs (&actual_num_vuses, &actual_num_vdefs, &num_partitioned,
- &num_unpartitioned);
-
- fprintf (file, "\nMemory reference statistics for %s\n\n",
- lang_hooks.decl_printable_name (current_function_decl, 2));
-
- fprintf (file, "Number of memory statements: %ld\n",
- stats->num_mem_stmts);
- fprintf (file, "Number of call sites: %ld\n",
- stats->num_call_sites);
- fprintf (file, "Number of pure/const call sites: %ld\n",
- stats->num_pure_const_call_sites);
- fprintf (file, "Number of asm sites: %ld\n",
- stats->num_asm_sites);
- fprintf (file, "Estimated number of loads: %ld (%ld/stmt)\n",
- stats->num_vuses,
- (stats->num_mem_stmts)
- ? CEIL (stats->num_vuses, stats->num_mem_stmts)
- : 0);
- fprintf (file, "Actual number of loads: %ld (%ld/stmt)\n",
- actual_num_vuses,
- (stats->num_mem_stmts)
- ? CEIL (actual_num_vuses, stats->num_mem_stmts)
- : 0);
-
- if (actual_num_vuses > stats->num_vuses + (stats->num_vuses / 25))
- fprintf (file, "\t(warning: estimation is lower by more than 25%%)\n");
-
- fprintf (file, "Estimated number of stores: %ld (%ld/stmt)\n",
- stats->num_vdefs,
- (stats->num_mem_stmts)
- ? CEIL (stats->num_vdefs, stats->num_mem_stmts)
- : 0);
- fprintf (file, "Actual number of stores: %ld (%ld/stmt)\n",
- actual_num_vdefs,
- (stats->num_mem_stmts)
- ? CEIL (actual_num_vdefs, stats->num_mem_stmts)
- : 0);
-
- if (actual_num_vdefs > stats->num_vdefs + (stats->num_vdefs / 25))
- fprintf (file, "\t(warning: estimation is lower by more than 25%%)\n");
-
- fprintf (file, "Partitioning thresholds: MAX = %d AVG = %d "
- "(%sNEED TO PARTITION)\n", MAX_ALIASED_VOPS, AVG_ALIASED_VOPS,
- stats->num_mem_stmts && need_to_partition_p (stats) ? "" : "NO ");
- fprintf (file, "Number of partitioned symbols: %ld\n", num_partitioned);
- fprintf (file, "Number of unpartitioned symbols: %ld\n", num_unpartitioned);
-}
-
-
-/* Dump memory reference stats for function FN to stderr. */
-
-void
-debug_mem_ref_stats (void)
-{
- dump_mem_ref_stats (stderr);
-}
-
-
-/* Dump memory reference stats for variable VAR to FILE. */
-
-static void
-dump_mem_sym_stats (FILE *file, tree var)
-{
- mem_sym_stats_t stats = mem_sym_stats (cfun, var);
-
- if (stats == NULL)
- return;
-
- fprintf (file, "read frequency: %6ld, write frequency: %6ld, "
- "direct reads: %3ld, direct writes: %3ld, "
- "indirect reads: %4ld, indirect writes: %4ld, symbol: ",
- stats->frequency_reads, stats->frequency_writes,
- stats->num_direct_reads, stats->num_direct_writes,
- stats->num_indirect_reads, stats->num_indirect_writes);
- print_generic_expr (file, stats->var, 0);
- fprintf (file, ", tags: ");
- dump_decl_set (file, stats->parent_tags);
-}
-
-
-/* Dump memory reference stats for variable VAR to stderr. */
-
-void
-debug_mem_sym_stats (tree var)
-{
- dump_mem_sym_stats (stderr, var);
-}
-
-/* Dump memory reference stats for variable VAR to FILE. For use
- of tree-dfa.c:dump_variable. */
-
-void
-dump_mem_sym_stats_for_var (FILE *file, tree var)
-{
- mem_sym_stats_t stats = mem_sym_stats (cfun, var);
-
- if (stats == NULL)
- return;
-
- fprintf (file, ", score: %ld", mem_sym_score (stats));
- fprintf (file, ", direct reads: %ld", stats->num_direct_reads);
- fprintf (file, ", direct writes: %ld", stats->num_direct_writes);
- fprintf (file, ", indirect reads: %ld", stats->num_indirect_reads);
- fprintf (file, ", indirect writes: %ld", stats->num_indirect_writes);
-}
-
-/* Dump memory reference stats for all memory symbols to FILE. */
-
-static void
-dump_all_mem_sym_stats (FILE *file)
-{
- referenced_var_iterator rvi;
- tree sym;
-
- FOR_EACH_REFERENCED_VAR (sym, rvi)
- {
- if (is_gimple_reg (sym))
- continue;
-
- dump_mem_sym_stats (file, sym);
- }
-}
-
-
-/* Dump memory reference stats for all memory symbols to stderr. */
-
-void
-debug_all_mem_sym_stats (void)
-{
- dump_all_mem_sym_stats (stderr);
-}
-
-
-/* Dump the MP_INFO array to FILE. */
-
-static void
-dump_mp_info (FILE *file, VEC(mem_sym_stats_t,heap) *mp_info)
-{
- unsigned i;
- mem_sym_stats_t mp_p;
-
- for (i = 0; VEC_iterate (mem_sym_stats_t, mp_info, i, mp_p); i++)
- if (!mp_p->partitioned_p)
- dump_mem_sym_stats (file, mp_p->var);
-}
-
-
-/* Dump the MP_INFO array to stderr. */
-
-void
-debug_mp_info (VEC(mem_sym_stats_t,heap) *mp_info)
-{
- dump_mp_info (stderr, mp_info);
-}
-
-
-/* Update memory reference stats for symbol VAR in statement STMT.
- NUM_DIRECT_READS and NUM_DIRECT_WRITES specify the number of times
- that VAR is read/written in STMT (indirect reads/writes are not
- recorded by this function, see compute_memory_partitions). */
-
-void
-update_mem_sym_stats_from_stmt (tree var, gimple stmt, long num_direct_reads,
- long num_direct_writes)
-{
- mem_sym_stats_t stats;
-
- gcc_assert (num_direct_reads >= 0 && num_direct_writes >= 0);
-
- stats = get_mem_sym_stats_for (var);
-
- stats->num_direct_reads += num_direct_reads;
- stats->frequency_reads += ((long) gimple_bb (stmt)->frequency
- * num_direct_reads);
-
- stats->num_direct_writes += num_direct_writes;
- stats->frequency_writes += ((long) gimple_bb (stmt)->frequency
- * num_direct_writes);
-}
-
-
-/* Given two MP_INFO entries MP1 and MP2, return -1 if MP1->VAR should
- be partitioned before MP2->VAR, 0 if they are the same or 1 if
- MP1->VAR should be partitioned after MP2->VAR. */
-
-static inline int
-compare_mp_info_entries (mem_sym_stats_t mp1, mem_sym_stats_t mp2)
-{
- long pscore1 = mem_sym_score (mp1);
- long pscore2 = mem_sym_score (mp2);
-
- if (pscore1 < pscore2)
- return -1;
- else if (pscore1 > pscore2)
- return 1;
- else
- return DECL_UID (mp1->var) - DECL_UID (mp2->var);
-}
-
-
-/* Comparison routine for qsort. The list is sorted by increasing
- partitioning score (PSCORE). This score is computed such that
- symbols with high scores are those that are least likely to be
- partitioned. */
-
-static int
-mp_info_cmp (const void *p, const void *q)
-{
- mem_sym_stats_t e1 = *((const mem_sym_stats_t *) p);
- mem_sym_stats_t e2 = *((const mem_sym_stats_t *) q);
- return compare_mp_info_entries (e1, e2);
-}
-
-
-/* Sort the array of reference counts used to compute memory partitions.
- Elements are sorted in ascending order of execution frequency and
- descending order of virtual operators needed. */
-
-static inline void
-sort_mp_info (VEC(mem_sym_stats_t,heap) *list)
-{
- unsigned num = VEC_length (mem_sym_stats_t, list);
-
- if (num < 2)
- return;
-
- if (num == 2)
- {
- if (compare_mp_info_entries (VEC_index (mem_sym_stats_t, list, 0),
- VEC_index (mem_sym_stats_t, list, 1)) > 0)
- {
- /* Swap elements if they are in the wrong order. */
- mem_sym_stats_t tmp = VEC_index (mem_sym_stats_t, list, 0);
- VEC_replace (mem_sym_stats_t, list, 0,
- VEC_index (mem_sym_stats_t, list, 1));
- VEC_replace (mem_sym_stats_t, list, 1, tmp);
- }
-
- return;
- }
-
- /* There are 3 or more elements, call qsort. */
- qsort (VEC_address (mem_sym_stats_t, list),
- VEC_length (mem_sym_stats_t, list),
- sizeof (mem_sym_stats_t),
- mp_info_cmp);
-}
-
-
-/* Return the memory partition tag (MPT) associated with memory
- symbol SYM. */
-
-static tree
-get_mpt_for (tree sym)
-{
- tree mpt;
-
- /* Don't create a new tag unnecessarily. */
- mpt = memory_partition (sym);
- if (mpt == NULL_TREE)
- {
- mpt = create_tag_raw (MEMORY_PARTITION_TAG, TREE_TYPE (sym), "MPT");
- TREE_ADDRESSABLE (mpt) = 0;
- add_referenced_var (mpt);
- VEC_safe_push (tree, heap, gimple_ssa_operands (cfun)->mpt_table, mpt);
- gcc_assert (MPT_SYMBOLS (mpt) == NULL);
- set_memory_partition (sym, mpt);
- }
-
- return mpt;
-}
-
-
-/* Add MP_P->VAR to a memory partition and return the partition. */
-
-static tree
-find_partition_for (mem_sym_stats_t mp_p)
-{
- unsigned i;
- VEC(tree,heap) *mpt_table;
- tree mpt;
-
- mpt_table = gimple_ssa_operands (cfun)->mpt_table;
- mpt = NULL_TREE;
-
- /* Find an existing partition for MP_P->VAR. */
- for (i = 0; VEC_iterate (tree, mpt_table, i, mpt); i++)
- {
- mem_sym_stats_t mpt_stats;
-
- /* If MPT does not have any symbols yet, use it. */
- if (MPT_SYMBOLS (mpt) == NULL)
- break;
-
- /* Otherwise, see if MPT has common parent tags with MP_P->VAR,
- but avoid grouping clobbered variables with non-clobbered
- variables (otherwise, this tends to creates a single memory
- partition because other call-clobbered variables may have
- common parent tags with non-clobbered ones). */
- mpt_stats = get_mem_sym_stats_for (mpt);
- if (mp_p->parent_tags
- && mpt_stats->parent_tags
- && is_call_clobbered (mpt) == is_call_clobbered (mp_p->var)
- && bitmap_intersect_p (mpt_stats->parent_tags, mp_p->parent_tags))
- break;
-
- /* If no common parent tags are found, see if both MPT and
- MP_P->VAR are call-clobbered. */
- if (is_call_clobbered (mpt) && is_call_clobbered (mp_p->var))
- break;
- }
-
- if (mpt == NULL_TREE)
- mpt = get_mpt_for (mp_p->var);
- else
- set_memory_partition (mp_p->var, mpt);
-
- mp_p->partitioned_p = true;
-
- mark_sym_for_renaming (mp_p->var);
- mark_sym_for_renaming (mpt);
-
- return mpt;
-}
-
-
-/* Rewrite the alias set for TAG to use the newly created partitions.
- If TAG is NULL, rewrite the set of call-clobbered variables.
- NEW_ALIASES is a scratch bitmap to build the new set of aliases for
- TAG. */
-
-static void
-rewrite_alias_set_for (tree tag, bitmap new_aliases)
-{
- bitmap_iterator bi;
- unsigned i;
- tree mpt, sym;
-
- EXECUTE_IF_SET_IN_BITMAP (MTAG_ALIASES (tag), 0, i, bi)
- {
- sym = referenced_var (i);
- mpt = memory_partition (sym);
- if (mpt)
- bitmap_set_bit (new_aliases, DECL_UID (mpt));
- else
- bitmap_set_bit (new_aliases, DECL_UID (sym));
- }
-
- /* Rebuild the may-alias array for TAG. */
- bitmap_copy (MTAG_ALIASES (tag), new_aliases);
-}
-
-
-/* Determine how many virtual operands can be saved by partitioning
- MP_P->VAR into MPT. When a symbol S is thrown inside a partition
- P, every virtual operand that used to reference S will now
- reference P. Whether it reduces the number of virtual operands
- depends on:
-
- 1- Direct references to S are never saved. Instead of the virtual
- operand to S, we will now have a virtual operand to P.
-
- 2- Indirect references to S are reduced only for those memory tags
- holding S that already had other symbols partitioned into P.
- For instance, if a memory tag T has the alias set { a b S c },
- the first time we partition S into P, the alias set will become
- { a b P c }, so no virtual operands will be saved. However, if
- we now partition symbol 'c' into P, then the alias set for T
- will become { a b P }, so we will be saving one virtual operand
- for every indirect reference to 'c'.
-
- 3- Is S is call-clobbered, we save as many virtual operands as
- call/asm sites exist in the code, but only if other
- call-clobbered symbols have been grouped into P. The first
- call-clobbered symbol that we group does not produce any
- savings.
-
- MEM_REF_STATS points to CFUN's memory reference information. */
-
-static void
-estimate_vop_reduction (struct mem_ref_stats_d *mem_ref_stats,
- mem_sym_stats_t mp_p, tree mpt)
-{
- unsigned i;
- bitmap_iterator bi;
- mem_sym_stats_t mpt_stats;
-
- /* We should only get symbols with indirect references here. */
- gcc_assert (mp_p->num_indirect_reads > 0 || mp_p->num_indirect_writes > 0);
-
- /* Note that the only statistics we keep for MPT is the set of
- parent tags to know which memory tags have had alias members
- partitioned, and the indicator has_call_clobbered_vars.
- Reference counts are not important for MPT. */
- mpt_stats = get_mem_sym_stats_for (mpt);
-
- /* Traverse all the parent tags for MP_P->VAR. For every tag T, if
- partition P is already grouping aliases of T, then reduce the
- number of virtual operands by the number of direct references
- to T. */
- if (mp_p->parent_tags)
- {
- if (mpt_stats->parent_tags == NULL)
- mpt_stats->parent_tags = BITMAP_ALLOC (&alias_bitmap_obstack);
-
- EXECUTE_IF_SET_IN_BITMAP (mp_p->parent_tags, 0, i, bi)
- {
- if (bitmap_bit_p (mpt_stats->parent_tags, i))
- {
- /* Partition MPT is already partitioning symbols in the
- alias set for TAG. This means that we are now saving
- 1 virtual operand for every direct reference to TAG. */
- tree tag = referenced_var (i);
- mem_sym_stats_t tag_stats = mem_sym_stats (cfun, tag);
- mem_ref_stats->num_vuses -= tag_stats->num_direct_reads;
- mem_ref_stats->num_vdefs -= tag_stats->num_direct_writes;
- }
- else
- {
- /* This is the first symbol in tag I's alias set that is
- being grouped under MPT. We will not save any
- virtual operands this time, but record that MPT is
- grouping a symbol from TAG's alias set so that the
- next time we get the savings. */
- bitmap_set_bit (mpt_stats->parent_tags, i);
- }
- }
- }
-
- /* If MP_P->VAR is call-clobbered, and MPT is already grouping
- call-clobbered symbols, then we will save as many virtual
- operands as asm/call sites there are. */
- if (is_call_clobbered (mp_p->var))
- {
- if (mpt_stats->has_call_clobbered_vars)
- mem_ref_stats->num_vdefs -= mem_ref_stats->num_call_sites
- + mem_ref_stats->num_asm_sites;
- else
- mpt_stats->has_call_clobbered_vars = true;
- }
-}
-
-
-/* Helper for compute_memory_partitions. Transfer reference counts
- from pointers to their pointed-to sets. Counters for pointers were
- computed by update_alias_info. MEM_REF_STATS points to CFUN's
- memory reference information. */
-
-static void
-update_reference_counts (struct mem_ref_stats_d *mem_ref_stats)
-{
- unsigned i;
- bitmap_iterator bi;
- mem_sym_stats_t sym_stats;
-
- for (i = 1; i < num_ssa_names; i++)
- {
- tree ptr;
- struct ptr_info_def *pi;
-
- ptr = ssa_name (i);
- if (ptr
- && POINTER_TYPE_P (TREE_TYPE (ptr))
- && (pi = SSA_NAME_PTR_INFO (ptr)) != NULL
- && pi->memory_tag_needed)
- {
- unsigned j;
- bitmap_iterator bj;
- tree tag;
- mem_sym_stats_t ptr_stats, tag_stats;
-
- /* If PTR has flow-sensitive points-to information, use
- PTR's name tag, otherwise use the symbol tag associated
- with PTR's symbol. */
- if (pi->name_mem_tag)
- tag = pi->name_mem_tag;
- else
- tag = symbol_mem_tag (SSA_NAME_VAR (ptr));
-
- ptr_stats = get_mem_sym_stats_for (ptr);
- tag_stats = get_mem_sym_stats_for (tag);
-
- /* TAG has as many direct references as dereferences we
- found for its parent pointer. */
- tag_stats->num_direct_reads += ptr_stats->num_direct_reads;
- tag_stats->num_direct_writes += ptr_stats->num_direct_writes;
-
- /* All the dereferences of pointer PTR are considered direct
- references to PTR's memory tag (TAG). In turn,
- references to TAG will become virtual operands for every
- symbol in TAG's alias set. So, for every symbol ALIAS in
- TAG's alias set, add as many indirect references to ALIAS
- as direct references there are for TAG. */
- if (MTAG_ALIASES (tag))
- EXECUTE_IF_SET_IN_BITMAP (MTAG_ALIASES (tag), 0, j, bj)
- {
- tree alias = referenced_var (j);
- sym_stats = get_mem_sym_stats_for (alias);
-
- /* All the direct references to TAG are indirect references
- to ALIAS. */
- sym_stats->num_indirect_reads += ptr_stats->num_direct_reads;
- sym_stats->num_indirect_writes += ptr_stats->num_direct_writes;
- sym_stats->frequency_reads += ptr_stats->frequency_reads;
- sym_stats->frequency_writes += ptr_stats->frequency_writes;
-
- /* Indicate that TAG is one of ALIAS's parent tags. */
- if (sym_stats->parent_tags == NULL)
- sym_stats->parent_tags = BITMAP_ALLOC (&alias_bitmap_obstack);
- bitmap_set_bit (sym_stats->parent_tags, DECL_UID (tag));
- }
- }
- }
-
- /* Call-clobbered symbols are indirectly written at every
- call/asm site. */
- EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, i, bi)
- {
- tree sym = referenced_var (i);
- sym_stats = get_mem_sym_stats_for (sym);
- sym_stats->num_indirect_writes += mem_ref_stats->num_call_sites
- + mem_ref_stats->num_asm_sites;
- }
-
- /* Addressable symbols are indirectly written at some ASM sites.
- Since only ASM sites that clobber memory actually affect
- addressable symbols, this is an over-estimation. */
- EXECUTE_IF_SET_IN_BITMAP (gimple_addressable_vars (cfun), 0, i, bi)
- {
- tree sym = referenced_var (i);
- sym_stats = get_mem_sym_stats_for (sym);
- sym_stats->num_indirect_writes += mem_ref_stats->num_asm_sites;
- }
-}
-
-
-/* Helper for compute_memory_partitions. Add all memory symbols to
- *MP_INFO_P and compute the initial estimate for the total number of
- virtual operands needed. MEM_REF_STATS points to CFUN's memory
- reference information. On exit, *TAGS_P will contain the list of
- memory tags whose alias set need to be rewritten after
- partitioning. */
-
-static void
-build_mp_info (struct mem_ref_stats_d *mem_ref_stats,
- VEC(mem_sym_stats_t,heap) **mp_info_p,
- VEC(tree,heap) **tags_p)
-{
- tree var;
- referenced_var_iterator rvi;
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- mem_sym_stats_t sym_stats;
- tree old_mpt;
-
- /* We are only interested in memory symbols other than MPTs. */
- if (is_gimple_reg (var) || TREE_CODE (var) == MEMORY_PARTITION_TAG)
- continue;
-
- /* Collect memory tags into the TAGS array so that we can
- rewrite their alias sets after partitioning. */
- if (MTAG_P (var) && MTAG_ALIASES (var))
- VEC_safe_push (tree, heap, *tags_p, var);
-
- /* Since we are going to re-compute partitions, any symbols that
- used to belong to a partition must be detached from it and
- marked for renaming. */
- if ((old_mpt = memory_partition (var)) != NULL)
- {
- mark_sym_for_renaming (old_mpt);
- set_memory_partition (var, NULL_TREE);
- mark_sym_for_renaming (var);
- }
-
- sym_stats = get_mem_sym_stats_for (var);
-
- /* Add VAR's reference info to MP_INFO. Note that the only
- symbols that make sense to partition are those that have
- indirect references. If a symbol S is always directly
- referenced, partitioning it will not reduce the number of
- virtual operators. The only symbols that are profitable to
- partition are those that belong to alias sets and/or are
- call-clobbered. */
- if (sym_stats->num_indirect_reads > 0
- || sym_stats->num_indirect_writes > 0)
- VEC_safe_push (mem_sym_stats_t, heap, *mp_info_p, sym_stats);
-
- /* Update the number of estimated VOPS. Note that direct
- references to memory tags are always counted as indirect
- references to their alias set members, so if a memory tag has
- aliases, do not count its direct references to avoid double
- accounting. */
- if (!MTAG_P (var) || !MTAG_ALIASES (var))
- {
- mem_ref_stats->num_vuses += sym_stats->num_direct_reads;
- mem_ref_stats->num_vdefs += sym_stats->num_direct_writes;
- }
-
- mem_ref_stats->num_vuses += sym_stats->num_indirect_reads;
- mem_ref_stats->num_vdefs += sym_stats->num_indirect_writes;
- }
-}
-
-
-/* Compute memory partitions. A memory partition (MPT) is an
- arbitrary grouping of memory symbols, such that references to one
- member of the group is considered a reference to all the members of
- the group.
-
- As opposed to alias sets in memory tags, the grouping into
- partitions is completely arbitrary and only done to reduce the
- number of virtual operands. The only rule that needs to be
- observed when creating memory partitions is that given two memory
- partitions MPT.i and MPT.j, they must not contain symbols in
- common.
-
- Memory partitions are used when putting the program into Memory-SSA
- form. In particular, in Memory-SSA PHI nodes are not computed for
- individual memory symbols. They are computed for memory
- partitions. This reduces the amount of PHI nodes in the SSA graph
- at the expense of precision (i.e., it makes unrelated stores affect
- each other).
-
- However, it is possible to increase precision by changing this
- partitioning scheme. For instance, if the partitioning scheme is
- such that get_mpt_for is the identity function (that is,
- get_mpt_for (s) = s), this will result in ultimate precision at the
- expense of huge SSA webs.
-
- At the other extreme, a partitioning scheme that groups all the
- symbols in the same set results in minimal SSA webs and almost
- total loss of precision.
-
- There partitioning heuristic uses three parameters to decide the
- order in which symbols are processed. The list of symbols is
- sorted so that symbols that are more likely to be partitioned are
- near the top of the list:
-
- - Execution frequency. If a memory references is in a frequently
- executed code path, grouping it into a partition may block useful
- transformations and cause sub-optimal code generation. So, the
- partition heuristic tries to avoid grouping symbols with high
- execution frequency scores. Execution frequency is taken
- directly from the basic blocks where every reference is made (see
- update_mem_sym_stats_from_stmt), which in turn uses the
- profile guided machinery, so if the program is compiled with PGO
- enabled, more accurate partitioning decisions will be made.
-
- - Number of references. Symbols with few references in the code,
- are partitioned before symbols with many references.
-
- - NO_ALIAS attributes. Symbols with any of the NO_ALIAS*
- attributes are partitioned after symbols marked MAY_ALIAS.
-
- Once the list is sorted, the partitioning proceeds as follows:
-
- 1- For every symbol S in MP_INFO, create a new memory partition MP,
- if necessary. To avoid memory partitions that contain symbols
- from non-conflicting alias sets, memory partitions are
- associated to the memory tag that holds S in its alias set. So,
- when looking for a memory partition for S, the memory partition
- associated with one of the memory tags holding S is chosen. If
- none exists, a new one is created.
-
- 2- Add S to memory partition MP.
-
- 3- Reduce by 1 the number of VOPS for every memory tag holding S.
-
- 4- If the total number of VOPS is less than MAX_ALIASED_VOPS or the
- average number of VOPS per statement is less than
- AVG_ALIASED_VOPS, stop. Otherwise, go to the next symbol in the
- list. */
-
-static void
-compute_memory_partitions (void)
-{
- tree tag;
- unsigned i;
- mem_sym_stats_t mp_p;
- VEC(mem_sym_stats_t,heap) *mp_info;
- bitmap new_aliases;
- VEC(tree,heap) *tags;
- struct mem_ref_stats_d *mem_ref_stats;
- int prev_max_aliased_vops;
-
- mem_ref_stats = gimple_mem_ref_stats (cfun);
- gcc_assert (mem_ref_stats->num_vuses == 0 && mem_ref_stats->num_vdefs == 0);
-
- if (mem_ref_stats->num_mem_stmts == 0)
- return;
-
- timevar_push (TV_MEMORY_PARTITIONING);
-
- mp_info = NULL;
- tags = NULL;
- prev_max_aliased_vops = MAX_ALIASED_VOPS;
-
- /* Since we clearly cannot lower the number of virtual operators
- below the total number of memory statements in the function, we
- may need to adjust MAX_ALIASED_VOPS beforehand. */
- if (MAX_ALIASED_VOPS < mem_ref_stats->num_mem_stmts)
- MAX_ALIASED_VOPS = mem_ref_stats->num_mem_stmts;
-
- /* Update reference stats for all the pointed-to variables and
- memory tags. */
- update_reference_counts (mem_ref_stats);
-
- /* Add all the memory symbols to MP_INFO. */
- build_mp_info (mem_ref_stats, &mp_info, &tags);
-
- /* No partitions required if we are below the threshold. */
- if (!need_to_partition_p (mem_ref_stats))
- {
- if (dump_file)
- fprintf (dump_file, "\nMemory partitioning NOT NEEDED for %s\n",
- get_name (current_function_decl));
- goto done;
- }
-
- /* Sort the MP_INFO array so that symbols that should be partitioned
- first are near the top of the list. */
- sort_mp_info (mp_info);
-
- if (dump_file)
- {
- fprintf (dump_file, "\nMemory partitioning NEEDED for %s\n\n",
- get_name (current_function_decl));
- fprintf (dump_file, "Memory symbol references before partitioning:\n");
- dump_mp_info (dump_file, mp_info);
- }
-
- /* Create partitions for variables in MP_INFO until we have enough
- to lower the total number of VOPS below MAX_ALIASED_VOPS or if
- the average number of VOPS per statement is below
- AVG_ALIASED_VOPS. */
- for (i = 0; VEC_iterate (mem_sym_stats_t, mp_info, i, mp_p); i++)
- {
- tree mpt;
-
- /* If we are below the threshold, stop. */
- if (!need_to_partition_p (mem_ref_stats))
- break;
-
- mpt = find_partition_for (mp_p);
- estimate_vop_reduction (mem_ref_stats, mp_p, mpt);
- }
-
- /* After partitions have been created, rewrite alias sets to use
- them instead of the original symbols. This way, if the alias set
- was computed as { a b c d e f }, and the subset { b e f } was
- grouped into partition MPT.3, then the new alias set for the tag
- will be { a c d MPT.3 }.
-
- Note that this is not strictly necessary. The operand scanner
- will always check if a symbol belongs to a partition when adding
- virtual operands. However, by reducing the size of the alias
- sets to be scanned, the work needed inside the operand scanner is
- significantly reduced. */
- new_aliases = BITMAP_ALLOC (&alias_bitmap_obstack);
-
- for (i = 0; VEC_iterate (tree, tags, i, tag); i++)
- {
- rewrite_alias_set_for (tag, new_aliases);
- bitmap_clear (new_aliases);
- }
-
- BITMAP_FREE (new_aliases);
-
- if (dump_file)
- {
- fprintf (dump_file, "\nMemory symbol references after partitioning:\n");
- dump_mp_info (dump_file, mp_info);
- }
-
-done:
- /* Free allocated memory. */
- VEC_free (mem_sym_stats_t, heap, mp_info);
- VEC_free (tree, heap, tags);
-
- MAX_ALIASED_VOPS = prev_max_aliased_vops;
-
- timevar_pop (TV_MEMORY_PARTITIONING);
-}
-
-/* Compute may-alias information for every variable referenced in function
- FNDECL.
-
- Alias analysis proceeds in 3 main phases:
-
- 1- Points-to and escape analysis.
-
- This phase walks the use-def chains in the SSA web looking for three
- things:
-
- * Assignments of the form P_i = &VAR
- * Assignments of the form P_i = malloc()
- * Pointers and ADDR_EXPR that escape the current function.
-
- The concept of 'escaping' is the same one used in the Java world. When
- a pointer or an ADDR_EXPR escapes, it means that it has been exposed
- outside of the current function. So, assignment to global variables,
- function arguments and returning a pointer are all escape sites, as are
- conversions between pointers and integers.
-
- This is where we are currently limited. Since not everything is renamed
- into SSA, we lose track of escape properties when a pointer is stashed
- inside a field in a structure, for instance. In those cases, we are
- assuming that the pointer does escape.
-
- We use escape analysis to determine whether a variable is
- call-clobbered. Simply put, if an ADDR_EXPR escapes, then the variable
- is call-clobbered. If a pointer P_i escapes, then all the variables
- pointed-to by P_i (and its memory tag) also escape.
-
- 2- Compute flow-sensitive aliases
-
- We have two classes of memory tags. Memory tags associated with the
- pointed-to data type of the pointers in the program. These tags are
- called "symbol memory tag" (SMT). The other class are those associated
- with SSA_NAMEs, called "name memory tag" (NMT). The basic idea is that
- when adding operands for an INDIRECT_REF *P_i, we will first check
- whether P_i has a name tag, if it does we use it, because that will have
- more precise aliasing information. Otherwise, we use the standard symbol
- tag.
-
- In this phase, we go through all the pointers we found in points-to
- analysis and create alias sets for the name memory tags associated with
- each pointer P_i. If P_i escapes, we mark call-clobbered the variables
- it points to and its tag.
-
-
- 3- Compute flow-insensitive aliases
-
- This pass will compare the alias set of every symbol memory tag and
- every addressable variable found in the program. Given a symbol
- memory tag SMT and an addressable variable V. If the alias sets of
- SMT and V conflict (as computed by may_alias_p), then V is marked
- as an alias tag and added to the alias set of SMT.
-
- For instance, consider the following function:
-
- foo (int i)
- {
- int *p, a, b;
-
- if (i > 10)
- p = &a;
- else
- p = &b;
-
- *p = 3;
- a = b + 2;
- return *p;
- }
-
- After aliasing analysis has finished, the symbol memory tag for pointer
- 'p' will have two aliases, namely variables 'a' and 'b'. Every time
- pointer 'p' is dereferenced, we want to mark the operation as a
- potential reference to 'a' and 'b'.
-
- foo (int i)
- {
- int *p, a, b;
-
- if (i_2 > 10)
- p_4 = &a;
- else
- p_6 = &b;
- # p_1 = PHI <p_4(1), p_6(2)>;
-
- # a_7 = VDEF <a_3>;
- # b_8 = VDEF <b_5>;
- *p_1 = 3;
-
- # a_9 = VDEF <a_7>
- # VUSE <b_8>
- a_9 = b_8 + 2;
-
- # VUSE <a_9>;
- # VUSE <b_8>;
- return *p_1;
- }
-
- In certain cases, the list of may aliases for a pointer may grow too
- large. This may cause an explosion in the number of virtual operands
- inserted in the code. Resulting in increased memory consumption and
- compilation time.
-
- When the number of virtual operands needed to represent aliased
- loads and stores grows too large (configurable with option --param
- max-aliased-vops and --param avg-aliased-vops), alias sets are
- grouped to avoid severe compile-time slow downs and memory
- consumption. See compute_memory_partitions. */
-
-unsigned int
-compute_may_aliases (void)
-{
- struct alias_info *ai;
-
- timevar_push (TV_TREE_MAY_ALIAS);
-
- memset (&alias_stats, 0, sizeof (alias_stats));
-
- /* Initialize aliasing information. */
- ai = init_alias_info ();
-
- /* For each pointer P_i, determine the sets of variables that P_i may
- point-to. For every addressable variable V, determine whether the
- address of V escapes the current function, making V call-clobbered
- (i.e., whether &V is stored in a global variable or if its passed as a
- function call argument). */
- compute_points_to_sets ();
-
- /* Update various related attributes like escaped addresses,
- pointer dereferences for loads and stores. This is used
- when creating name tags and alias sets. */
- update_alias_info (ai);
-
- /* Collect all pointers and addressable variables, compute alias sets,
- create memory tags for pointers and promote variables whose address is
- not needed anymore. */
- setup_pointers_and_addressables (ai);
-
- /* Compute type-based flow-insensitive aliasing for all the type
- memory tags. */
- compute_flow_insensitive_aliasing (ai);
-
- /* Compute flow-sensitive, points-to based aliasing for all the name
- memory tags. */
- compute_flow_sensitive_aliasing (ai);
-
- /* Compute call clobbering information. */
- compute_call_clobbered (ai);
-
- /* If the program makes no reference to global variables, but it
- contains a mixture of pure and non-pure functions, then we need
- to create use-def and def-def links between these functions to
- avoid invalid transformations on them. */
- maybe_create_global_var ();
-
- /* Compute memory partitions for every memory variable. */
- compute_memory_partitions ();
-
- /* Remove partitions with no symbols. Partitions may end up with an
- empty MPT_SYMBOLS set if a previous round of alias analysis
- needed to partition more symbols. Since we don't need those
- partitions anymore, remove them to free up the space. */
- {
- tree mpt;
- unsigned i;
- VEC(tree,heap) *mpt_table;
-
- mpt_table = gimple_ssa_operands (cfun)->mpt_table;
- i = 0;
- while (i < VEC_length (tree, mpt_table))
- {
- mpt = VEC_index (tree, mpt_table, i);
- if (MPT_SYMBOLS (mpt) == NULL)
- VEC_unordered_remove (tree, mpt_table, i);
- else
- i++;
- }
- }
-
- /* Populate all virtual operands and newly promoted register operands. */
- {
- gimple_stmt_iterator gsi;
- basic_block bb;
- FOR_EACH_BB (bb)
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- update_stmt_if_modified (gsi_stmt (gsi));
- }
-
- /* Debugging dumps. */
- if (dump_file)
- {
- dump_mem_ref_stats (dump_file);
- dump_alias_info (dump_file);
- dump_points_to_info (dump_file);
-
- if (dump_flags & TDF_STATS)
- dump_alias_stats (dump_file);
-
- if (dump_flags & TDF_DETAILS)
- dump_referenced_vars (dump_file);
- }
-
- /* Deallocate memory used by aliasing data structures. */
- delete_alias_info (ai);
-
- if (need_ssa_update_p ())
- update_ssa (TODO_update_ssa);
-
- timevar_pop (TV_TREE_MAY_ALIAS);
-
- return 0;
-}
-
-/* Data structure used to count the number of dereferences to PTR
- inside an expression. */
-struct count_ptr_d
-{
- tree ptr;
- unsigned num_stores;
- unsigned num_loads;
-};
-
-
-/* Helper for count_uses_and_derefs. Called by walk_tree to look for
- (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA. */
-
-static tree
-count_ptr_derefs (tree *tp, int *walk_subtrees, void *data)
-{
- struct walk_stmt_info *wi_p = (struct walk_stmt_info *) data;
- struct count_ptr_d *count_p = (struct count_ptr_d *) wi_p->info;
-
- /* Do not walk inside ADDR_EXPR nodes. In the expression &ptr->fld,
- pointer 'ptr' is *not* dereferenced, it is simply used to compute
- the address of 'fld' as 'ptr + offsetof(fld)'. */
- if (TREE_CODE (*tp) == ADDR_EXPR)
- {
- *walk_subtrees = 0;
- return NULL_TREE;
- }
-
- if (INDIRECT_REF_P (*tp) && TREE_OPERAND (*tp, 0) == count_p->ptr)
- {
- if (wi_p->is_lhs)
- count_p->num_stores++;
- else
- count_p->num_loads++;
- }
-
- return NULL_TREE;
-}
-
-
-/* Count the number of direct and indirect uses for pointer PTR in
- statement STMT. The number of direct uses is stored in
- *NUM_USES_P. Indirect references are counted separately depending
- on whether they are store or load operations. The counts are
- stored in *NUM_STORES_P and *NUM_LOADS_P. */
-
-void
-count_uses_and_derefs (tree ptr, gimple stmt, unsigned *num_uses_p,
- unsigned *num_loads_p, unsigned *num_stores_p)
-{
- ssa_op_iter i;
- tree use;
-
- *num_uses_p = 0;
- *num_loads_p = 0;
- *num_stores_p = 0;
-
- /* Find out the total number of uses of PTR in STMT. */
- FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE)
- if (use == ptr)
- (*num_uses_p)++;
-
- /* Now count the number of indirect references to PTR. This is
- truly awful, but we don't have much choice. There are no parent
- pointers inside INDIRECT_REFs, so an expression like
- '*x_1 = foo (x_1, *x_1)' needs to be traversed piece by piece to
- find all the indirect and direct uses of x_1 inside. The only
- shortcut we can take is the fact that GIMPLE only allows
- INDIRECT_REFs inside the expressions below. */
- if (is_gimple_assign (stmt)
- || gimple_code (stmt) == GIMPLE_RETURN
- || gimple_code (stmt) == GIMPLE_ASM
- || is_gimple_call (stmt))
- {
- struct walk_stmt_info wi;
- struct count_ptr_d count;
-
- count.ptr = ptr;
- count.num_stores = 0;
- count.num_loads = 0;
-
- memset (&wi, 0, sizeof (wi));
- wi.info = &count;
- walk_gimple_op (stmt, count_ptr_derefs, &wi);
-
- *num_stores_p = count.num_stores;
- *num_loads_p = count.num_loads;
- }
-
- gcc_assert (*num_uses_p >= *num_loads_p + *num_stores_p);
-}
-
-/* Remove memory references stats for function FN. */
-
-void
-delete_mem_ref_stats (struct function *fn)
-{
- if (gimple_mem_ref_stats (fn)->mem_sym_stats)
- {
- free_alloc_pool (mem_sym_stats_pool);
- pointer_map_destroy (gimple_mem_ref_stats (fn)->mem_sym_stats);
- }
- gimple_mem_ref_stats (fn)->mem_sym_stats = NULL;
-}
-
-
-/* Initialize memory reference stats. */
-
-static void
-init_mem_ref_stats (void)
-{
- struct mem_ref_stats_d *mem_ref_stats = gimple_mem_ref_stats (cfun);
-
- mem_sym_stats_pool = create_alloc_pool ("Mem sym stats",
- sizeof (struct mem_sym_stats_d),
- 100);
- memset (mem_ref_stats, 0, sizeof (struct mem_ref_stats_d));
- mem_ref_stats->mem_sym_stats = pointer_map_create ();
-}
-
-
-/* Helper for init_alias_info. Reset existing aliasing information. */
-
-static void
-reset_alias_info (void)
-{
- referenced_var_iterator rvi;
- tree var;
- unsigned i;
- bitmap active_nmts, all_nmts;
-
- /* Clear the set of addressable variables. We do not need to clear
- the TREE_ADDRESSABLE bit on every symbol because we are going to
- re-compute addressability here. */
- bitmap_clear (gimple_addressable_vars (cfun));
-
- active_nmts = BITMAP_ALLOC (&alias_bitmap_obstack);
- all_nmts = BITMAP_ALLOC (&alias_bitmap_obstack);
-
- /* Clear flow-insensitive alias information from each symbol. */
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (is_gimple_reg (var))
- continue;
-
- if (MTAG_P (var))
- MTAG_ALIASES (var) = NULL;
-
- /* Memory partition information will be computed from scratch. */
- if (TREE_CODE (var) == MEMORY_PARTITION_TAG)
- MPT_SYMBOLS (var) = NULL;
-
- /* Collect all the name tags to determine if we have any
- orphaned that need to be removed from the IL. A name tag
- will be orphaned if it is not associated with any active SSA
- name. */
- if (TREE_CODE (var) == NAME_MEMORY_TAG)
- bitmap_set_bit (all_nmts, DECL_UID (var));
-
- /* Since we are about to re-discover call-clobbered
- variables, clear the call-clobbered flag. */
- clear_call_clobbered (var);
- }
-
- /* There should be no call-clobbered variable left. */
- gcc_assert (bitmap_empty_p (gimple_call_clobbered_vars (cfun)));
-
- /* Clear the call-used variables. */
- bitmap_clear (gimple_call_used_vars (cfun));
-
- /* Clear flow-sensitive points-to information from each SSA name. */
- for (i = 1; i < num_ssa_names; i++)
- {
- tree name = ssa_name (i);
-
- if (!name || !POINTER_TYPE_P (TREE_TYPE (name)))
- continue;
-
- if (SSA_NAME_PTR_INFO (name))
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (name);
-
- /* Clear all the flags but keep the name tag to
- avoid creating new temporaries unnecessarily. If
- this pointer is found to point to a subset or
- superset of its former points-to set, then a new
- tag will need to be created in create_name_tags. */
- pi->pt_anything = 0;
- pi->pt_null = 0;
- pi->value_escapes_p = 0;
- pi->memory_tag_needed = 0;
- pi->is_dereferenced = 0;
- if (pi->pt_vars)
- bitmap_clear (pi->pt_vars);
-
- /* Add NAME's name tag to the set of active tags. */
- if (pi->name_mem_tag)
- bitmap_set_bit (active_nmts, DECL_UID (pi->name_mem_tag));
- }
- }
-
- /* Name memory tags that are no longer associated with an SSA name
- are considered stale and should be removed from the IL. All the
- name tags that are in the set ALL_NMTS but not in ACTIVE_NMTS are
- considered stale and marked for renaming. */
- bitmap_and_compl_into (all_nmts, active_nmts);
- mark_set_for_renaming (all_nmts);
-
- BITMAP_FREE (all_nmts);
- BITMAP_FREE (active_nmts);
-}
-
-
-/* Initialize the data structures used for alias analysis. */
-
-static struct alias_info *
-init_alias_info (void)
-{
- struct alias_info *ai;
- referenced_var_iterator rvi;
- tree var;
- static bool alias_bitmap_obstack_initialized;
-
- ai = XCNEW (struct alias_info);
- ai->ssa_names_visited = sbitmap_alloc (num_ssa_names);
- sbitmap_zero (ai->ssa_names_visited);
- ai->processed_ptrs = VEC_alloc (tree, heap, 50);
- ai->dereferenced_ptrs = pointer_set_create ();
-
- /* Clear out all memory reference stats. */
- init_mem_ref_stats ();
-
- /* If aliases have been computed before, clear existing information. */
- if (gimple_aliases_computed_p (cfun))
- reset_alias_info ();
- else
- {
- /* If this is the first time we compute aliasing information,
- every non-register symbol will need to be put into SSA form
- (the initial SSA form only operates on GIMPLE registers). */
- FOR_EACH_REFERENCED_VAR (var, rvi)
- if (!is_gimple_reg (var))
- mark_sym_for_renaming (var);
- }
-
- /* Next time, we will need to reset alias information. */
- cfun->gimple_df->aliases_computed_p = true;
- if (alias_bitmap_obstack_initialized)
- bitmap_obstack_release (&alias_bitmap_obstack);
- bitmap_obstack_initialize (&alias_bitmap_obstack);
- alias_bitmap_obstack_initialized = true;
-
- return ai;
-}
-
-
-/* Deallocate memory used by alias analysis. */
-
-static void
-delete_alias_info (struct alias_info *ai)
-{
- size_t i;
-
- sbitmap_free (ai->ssa_names_visited);
-
- VEC_free (tree, heap, ai->processed_ptrs);
-
- for (i = 0; i < ai->num_addressable_vars; i++)
- free (ai->addressable_vars[i]);
- free (ai->addressable_vars);
-
- for (i = 0; i < ai->num_pointers; i++)
- free (ai->pointers[i]);
- free (ai->pointers);
-
- pointer_set_destroy (ai->dereferenced_ptrs);
- free (ai);
-
- delete_mem_ref_stats (cfun);
- delete_points_to_sets ();
-}
-
-
-/* Used for hashing to identify pointer infos with identical
- pt_vars bitmaps. */
-
-static int
-eq_ptr_info (const void *p1, const void *p2)
-{
- const struct ptr_info_def *n1 = (const struct ptr_info_def *) p1;
- const struct ptr_info_def *n2 = (const struct ptr_info_def *) p2;
- return bitmap_equal_p (n1->pt_vars, n2->pt_vars);
-}
-
-static hashval_t
-ptr_info_hash (const void *p)
-{
- const struct ptr_info_def *n = (const struct ptr_info_def *) p;
- return bitmap_hash (n->pt_vars);
-}
+dump_alias_stats (FILE *s)
+{
+ fprintf (s, "\nAlias oracle query stats:\n");
+ fprintf (s, " refs_may_alias_p: "
+ HOST_WIDE_INT_PRINT_DEC" disambiguations, "
+ HOST_WIDE_INT_PRINT_DEC" queries\n",
+ alias_stats.refs_may_alias_p_no_alias,
+ alias_stats.refs_may_alias_p_no_alias
+ + alias_stats.refs_may_alias_p_may_alias);
+ fprintf (s, " ref_maybe_used_by_call_p: "
+ HOST_WIDE_INT_PRINT_DEC" disambiguations, "
+ HOST_WIDE_INT_PRINT_DEC" queries\n",
+ alias_stats.ref_maybe_used_by_call_p_no_alias,
+ alias_stats.refs_may_alias_p_no_alias
+ + alias_stats.ref_maybe_used_by_call_p_may_alias);
+ fprintf (s, " call_may_clobber_ref_p: "
+ HOST_WIDE_INT_PRINT_DEC" disambiguations, "
+ HOST_WIDE_INT_PRINT_DEC" queries\n",
+ alias_stats.call_may_clobber_ref_p_no_alias,
+ alias_stats.call_may_clobber_ref_p_no_alias
+ + alias_stats.call_may_clobber_ref_p_may_alias);
+}
+
+
+/* Return true, if dereferencing PTR may alias with a global variable. */
-
-/* Create name tags for all the pointers that have been dereferenced.
- We only create a name tag for a pointer P if P is found to point to
- a set of variables (so that we can alias them to *P) or if it is
- the result of a call to malloc (which means that P cannot point to
- anything else nor alias any other variable).
-
- If two pointers P and Q point to the same set of variables, they
- are assigned the same name tag. */
-
-static void
-create_name_tags (void)
-{
- size_t i;
- VEC (tree, heap) *with_ptvars = NULL;
- tree ptr;
- htab_t ptr_hash;
-
- /* Collect the list of pointers with a non-empty points to set. */
- for (i = 1; i < num_ssa_names; i++)
- {
- tree ptr = ssa_name (i);
- struct ptr_info_def *pi;
-
- if (!ptr
- || !POINTER_TYPE_P (TREE_TYPE (ptr))
- || !SSA_NAME_PTR_INFO (ptr))
- continue;
-
- pi = SSA_NAME_PTR_INFO (ptr);
-
- if (pi->pt_anything || !pi->memory_tag_needed)
- {
- /* No name tags for pointers that have not been
- dereferenced or point to an arbitrary location. */
- pi->name_mem_tag = NULL_TREE;
- continue;
- }
-
- /* Set pt_anything on the pointers without pt_vars filled in so
- that they are assigned a symbol tag. */
- if (pi->pt_vars && !bitmap_empty_p (pi->pt_vars))
- VEC_safe_push (tree, heap, with_ptvars, ptr);
- else
- set_pt_anything (ptr);
- }
-
- /* If we didn't find any pointers with pt_vars set, we're done. */
- if (!with_ptvars)
- return;
-
- ptr_hash = htab_create (10, ptr_info_hash, eq_ptr_info, NULL);
-
- /* Now go through the pointers with pt_vars, and find a name tag
- with the same pt_vars as this pointer, or create one if one
- doesn't exist. */
- for (i = 0; VEC_iterate (tree, with_ptvars, i, ptr); i++)
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
- tree old_name_tag = pi->name_mem_tag;
- struct ptr_info_def **slot;
-
- /* If PTR points to a set of variables, check if we don't
- have another pointer Q with the same points-to set before
- creating a tag. If so, use Q's tag instead of creating a
- new one.
-
- This is important for not creating unnecessary symbols
- and also for copy propagation. If we ever need to
- propagate PTR into Q or vice-versa, we would run into
- problems if they both had different name tags because
- they would have different SSA version numbers (which
- would force us to take the name tags in and out of SSA). */
- slot = (struct ptr_info_def **) htab_find_slot (ptr_hash, pi, INSERT);
- if (*slot)
- pi->name_mem_tag = (*slot)->name_mem_tag;
- else
- {
- *slot = pi;
-
- /* If we didn't find a pointer with the same points-to set
- as PTR, create a new name tag if needed. */
- if (pi->name_mem_tag == NULL_TREE)
- pi->name_mem_tag = get_nmt_for (ptr);
- }
-
- /* If the new name tag computed for PTR is different than
- the old name tag that it used to have, then the old tag
- needs to be removed from the IL, so we mark it for
- renaming. */
- if (old_name_tag && old_name_tag != pi->name_mem_tag)
- mark_sym_for_renaming (old_name_tag);
-
- /* Inherit volatility from the pointed-to type. */
- TREE_THIS_VOLATILE (pi->name_mem_tag)
- |= TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (ptr)));
-
- /* Mark the new name tag for renaming. */
- mark_sym_for_renaming (pi->name_mem_tag);
- }
-
- htab_delete (ptr_hash);
-
- VEC_free (tree, heap, with_ptvars);
-}
-
-
-/* Union the alias set SET into the may-aliases for TAG. */
-
-static void
-union_alias_set_into (tree tag, bitmap set)
+bool
+ptr_deref_may_alias_global_p (tree ptr)
{
- bitmap ma = MTAG_ALIASES (tag);
-
- if (bitmap_empty_p (set))
- return;
-
- if (!ma)
- ma = MTAG_ALIASES (tag) = BITMAP_ALLOC (&alias_bitmap_obstack);
- bitmap_ior_into (ma, set);
-}
-
-
-/* For every pointer P_i in AI->PROCESSED_PTRS, create may-alias sets for
- the name memory tag (NMT) associated with P_i. If P_i escapes, then its
- name tag and the variables it points-to are call-clobbered. Finally, if
- P_i escapes and we could not determine where it points to, then all the
- variables in the same alias set as *P_i are marked call-clobbered. This
- is necessary because we must assume that P_i may take the address of any
- variable in the same alias set. */
+ struct ptr_info_def *pi;
-static void
-compute_flow_sensitive_aliasing (struct alias_info *ai)
-{
- size_t i;
- tree ptr;
-
- timevar_push (TV_FLOW_SENSITIVE);
-
- for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
- {
- if (!find_what_p_points_to (ptr))
- set_pt_anything (ptr);
- }
+ /* If we end up with a pointer constant here that may point
+ to global memory. */
+ if (TREE_CODE (ptr) != SSA_NAME)
+ return true;
- create_name_tags ();
+ pi = SSA_NAME_PTR_INFO (ptr);
- for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+ /* If we do not have points-to information for this variable,
+ we have to punt. */
+ if (!pi)
+ return true;
- /* Set up aliasing information for PTR's name memory tag (if it has
- one). Note that only pointers that have been dereferenced will
- have a name memory tag. */
- if (pi->name_mem_tag && pi->pt_vars)
- {
- if (!bitmap_empty_p (pi->pt_vars))
- union_alias_set_into (pi->name_mem_tag, pi->pt_vars);
- }
- }
- timevar_pop (TV_FLOW_SENSITIVE);
+ return pt_solution_includes_global (&pi->pt);
}
-
-/* Return TRUE if at least one symbol in TAG2's alias set is also
- present in TAG1's alias set. */
+/* Return true if dereferencing PTR may alias DECL. */
static bool
-have_common_aliases_p (bitmap tag1aliases, bitmap tag2aliases)
-{
-
- /* This is the old behavior of have_common_aliases_p, which is to
- return false if both sets are empty, or one set is and the other
- isn't. */
- if (tag1aliases == NULL || tag2aliases == NULL)
- return false;
-
- return bitmap_intersect_p (tag1aliases, tag2aliases);
-}
-
-/* Compute type-based alias sets. Traverse all the pointers and
- addressable variables found in setup_pointers_and_addressables.
-
- For every pointer P in AI->POINTERS and addressable variable V in
- AI->ADDRESSABLE_VARS, add V to the may-alias sets of P's symbol
- memory tag (SMT) if their alias sets conflict. V is then marked as
- an aliased symbol so that the operand scanner knows that statements
- containing V have aliased operands. */
-
-static void
-compute_flow_insensitive_aliasing (struct alias_info *ai)
+ptr_deref_may_alias_decl_p (tree ptr, tree decl)
{
- referenced_var_iterator rvi;
- tree var;
- size_t i;
-
- timevar_push (TV_FLOW_INSENSITIVE);
- /* For every pointer P, determine which addressable variables may alias
- with P's symbol memory tag. */
- for (i = 0; i < ai->num_pointers; i++)
- {
- size_t j;
- struct alias_map_d *p_map = ai->pointers[i];
- tree tag = symbol_mem_tag (p_map->var);
- tree var;
-
- for (j = 0; j < ai->num_addressable_vars; j++)
- {
- struct alias_map_d *v_map;
- var_ann_t v_ann;
-
- v_map = ai->addressable_vars[j];
- var = v_map->var;
- v_ann = var_ann (var);
-
- /* We used to skip variables that have never been written to
- if the memory tag has been never written to directly (or
- either of them were call clobbered). This is not enough
- though, as this misses writes through the tags aliases.
- So, for correctness we need to include any aliased
- variable here. */
-
- if (may_alias_p (p_map->var, p_map->set, var, v_map->set, false))
- {
- /* Add VAR to TAG's may-aliases set. */
- add_may_alias (tag, var);
- }
- }
- }
-
- /* Since this analysis is based exclusively on symbols, it fails to
- handle cases where two pointers P and Q have different memory
- tags with conflicting alias set numbers but no aliased symbols in
- common.
-
- For example, suppose that we have two memory tags SMT.1 and SMT.2
- such that
-
- may-aliases (SMT.1) = { a }
- may-aliases (SMT.2) = { b }
-
- and the alias set number of SMT.1 conflicts with that of SMT.2.
- Since they don't have symbols in common, loads and stores from
- SMT.1 and SMT.2 will seem independent of each other, which will
- lead to the optimizers making invalid transformations (see
- testsuite/gcc.c-torture/execute/pr15262-[12].c).
-
- To avoid this problem, we do a final traversal of AI->POINTERS
- looking for pairs of pointers that have no aliased symbols in
- common and yet have conflicting alias set numbers. */
- for (i = 0; i < ai->num_pointers; i++)
- {
- size_t j;
- struct alias_map_d *p_map1 = ai->pointers[i];
- tree tag1 = symbol_mem_tag (p_map1->var);
- bitmap may_aliases1 = MTAG_ALIASES (tag1);
-
- for (j = 0; j < ai->num_pointers; j++)
- {
- struct alias_map_d *p_map2 = ai->pointers[j];
- tree tag2 = symbol_mem_tag (p_map2->var);
- bitmap may_aliases2 = may_aliases (tag2);
-
- /* By convention tags don't alias themselves. */
- if (tag1 == tag2)
- continue;
-
- /* If the pointers may not point to each other, do nothing. */
- if (!may_alias_p (p_map1->var, p_map1->set, tag2, p_map2->set, true))
- continue;
-
- /* The two pointers may alias each other. If they already have
- symbols in common, do nothing. */
- if (have_common_aliases_p (may_aliases1, may_aliases2))
- continue;
-
- add_may_alias (tag1, tag2);
- }
- }
-
- /* We have to add all HEAP variables to all SMTs aliases bitmaps.
- As we don't know which effective type the HEAP will have we cannot
- do better here and we need the conflicts with obfuscated pointers
- (a simple (*(int[n] *)ptr)[i] will do, with ptr from a VLA array
- allocation). */
- for (i = 0; i < ai->num_pointers; i++)
- {
- struct alias_map_d *p_map = ai->pointers[i];
- tree tag = symbol_mem_tag (p_map->var);
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (var_ann (var)->is_heapvar)
- add_may_alias (tag, var);
- }
- }
-
- timevar_pop (TV_FLOW_INSENSITIVE);
-}
-
-
-/* Create a new alias set entry for VAR in AI->ADDRESSABLE_VARS. */
-
-static void
-create_alias_map_for (tree var, struct alias_info *ai)
-{
- struct alias_map_d *alias_map;
- alias_map = XCNEW (struct alias_map_d);
- alias_map->var = var;
- alias_map->set = get_alias_set (var);
- ai->addressable_vars[ai->num_addressable_vars++] = alias_map;
-}
-
-
-/* Update related alias information kept in AI. This is used when
- building name tags, alias sets and deciding grouping heuristics.
- STMT is the statement to process. This function also updates
- ADDRESSABLE_VARS. */
-
-static void
-update_alias_info_1 (gimple stmt, struct alias_info *ai)
-{
- bitmap addr_taken;
- use_operand_p use_p;
- ssa_op_iter iter;
- bool stmt_dereferences_ptr_p;
- enum escape_type stmt_escape_type = is_escape_site (stmt);
- struct mem_ref_stats_d *mem_ref_stats = gimple_mem_ref_stats (cfun);
-
- stmt_dereferences_ptr_p = false;
-
- if (stmt_escape_type == ESCAPE_TO_CALL
- || stmt_escape_type == ESCAPE_TO_PURE_CONST)
- {
- mem_ref_stats->num_call_sites++;
- if (stmt_escape_type == ESCAPE_TO_PURE_CONST)
- mem_ref_stats->num_pure_const_call_sites++;
- }
- else if (stmt_escape_type == ESCAPE_TO_ASM)
- mem_ref_stats->num_asm_sites++;
-
- /* Mark all the variables whose address are taken by the statement. */
- addr_taken = gimple_addresses_taken (stmt);
- if (addr_taken)
- bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken);
-
- /* If we have a call or an assignment, see if the lhs contains
- a local decl that requires not to be a gimple register. */
- if (gimple_code (stmt) == GIMPLE_ASSIGN
- || gimple_code (stmt) == GIMPLE_CALL)
- {
- tree lhs = gimple_get_lhs (stmt);
- /* A plain decl does not need it set. */
- if (lhs && handled_component_p (lhs))
- {
- tree var = get_base_address (lhs);
- if (DECL_P (var)
- /* We are not going to mess with RESULT_DECL anyway. */
- && TREE_CODE (var) != RESULT_DECL
- && is_gimple_reg_type (TREE_TYPE (var)))
- bitmap_set_bit (gimple_addressable_vars (cfun), DECL_UID (var));
- }
- }
-
- /* Process each operand use. For pointers, determine whether they
- are dereferenced by the statement, or whether their value
- escapes, etc. */
- FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
- {
- tree op, var;
- var_ann_t v_ann;
- struct ptr_info_def *pi;
- unsigned num_uses, num_loads, num_stores;
-
- op = USE_FROM_PTR (use_p);
-
- /* If STMT is a PHI node, OP may be an ADDR_EXPR. If so, add it
- to the set of addressable variables. */
- if (TREE_CODE (op) == ADDR_EXPR)
- {
- bitmap addressable_vars = gimple_addressable_vars (cfun);
-
- gcc_assert (gimple_code (stmt) == GIMPLE_PHI);
- gcc_assert (addressable_vars);
-
- /* PHI nodes don't have annotations for pinning the set
- of addresses taken, so we collect them here.
-
- FIXME, should we allow PHI nodes to have annotations
- so that they can be treated like regular statements?
- Currently, they are treated as second-class
- statements. */
- add_to_addressable_set (TREE_OPERAND (op, 0), &addressable_vars);
- continue;
- }
-
- /* Ignore constants (they may occur in PHI node arguments). */
- if (TREE_CODE (op) != SSA_NAME)
- continue;
-
- var = SSA_NAME_VAR (op);
- v_ann = var_ann (var);
-
- /* The base variable of an SSA name must be a GIMPLE register, and thus
- it cannot be aliased. */
- gcc_assert (!may_be_aliased (var));
-
- /* We are only interested in pointers. */
- if (!POINTER_TYPE_P (TREE_TYPE (op)))
- continue;
-
- pi = get_ptr_info (op);
-
- /* Add OP to AI->PROCESSED_PTRS, if it's not there already. */
- if (!TEST_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op)))
- {
- SET_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op));
- VEC_safe_push (tree, heap, ai->processed_ptrs, op);
- }
-
- /* If STMT is a PHI node, then it will not have pointer
- dereferences and it will not be an escape point. */
- if (gimple_code (stmt) == GIMPLE_PHI)
- continue;
-
- /* Determine whether OP is a dereferenced pointer, and if STMT
- is an escape point, whether OP escapes. */
- count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores);
-
- /* For directly dereferenced pointers we can apply
- TBAA-pruning to their points-to set. We may not count the
- implicit dereferences &PTR->FLD here. */
- if (num_loads + num_stores > 0)
- pi->is_dereferenced = 1;
-
- /* Handle a corner case involving address expressions of the
- form '&PTR->FLD'. The problem with these expressions is that
- they do not represent a dereference of PTR. However, if some
- other transformation propagates them into an INDIRECT_REF
- expression, we end up with '*(&PTR->FLD)' which is folded
- into 'PTR->FLD'.
-
- So, if the original code had no other dereferences of PTR,
- the aliaser will not create memory tags for it, and when
- &PTR->FLD gets propagated to INDIRECT_REF expressions, the
- memory operations will receive no VDEF/VUSE operands.
-
- One solution would be to have count_uses_and_derefs consider
- &PTR->FLD a dereference of PTR. But that is wrong, since it
- is not really a dereference but an offset calculation.
-
- What we do here is to recognize these special ADDR_EXPR
- nodes. Since these expressions are never GIMPLE values (they
- are not GIMPLE invariants), they can only appear on the RHS
- of an assignment and their base address is always an
- INDIRECT_REF expression. */
- if (is_gimple_assign (stmt)
- && gimple_assign_rhs_code (stmt) == ADDR_EXPR
- && !is_gimple_val (gimple_assign_rhs1 (stmt)))
- {
- /* If the RHS if of the form &PTR->FLD and PTR == OP, then
- this represents a potential dereference of PTR. */
- tree rhs = gimple_assign_rhs1 (stmt);
- tree base = get_base_address (TREE_OPERAND (rhs, 0));
- if (TREE_CODE (base) == INDIRECT_REF
- && TREE_OPERAND (base, 0) == op)
- num_loads++;
- }
-
- if (num_loads + num_stores > 0)
- {
- /* Mark OP as dereferenced. In a subsequent pass,
- dereferenced pointers that point to a set of
- variables will be assigned a name tag to alias
- all the variables OP points to. */
- pi->memory_tag_needed = 1;
-
- /* ??? For always executed direct dereferences we can
- apply TBAA-pruning to their escape set. */
-
- /* Mark OP as being dereferenced. */
- pointer_set_insert (ai->dereferenced_ptrs, var);
-
- /* Update the frequency estimate for all the dereferences of
- pointer OP. */
- update_mem_sym_stats_from_stmt (op, stmt, num_loads, num_stores);
-
- /* Indicate that STMT contains pointer dereferences. */
- stmt_dereferences_ptr_p = true;
- }
-
- if (stmt_escape_type != NO_ESCAPE && num_loads + num_stores < num_uses)
- {
- /* If STMT is an escape point and STMT contains at
- least one direct use of OP, then the value of OP
- escapes and so the pointed-to variables need to
- be marked call-clobbered. */
- pi->value_escapes_p = 1;
- pi->escape_mask |= stmt_escape_type;
-
- /* If the statement makes a function call, assume
- that pointer OP will be dereferenced in a store
- operation inside the called function. */
- if (is_gimple_call (stmt)
- || stmt_escape_type == ESCAPE_STORED_IN_GLOBAL)
- {
- pointer_set_insert (ai->dereferenced_ptrs, var);
- pi->memory_tag_needed = 1;
- }
- }
- }
-
- if (gimple_code (stmt) == GIMPLE_PHI)
- return;
-
- /* Mark stored variables in STMT as being written to and update the
- memory reference stats for all memory symbols referenced by STMT. */
- if (gimple_references_memory_p (stmt))
- {
- unsigned i;
- bitmap_iterator bi;
-
- mem_ref_stats->num_mem_stmts++;
-
- /* Notice that we only update memory reference stats for symbols
- loaded and stored by the statement if the statement does not
- contain pointer dereferences and it is not a call/asm site.
- This is to avoid double accounting problems when creating
- memory partitions. After computing points-to information,
- pointer dereference statistics are used to update the
- reference stats of the pointed-to variables, so here we
- should only update direct references to symbols.
-
- Indirect references are not updated here for two reasons: (1)
- The first time we compute alias information, the sets
- LOADED/STORED are empty for pointer dereferences, (2) After
- partitioning, LOADED/STORED may have references to
- partitions, not the original pointed-to variables. So, if we
- always counted LOADED/STORED here and during partitioning, we
- would count many symbols more than once.
-
- This does cause some imprecision when a statement has a
- combination of direct symbol references and pointer
- dereferences (e.g., MEMORY_VAR = *PTR) or if a call site has
- memory symbols in its argument list, but these cases do not
- occur so frequently as to constitute a serious problem. */
- if (!stmt_dereferences_ptr_p
- && stmt_escape_type != ESCAPE_TO_CALL
- && stmt_escape_type != ESCAPE_TO_PURE_CONST
- && stmt_escape_type != ESCAPE_TO_ASM)
- {
- if (gimple_stored_syms (stmt))
- EXECUTE_IF_SET_IN_BITMAP (gimple_stored_syms (stmt), 0, i, bi)
- update_mem_sym_stats_from_stmt (referenced_var (i), stmt, 0, 1);
-
- if (gimple_loaded_syms (stmt))
- EXECUTE_IF_SET_IN_BITMAP (gimple_loaded_syms (stmt), 0, i, bi)
- update_mem_sym_stats_from_stmt (referenced_var (i), stmt, 1, 0);
- }
- }
-}
-
-/* Update various related attributes like escaped addresses,
- pointer dereferences for loads and stores. This is used
- when creating name tags and alias sets. */
-
-static void
-update_alias_info (struct alias_info *ai)
-{
- basic_block bb;
-
- FOR_EACH_BB (bb)
- {
- gimple_stmt_iterator gsi;
- gimple phi;
-
- for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- phi = gsi_stmt (gsi);
- if (is_gimple_reg (PHI_RESULT (phi)))
- update_alias_info_1 (phi, ai);
- }
-
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- update_alias_info_1 (gsi_stmt (gsi), ai);
- }
-}
-
-/* Create memory tags for all the dereferenced pointers and build the
- ADDRESSABLE_VARS and POINTERS arrays used for building the may-alias
- sets. Based on the address escape and points-to information collected
- earlier, this pass will also clear the TREE_ADDRESSABLE flag from those
- variables whose address is not needed anymore. */
-
-static void
-setup_pointers_and_addressables (struct alias_info *ai)
-{
- size_t num_addressable_vars, num_pointers;
- referenced_var_iterator rvi;
- tree var;
- VEC (tree, heap) *varvec = NULL;
- safe_referenced_var_iterator srvi;
-
- /* Size up the arrays ADDRESSABLE_VARS and POINTERS. */
- num_addressable_vars = num_pointers = 0;
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (may_be_aliased (var))
- num_addressable_vars++;
-
- if (POINTER_TYPE_P (TREE_TYPE (var)))
- {
- /* Since we don't keep track of volatile variables, assume that
- these pointers are used in indirect store operations. */
- if (TREE_THIS_VOLATILE (var))
- pointer_set_insert (ai->dereferenced_ptrs, var);
-
- num_pointers++;
- }
- }
-
- /* Create ADDRESSABLE_VARS and POINTERS. Note that these arrays are
- always going to be slightly bigger than we actually need them
- because some TREE_ADDRESSABLE variables will be marked
- non-addressable below and only pointers with unique symbol tags are
- going to be added to POINTERS. */
- ai->addressable_vars = XCNEWVEC (struct alias_map_d *, num_addressable_vars);
- ai->pointers = XCNEWVEC (struct alias_map_d *, num_pointers);
- ai->num_addressable_vars = 0;
- ai->num_pointers = 0;
-
- FOR_EACH_REFERENCED_VAR_SAFE (var, varvec, srvi)
- {
- /* Name memory tags already have flow-sensitive aliasing
- information, so they need not be processed by
- compute_flow_insensitive_aliasing. Similarly, symbol memory
- tags are already accounted for when we process their
- associated pointer.
-
- Structure fields, on the other hand, have to have some of this
- information processed for them, but it's pointless to mark them
- non-addressable (since they are fake variables anyway). */
- if (MTAG_P (var))
- continue;
-
- /* Remove the ADDRESSABLE flag from every addressable variable whose
- address is not needed anymore. This is caused by the propagation
- of ADDR_EXPR constants into INDIRECT_REF expressions and the
- removal of dead pointer assignments done by the early scalar
- cleanup passes. */
- if (TREE_ADDRESSABLE (var))
- {
- if (!bitmap_bit_p (gimple_addressable_vars (cfun), DECL_UID (var))
- && TREE_CODE (var) != RESULT_DECL
- && !is_global_var (var))
- {
- bool okay_to_mark = true;
-
- /* Since VAR is now a regular GIMPLE register, we will need
- to rename VAR into SSA afterwards. */
- mark_sym_for_renaming (var);
-
- /* The address of VAR is not needed, remove the
- addressable bit, so that it can be optimized as a
- regular variable. */
- if (okay_to_mark)
- {
- /* The memory partition holding VAR will no longer
- contain VAR, and statements referencing it will need
- to be updated. */
- if (memory_partition (var))
- mark_sym_for_renaming (memory_partition (var));
-
- mark_non_addressable (var);
- }
- }
- }
-
- /* Global variables and addressable locals may be aliased. Create an
- entry in ADDRESSABLE_VARS for VAR. */
- if (may_be_aliased (var))
- {
- create_alias_map_for (var, ai);
- mark_sym_for_renaming (var);
- }
-
- /* Add pointer variables that have been dereferenced to the POINTERS
- array and create a symbol memory tag for them. */
- if (POINTER_TYPE_P (TREE_TYPE (var)))
- {
- if (pointer_set_contains (ai->dereferenced_ptrs, var))
- {
- tree tag, old_tag;
- var_ann_t t_ann;
-
- /* If pointer VAR still doesn't have a memory tag
- associated with it, create it now or re-use an
- existing one. */
- tag = get_smt_for (var, ai);
- t_ann = var_ann (tag);
-
- /* The symbol tag will need to be renamed into SSA
- afterwards. Note that we cannot do this inside
- get_smt_for because aliasing may run multiple times
- and we only create symbol tags the first time. */
- mark_sym_for_renaming (tag);
-
- /* Similarly, if pointer VAR used to have another type
- tag, we will need to process it in the renamer to
- remove the stale virtual operands. */
- old_tag = symbol_mem_tag (var);
- if (old_tag)
- mark_sym_for_renaming (old_tag);
-
- /* Associate the tag with pointer VAR. */
- set_symbol_mem_tag (var, tag);
- }
- else
- {
- /* The pointer has not been dereferenced. If it had a
- symbol memory tag, remove it and mark the old tag for
- renaming to remove it out of the IL. */
- tree tag = symbol_mem_tag (var);
- if (tag)
- {
- mark_sym_for_renaming (tag);
- set_symbol_mem_tag (var, NULL_TREE);
- }
- }
- }
- }
-
- VEC_free (tree, heap, varvec);
-}
-
-
-/* Determine whether to use .GLOBAL_VAR to model call clobbering
- semantics. If the function makes no references to global
- variables and contains at least one call to a non-pure function,
- then we need to mark the side-effects of the call using .GLOBAL_VAR
- to represent all possible global memory referenced by the callee. */
-
-static void
-maybe_create_global_var (void)
-{
- /* No need to create it, if we have one already. */
- if (gimple_global_var (cfun) == NULL_TREE)
- {
- struct mem_ref_stats_d *stats = gimple_mem_ref_stats (cfun);
-
- /* Create .GLOBAL_VAR if there are no call-clobbered
- variables and the program contains a mixture of pure/const
- and regular function calls. This is to avoid the problem
- described in PR 20115:
-
- int X;
- int func_pure (void) { return X; }
- int func_non_pure (int a) { X += a; }
- int foo ()
- {
- int a = func_pure ();
- func_non_pure (a);
- a = func_pure ();
- return a;
- }
-
- Since foo() has no call-clobbered variables, there is
- no relationship between the calls to func_pure and
- func_non_pure. Since func_pure has no side-effects, value
- numbering optimizations elide the second call to func_pure.
- So, if we have some pure/const and some regular calls in the
- program we create .GLOBAL_VAR to avoid missing these
- relations. */
- if (bitmap_empty_p (gimple_call_clobbered_vars (cfun))
- && stats->num_call_sites > 0
- && stats->num_pure_const_call_sites > 0
- && stats->num_call_sites > stats->num_pure_const_call_sites)
- create_global_var ();
- }
-}
-
-
-/* Return TRUE if pointer PTR may point to variable VAR.
-
- MEM_ALIAS_SET is the alias set for the memory location pointed-to by PTR
- This is needed because when checking for type conflicts we are
- interested in the alias set of the memory location pointed-to by
- PTR. The alias set of PTR itself is irrelevant.
-
- VAR_ALIAS_SET is the alias set for VAR. */
-
-bool
-may_alias_p (tree ptr, alias_set_type mem_alias_set,
- tree var, alias_set_type var_alias_set,
- bool alias_set_only)
-{
- tree mem;
-
- alias_stats.alias_queries++;
- alias_stats.simple_queries++;
-
- /* By convention, a variable cannot alias itself. */
- mem = symbol_mem_tag (ptr);
- if (mem == var)
- {
- alias_stats.alias_noalias++;
- alias_stats.simple_resolved++;
- return false;
- }
-
- /* If -fargument-noalias-global is > 2, pointer arguments may
- not point to anything else. */
- if (flag_argument_noalias > 2 && TREE_CODE (ptr) == PARM_DECL)
- {
- alias_stats.alias_noalias++;
- alias_stats.simple_resolved++;
- return false;
- }
-
- /* If -fargument-noalias-global is > 1, pointer arguments may
- not point to global variables. */
- if (flag_argument_noalias > 1 && is_global_var (var)
- && TREE_CODE (ptr) == PARM_DECL)
- {
- alias_stats.alias_noalias++;
- alias_stats.simple_resolved++;
- return false;
- }
-
- /* If the pointed to memory has alias set zero, or the pointer
- is ref-all, or the pointer decl is marked that no TBAA is to
- be applied, the MEM can alias VAR. */
- if (mem_alias_set == 0
- || DECL_POINTER_ALIAS_SET (ptr) == 0
- || TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (ptr))
- || DECL_NO_TBAA_P (ptr))
- {
- alias_stats.alias_mayalias++;
- alias_stats.simple_resolved++;
- return true;
- }
-
- gcc_assert (TREE_CODE (mem) == SYMBOL_MEMORY_TAG);
-
- alias_stats.tbaa_queries++;
-
- /* If the alias sets don't conflict then MEM cannot alias VAR. */
- if (mem_alias_set != var_alias_set
- && !alias_set_subset_of (mem_alias_set, var_alias_set))
- {
- alias_stats.alias_noalias++;
- alias_stats.tbaa_resolved++;
- return false;
- }
-
- /* If VAR is a record or union type, PTR cannot point into VAR
- unless there is some explicit address operation in the
- program that can reference a field of the type pointed-to by
- PTR. This also assumes that the types of both VAR and PTR
- are contained within the compilation unit, and that there is
- no fancy addressing arithmetic associated with any of the
- types involved. */
- if (mem_alias_set != 0 && var_alias_set != 0)
- {
- tree ptr_type = TREE_TYPE (ptr);
- tree var_type = TREE_TYPE (var);
-
- /* The star count is -1 if the type at the end of the
- pointer_to chain is not a record or union type. */
- if (!alias_set_only &&
- 0 /* FIXME tuples ipa_type_escape_star_count_of_interesting_type (var_type) >= 0*/)
- {
- int ptr_star_count = 0;
-
- /* ipa_type_escape_star_count_of_interesting_type is a
- little too restrictive for the pointer type, need to
- allow pointers to primitive types as long as those
- types cannot be pointers to everything. */
- while (POINTER_TYPE_P (ptr_type))
- {
- /* Strip the *s off. */
- ptr_type = TREE_TYPE (ptr_type);
- ptr_star_count++;
- }
-
- /* There does not appear to be a better test to see if
- the pointer type was one of the pointer to everything
- types. */
- if (ptr_star_count > 0)
- {
- alias_stats.structnoaddress_queries++;
- if (ipa_type_escape_field_does_not_clobber_p (var_type,
- TREE_TYPE (ptr)))
- {
- alias_stats.structnoaddress_resolved++;
- alias_stats.alias_noalias++;
- return false;
- }
- }
- else if (ptr_star_count == 0)
- {
- /* If PTR_TYPE was not really a pointer to type, it cannot
- alias. */
- alias_stats.structnoaddress_queries++;
- alias_stats.structnoaddress_resolved++;
- alias_stats.alias_noalias++;
- return false;
- }
- }
- }
+ struct ptr_info_def *pi;
- alias_stats.alias_mayalias++;
- return true;
-}
+ /* ??? During SCCVN/PRE we can end up with *&x during valueizing
+ operands. Likewise we can end up with dereferencing constant
+ pointers. Just bail out in these cases for now. */
+ if (TREE_CODE (ptr) == ADDR_EXPR
+ || TREE_CODE (ptr) == INTEGER_CST)
+ return true;
-/* Return true, if PTR may point to a global variable. */
+ gcc_assert (TREE_CODE (ptr) == SSA_NAME
+ && (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == RESULT_DECL));
-bool
-may_point_to_global_var (tree ptr)
-{
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+ /* Non-aliased variables can not be pointed to. */
+ if (!may_be_aliased (decl))
+ return false;
- /* If we do not have points-to information for this variable,
- we have to punt. */
- if (!pi
- || !pi->name_mem_tag)
+ /* If we do not have useful points-to information for this pointer
+ we cannot disambiguate anything else. */
+ pi = SSA_NAME_PTR_INFO (ptr);
+ if (!pi)
return true;
- /* The name memory tag is marked as global variable if the points-to
- set contains a global variable. */
- return is_global_var (pi->name_mem_tag);
+ return pt_solution_includes (&pi->pt, decl);
}
-/* Add ALIAS to the set of variables that may alias VAR. */
+/* Return true if dereferenced PTR1 and PTR2 may alias. */
-static void
-add_may_alias (tree var, tree alias)
+static bool
+ptr_derefs_may_alias_p (tree ptr1, tree ptr2)
{
- /* Don't allow self-referential aliases. */
- gcc_assert (var != alias);
-
- /* ALIAS must be addressable if it's being added to an alias set. */
-#if 1
- TREE_ADDRESSABLE (alias) = 1;
-#else
- gcc_assert (may_be_aliased (alias));
-#endif
-
- /* VAR must be a symbol or a name tag. */
- gcc_assert (TREE_CODE (var) == SYMBOL_MEMORY_TAG
- || TREE_CODE (var) == NAME_MEMORY_TAG);
-
- if (MTAG_ALIASES (var) == NULL)
- MTAG_ALIASES (var) = BITMAP_ALLOC (&alias_bitmap_obstack);
-
- bitmap_set_bit (MTAG_ALIASES (var), DECL_UID (alias));
-}
+ struct ptr_info_def *pi1, *pi2;
+ /* ??? During SCCVN/PRE we can end up with *&x during valueizing
+ operands. Likewise we can end up with dereferencing constant
+ pointers. Just bail out in these cases for now. */
+ if (TREE_CODE (ptr1) == ADDR_EXPR
+ || TREE_CODE (ptr1) == INTEGER_CST
+ || TREE_CODE (ptr2) == ADDR_EXPR
+ || TREE_CODE (ptr2) == INTEGER_CST)
+ return true;
-/* Mark pointer PTR as pointing to an arbitrary memory location. */
+ gcc_assert (TREE_CODE (ptr1) == SSA_NAME
+ && TREE_CODE (ptr2) == SSA_NAME);
-static void
-set_pt_anything (tree ptr)
-{
- struct ptr_info_def *pi = get_ptr_info (ptr);
+ /* We may end up with two empty points-to solutions for two same pointers.
+ In this case we still want to say both pointers alias, so shortcut
+ that here. */
+ if (ptr1 == ptr2)
+ return true;
- pi->pt_anything = 1;
- /* Anything includes global memory. */
- pi->pt_global_mem = 1;
- pi->pt_vars = NULL;
+ /* If we do not have useful points-to information for either pointer
+ we cannot disambiguate anything else. */
+ pi1 = SSA_NAME_PTR_INFO (ptr1);
+ pi2 = SSA_NAME_PTR_INFO (ptr2);
+ if (!pi1 || !pi2)
+ return true;
- /* The pointer used to have a name tag, but we now found it pointing
- to an arbitrary location. The name tag needs to be renamed and
- disassociated from PTR. */
- if (pi->name_mem_tag)
- {
- mark_sym_for_renaming (pi->name_mem_tag);
- pi->name_mem_tag = NULL_TREE;
- }
+ return pt_solutions_intersect (&pi1->pt, &pi2->pt);
}
-
/* Return true if STMT is an "escape" site from the current function. Escape
sites those statements which might expose the address of a variable
outside the current function. STMT is an escape site iff:
@@ -3197,211 +301,6 @@ is_escape_site (gimple stmt)
return NO_ESCAPE;
}
-/* Create a new memory tag of type TYPE.
- Does NOT push it into the current binding. */
-
-tree
-create_tag_raw (enum tree_code code, tree type, const char *prefix)
-{
- tree tmp_var;
-
- tmp_var = build_decl (code, create_tmp_var_name (prefix), type);
-
- /* Memory tags are always writable and non-static. */
- TREE_READONLY (tmp_var) = 0;
- TREE_STATIC (tmp_var) = 0;
-
- /* It doesn't start out global. */
- MTAG_GLOBAL (tmp_var) = 0;
- TREE_USED (tmp_var) = 1;
-
- return tmp_var;
-}
-
-/* Create a new memory tag of type TYPE. If IS_TYPE_TAG is true, the tag
- is considered to represent all the pointers whose pointed-to types are
- in the same alias set class. Otherwise, the tag represents a single
- SSA_NAME pointer variable. */
-
-static tree
-create_memory_tag (tree type, bool is_type_tag)
-{
- tree tag = create_tag_raw (is_type_tag ? SYMBOL_MEMORY_TAG : NAME_MEMORY_TAG,
- type, (is_type_tag) ? "SMT" : "NMT");
-
- /* By default, memory tags are local variables. Alias analysis will
- determine whether they should be considered globals. */
- DECL_CONTEXT (tag) = current_function_decl;
-
- /* Memory tags are by definition addressable. */
- TREE_ADDRESSABLE (tag) = 1;
-
- set_symbol_mem_tag (tag, NULL_TREE);
-
- /* Add the tag to the symbol table. */
- add_referenced_var (tag);
-
- return tag;
-}
-
-
-/* Create a name memory tag to represent a specific SSA_NAME pointer P_i.
- This is used if P_i has been found to point to a specific set of
- variables or to a non-aliased memory location like the address returned
- by malloc functions. */
-
-static tree
-get_nmt_for (tree ptr)
-{
- struct ptr_info_def *pi = get_ptr_info (ptr);
- tree tag = pi->name_mem_tag;
-
- if (tag == NULL_TREE)
- tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
- return tag;
-}
-
-
-/* Return the symbol memory tag associated to pointer PTR. A memory
- tag is an artificial variable that represents the memory location
- pointed-to by PTR. It is used to model the effects of pointer
- de-references on addressable variables.
-
- AI points to the data gathered during alias analysis. This
- function populates the array AI->POINTERS. */
-
-static tree
-get_smt_for (tree ptr, struct alias_info *ai)
-{
- size_t i;
- tree tag;
- tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
- alias_set_type tag_set;
-
- /* Get the alias set to be used for the pointed-to memory. If that
- differs from what we would get from looking at the type adjust
- the tag_type to void to make sure we get a proper alias set from
- just looking at the SMT we create. */
- tag_set = get_alias_set (tag_type);
- if (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (ptr))
- /* This is overly conservative but we do not want to assign
- restrict alias sets here (which if they are not assigned
- are -2 but still "known"). */
- || DECL_POINTER_ALIAS_SET_KNOWN_P (ptr))
- {
- tag_set = 0;
- tag_type = void_type_node;
- }
-
- /* To avoid creating unnecessary memory tags, only create one memory tag
- per alias set class. Note that it may be tempting to group
- memory tags based on conflicting alias sets instead of
- equivalence. That would be wrong because alias sets are not
- necessarily transitive (as demonstrated by the libstdc++ test
- 23_containers/vector/cons/4.cc). Given three alias sets A, B, C
- such that conflicts (A, B) == true and conflicts (A, C) == true,
- it does not necessarily follow that conflicts (B, C) == true. */
- for (i = 0, tag = NULL_TREE; i < ai->num_pointers; i++)
- {
- struct alias_map_d *curr = ai->pointers[i];
- tree curr_tag = symbol_mem_tag (curr->var);
- if (tag_set == curr->set)
- {
- tag = curr_tag;
- break;
- }
- }
-
- /* If VAR cannot alias with any of the existing memory tags, create a new
- tag for PTR and add it to the POINTERS array. */
- if (tag == NULL_TREE)
- {
- struct alias_map_d *alias_map;
-
- /* If PTR did not have a symbol tag already, create a new SMT.*
- artificial variable representing the memory location
- pointed-to by PTR. */
- tag = symbol_mem_tag (ptr);
- if (tag == NULL_TREE
- || tag_set != get_alias_set (tag))
- tag = create_memory_tag (tag_type, true);
-
- /* Add PTR to the POINTERS array. Note that we are not interested in
- PTR's alias set. Instead, we cache the alias set for the memory that
- PTR points to. */
- alias_map = XCNEW (struct alias_map_d);
- alias_map->var = ptr;
- alias_map->set = tag_set;
- ai->pointers[ai->num_pointers++] = alias_map;
- }
-
- /* If the pointed-to type is volatile, so is the tag. */
- TREE_THIS_VOLATILE (tag) |= TREE_THIS_VOLATILE (tag_type);
-
- /* Make sure that the symbol tag has the same alias set as the
- pointed-to type or at least accesses through the pointer will
- alias that set. The latter can happen after the vectorizer
- created pointers of vector type. */
- gcc_assert (tag_set == get_alias_set (tag)
- || alias_set_subset_of (tag_set, get_alias_set (tag)));
-
- return tag;
-}
-
-
-/* Create GLOBAL_VAR, an artificial global variable to act as a
- representative of all the variables that may be clobbered by function
- calls. */
-
-static void
-create_global_var (void)
-{
- tree global_var = build_decl (VAR_DECL, get_identifier (".GLOBAL_VAR"),
- void_type_node);
- DECL_ARTIFICIAL (global_var) = 1;
- TREE_READONLY (global_var) = 0;
- DECL_EXTERNAL (global_var) = 1;
- TREE_STATIC (global_var) = 1;
- TREE_USED (global_var) = 1;
- DECL_CONTEXT (global_var) = NULL_TREE;
- TREE_THIS_VOLATILE (global_var) = 0;
- TREE_ADDRESSABLE (global_var) = 0;
-
- create_var_ann (global_var);
- mark_call_clobbered (global_var, ESCAPE_UNKNOWN);
- add_referenced_var (global_var);
- mark_sym_for_renaming (global_var);
- cfun->gimple_df->global_var = global_var;
-}
-
-
-/* Dump alias statistics on FILE. */
-
-static void
-dump_alias_stats (FILE *file)
-{
- const char *funcname
- = lang_hooks.decl_printable_name (current_function_decl, 2);
- fprintf (file, "\nAlias statistics for %s\n\n", funcname);
- fprintf (file, "Total alias queries:\t%u\n", alias_stats.alias_queries);
- fprintf (file, "Total alias mayalias results:\t%u\n",
- alias_stats.alias_mayalias);
- fprintf (file, "Total alias noalias results:\t%u\n",
- alias_stats.alias_noalias);
- fprintf (file, "Total simple queries:\t%u\n",
- alias_stats.simple_queries);
- fprintf (file, "Total simple resolved:\t%u\n",
- alias_stats.simple_resolved);
- fprintf (file, "Total TBAA queries:\t%u\n",
- alias_stats.tbaa_queries);
- fprintf (file, "Total TBAA resolved:\t%u\n",
- alias_stats.tbaa_resolved);
- fprintf (file, "Total non-addressable structure type queries:\t%u\n",
- alias_stats.structnoaddress_queries);
- fprintf (file, "Total non-addressable structure type resolved:\t%u\n",
- alias_stats.structnoaddress_resolved);
-}
-
/* Dump alias information on FILE. */
@@ -3414,11 +313,7 @@ dump_alias_info (FILE *file)
referenced_var_iterator rvi;
tree var;
- fprintf (file, "\nAlias information for %s\n\n", funcname);
-
- dump_memory_partitions (file);
-
- fprintf (file, "\nFlow-insensitive alias information for %s\n\n", funcname);
+ fprintf (file, "\n\nAlias information for %s\n\n", funcname);
fprintf (file, "Aliased symbols\n\n");
@@ -3428,46 +323,22 @@ dump_alias_info (FILE *file)
dump_variable (file, var);
}
- fprintf (file, "\nDereferenced pointers\n\n");
+ fprintf (file, "\n\nFlow-insensitive points-to information for %s\n\n", funcname);
- FOR_EACH_REFERENCED_VAR (var, rvi)
- if (symbol_mem_tag (var))
- dump_variable (file, var);
-
- fprintf (file, "\nSymbol memory tags\n\n");
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (TREE_CODE (var) == SYMBOL_MEMORY_TAG)
- dump_variable (file, var);
- }
-
- fprintf (file, "\n\nFlow-sensitive alias information for %s\n\n", funcname);
-
- fprintf (file, "SSA_NAME pointers\n\n");
for (i = 1; i < num_ssa_names; i++)
{
tree ptr = ssa_name (i);
struct ptr_info_def *pi;
- if (ptr == NULL_TREE)
+ if (ptr == NULL_TREE
+ || SSA_NAME_IN_FREE_LIST (ptr))
continue;
pi = SSA_NAME_PTR_INFO (ptr);
- if (!SSA_NAME_IN_FREE_LIST (ptr)
- && pi
- && pi->name_mem_tag)
+ if (pi)
dump_points_to_info_for (file, ptr);
}
- fprintf (file, "\nName memory tags\n\n");
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (TREE_CODE (var) == NAME_MEMORY_TAG)
- dump_variable (file, var);
- }
-
fprintf (file, "\n");
}
@@ -3495,6 +366,7 @@ get_ptr_info (tree t)
if (pi == NULL)
{
pi = GGC_CNEW (struct ptr_info_def);
+ pt_solution_reset (&pi->pt);
SSA_NAME_PTR_INFO (t) = pi;
}
@@ -3512,30 +384,24 @@ dump_points_to_info_for (FILE *file, tree ptr)
if (pi)
{
- if (pi->name_mem_tag)
- {
- fprintf (file, ", name memory tag: ");
- print_generic_expr (file, pi->name_mem_tag, dump_flags);
- }
-
- if (pi->is_dereferenced)
- fprintf (file, ", is dereferenced");
- else if (pi->memory_tag_needed)
- fprintf (file, ", is dereferenced in call");
+ if (pi->pt.anything)
+ fprintf (file, ", points-to anything");
- if (pi->value_escapes_p)
- fprintf (file, ", its value escapes");
+ if (pi->pt.nonlocal)
+ fprintf (file, ", points-to non-local");
- if (pi->pt_anything)
- fprintf (file, ", points-to anything");
+ if (pi->pt.escaped)
+ fprintf (file, ", points-to escaped");
- if (pi->pt_null)
+ if (pi->pt.null)
fprintf (file, ", points-to NULL");
- if (pi->pt_vars)
+ if (pi->pt.vars)
{
fprintf (file, ", points-to vars: ");
- dump_decl_set (file, pi->pt_vars);
+ dump_decl_set (file, pi->pt.vars);
+ if (pi->pt.vars_contains_global)
+ fprintf (file, " (includes global vars)");
}
}
@@ -3551,249 +417,717 @@ debug_points_to_info_for (tree var)
dump_points_to_info_for (stderr, var);
}
+/* Return 1 if TYPE1 and TYPE2 are to be considered equivalent for the
+ purpose of TBAA. Return 0 if they are distinct and -1 if we cannot
+ decide. */
-/* Dump points-to information into FILE. NOTE: This function is slow, as
- it needs to traverse the whole CFG looking for pointer SSA_NAMEs. */
+static inline int
+same_type_for_tbaa (tree type1, tree type2)
+{
+ type1 = TYPE_MAIN_VARIANT (type1);
+ type2 = TYPE_MAIN_VARIANT (type2);
-void
-dump_points_to_info (FILE *file ATTRIBUTE_UNUSED)
+ /* If we would have to do structural comparison bail out. */
+ if (TYPE_STRUCTURAL_EQUALITY_P (type1)
+ || TYPE_STRUCTURAL_EQUALITY_P (type2))
+ return -1;
+
+ /* Compare the canonical types. */
+ if (TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2))
+ return 1;
+
+ /* ??? Array types are not properly unified in all cases as we have
+ spurious changes in the index types for example. Removing this
+ causes all sorts of problems with the Fortran frontend. */
+ if (TREE_CODE (type1) == ARRAY_TYPE
+ && TREE_CODE (type2) == ARRAY_TYPE)
+ return -1;
+
+ /* The types are known to be not equal. */
+ return 0;
+}
+
+/* Determine if the two component references REF1 and REF2 which are
+ based on access types TYPE1 and TYPE2 and of which at least one is based
+ on an indirect reference may alias. */
+
+static bool
+nonaliasing_component_refs_p (tree ref1, tree type1,
+ HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
+ tree ref2, tree type2,
+ HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2)
+{
+ /* If one reference is a component references through pointers try to find a
+ common base and apply offset based disambiguation. This handles
+ for example
+ struct A { int i; int j; } *q;
+ struct B { struct A a; int k; } *p;
+ disambiguating q->i and p->a.j. */
+ tree *refp;
+ int same_p;
+
+ /* Now search for the type1 in the access path of ref2. This
+ would be a common base for doing offset based disambiguation on. */
+ /* Skip the outermost ref - we would have caught that earlier. */
+ refp = &TREE_OPERAND (ref2, 0);
+ while (handled_component_p (*refp)
+ && same_type_for_tbaa (TREE_TYPE (*refp), type1) == 0)
+ refp = &TREE_OPERAND (*refp, 0);
+ same_p = same_type_for_tbaa (TREE_TYPE (*refp), type1);
+ /* If we couldn't compare types we have to bail out. */
+ if (same_p == -1)
+ return true;
+ else if (same_p == 1)
+ {
+ HOST_WIDE_INT offadj, sztmp, msztmp;
+ get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp);
+ offset2 -= offadj;
+ return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+ }
+ /* If we didn't find a common base, try the other way around. */
+ refp = &TREE_OPERAND (ref1, 0);
+ while (handled_component_p (*refp)
+ && same_type_for_tbaa (TREE_TYPE (*refp), type2) == 0)
+ refp = &TREE_OPERAND (*refp, 0);
+ same_p = same_type_for_tbaa (TREE_TYPE (*refp), type2);
+ /* If we couldn't compare types we have to bail out. */
+ if (same_p == -1)
+ return true;
+ else if (same_p == 1)
+ {
+ HOST_WIDE_INT offadj, sztmp, msztmp;
+ get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp);
+ offset1 -= offadj;
+ return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+ }
+ /* If we have two type access paths B1.path1 and B2.path2 they may
+ only alias if either B1 is in B2.path2 or B2 is in B1.path1. */
+ return false;
+}
+
+/* Return true if two memory references based on the variables BASE1
+ and BASE2 constrained to [OFFSET1, OFFSET1 + MAX_SIZE1[ and
+ [OFFSET2, OFFSET2 + MAX_SIZE2[ may alias. */
+
+static bool
+decl_refs_may_alias_p (tree base1,
+ HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
+ tree base2,
+ HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2)
{
- basic_block bb;
- gimple_stmt_iterator si;
- ssa_op_iter iter;
- const char *fname =
- lang_hooks.decl_printable_name (current_function_decl, 2);
- referenced_var_iterator rvi;
- tree var;
+ gcc_assert (SSA_VAR_P (base1) && SSA_VAR_P (base2));
+
+ /* If both references are based on different variables, they cannot alias. */
+ if (!operand_equal_p (base1, base2, 0))
+ return false;
+
+ /* If both references are based on the same variable, they cannot alias if
+ the accesses do not overlap. */
+ return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+}
- fprintf (file, "\n\nPointed-to sets for pointers in %s\n\n", fname);
+/* Return true if an indirect reference based on *PTR1 constrained
+ to [OFFSET1, OFFSET1 + MAX_SIZE1[ may alias a variable based on BASE2
+ constrained to [OFFSET2, OFFSET2 + MAX_SIZE2[. *PTR1 and BASE2 have
+ the alias sets BASE1_ALIAS_SET and BASE2_ALIAS_SET which can be -1
+ in which case they are computed on-demand. REF1 and REF2
+ if non-NULL are the complete memory reference trees. */
- /* First dump points-to information for the default definitions of
- pointer variables. This is necessary because default definitions are
- not part of the code. */
- FOR_EACH_REFERENCED_VAR (var, rvi)
+static bool
+indirect_ref_may_alias_decl_p (tree ref1, tree ptr1,
+ HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
+ alias_set_type base1_alias_set,
+ tree ref2, tree base2,
+ HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
+ alias_set_type base2_alias_set)
+{
+ /* If only one reference is based on a variable, they cannot alias if
+ the pointer access is beyond the extent of the variable access.
+ (the pointer base cannot validly point to an offset less than zero
+ of the variable).
+ They also cannot alias if the pointer may not point to the decl. */
+ if (max_size2 != -1
+ && !ranges_overlap_p (offset1, max_size1, 0, offset2 + max_size2))
+ return false;
+ if (!ptr_deref_may_alias_decl_p (ptr1, base2))
+ return false;
+
+ /* Disambiguations that rely on strict aliasing rules follow. */
+ if (!flag_strict_aliasing)
+ return true;
+
+ /* If the alias set for a pointer access is zero all bets are off. */
+ if (base1_alias_set == -1)
+ base1_alias_set = get_deref_alias_set (ptr1);
+ if (base1_alias_set == 0)
+ return true;
+ if (base2_alias_set == -1)
+ base2_alias_set = get_alias_set (base2);
+
+ /* If both references are through the same type, they do not alias
+ if the accesses do not overlap. This does extra disambiguation
+ for mixed/pointer accesses but requires strict aliasing. */
+ if (same_type_for_tbaa (TREE_TYPE (TREE_TYPE (ptr1)),
+ TREE_TYPE (base2)) == 1)
+ return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+
+ /* The only way to access a variable is through a pointer dereference
+ of the same alias set or a subset of it. */
+ if (base1_alias_set != base2_alias_set
+ && !alias_set_subset_of (base1_alias_set, base2_alias_set))
+ return false;
+
+ /* Do access-path based disambiguation. */
+ if (ref1 && ref2
+ && handled_component_p (ref1)
+ && handled_component_p (ref2))
+ return nonaliasing_component_refs_p (ref1, TREE_TYPE (TREE_TYPE (ptr1)),
+ offset1, max_size1,
+ ref2, TREE_TYPE (base2),
+ offset2, max_size2);
+
+ return true;
+}
+
+/* Return true if two indirect references based on *PTR1
+ and *PTR2 constrained to [OFFSET1, OFFSET1 + MAX_SIZE1[ and
+ [OFFSET2, OFFSET2 + MAX_SIZE2[ may alias. *PTR1 and *PTR2 have
+ the alias sets BASE1_ALIAS_SET and BASE2_ALIAS_SET which can be -1
+ in which case they are computed on-demand. REF1 and REF2
+ if non-NULL are the complete memory reference trees. */
+
+static bool
+indirect_refs_may_alias_p (tree ref1, tree ptr1,
+ HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
+ alias_set_type base1_alias_set,
+ tree ref2, tree ptr2,
+ HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
+ alias_set_type base2_alias_set)
+{
+ /* If both bases are based on pointers they cannot alias if they may not
+ point to the same memory object or if they point to the same object
+ and the accesses do not overlap. */
+ if (operand_equal_p (ptr1, ptr2, 0))
+ return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+ if (!ptr_derefs_may_alias_p (ptr1, ptr2))
+ return false;
+
+ /* Disambiguations that rely on strict aliasing rules follow. */
+ if (!flag_strict_aliasing)
+ return true;
+
+ /* If the alias set for a pointer access is zero all bets are off. */
+ if (base1_alias_set == -1)
+ base1_alias_set = get_deref_alias_set (ptr1);
+ if (base1_alias_set == 0)
+ return true;
+ if (base2_alias_set == -1)
+ base2_alias_set = get_deref_alias_set (ptr2);
+ if (base2_alias_set == 0)
+ return true;
+
+ /* If both references are through the same type, they do not alias
+ if the accesses do not overlap. This does extra disambiguation
+ for mixed/pointer accesses but requires strict aliasing. */
+ if (same_type_for_tbaa (TREE_TYPE (TREE_TYPE (ptr1)),
+ TREE_TYPE (TREE_TYPE (ptr2))) == 1)
+ return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+
+ /* Do type-based disambiguation. */
+ if (base1_alias_set != base2_alias_set
+ && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
+ return false;
+
+ /* Do access-path based disambiguation. */
+ if (ref1 && ref2
+ && handled_component_p (ref1)
+ && handled_component_p (ref2))
+ return nonaliasing_component_refs_p (ref1, TREE_TYPE (TREE_TYPE (ptr1)),
+ offset1, max_size1,
+ ref2, TREE_TYPE (TREE_TYPE (ptr2)),
+ offset2, max_size2);
+
+ return true;
+}
+
+/* Return true, if the two memory references REF1 and REF2 may alias. */
+
+static bool
+refs_may_alias_p_1 (tree ref1, tree ref2)
+{
+ tree base1, base2;
+ HOST_WIDE_INT offset1 = 0, offset2 = 0;
+ HOST_WIDE_INT size1 = -1, size2 = -1;
+ HOST_WIDE_INT max_size1 = -1, max_size2 = -1;
+ bool var1_p, var2_p, ind1_p, ind2_p;
+
+ gcc_assert ((SSA_VAR_P (ref1)
+ || handled_component_p (ref1)
+ || INDIRECT_REF_P (ref1)
+ || TREE_CODE (ref1) == TARGET_MEM_REF)
+ && (SSA_VAR_P (ref2)
+ || handled_component_p (ref2)
+ || INDIRECT_REF_P (ref2)
+ || TREE_CODE (ref2) == TARGET_MEM_REF));
+
+ /* Defer to TBAA if possible. */
+ if (flag_strict_aliasing
+ && !alias_sets_conflict_p (get_alias_set (ref1), get_alias_set (ref2)))
+ return false;
+
+ /* If one reference is a TARGET_MEM_REF weird things are allowed. */
+ if (TREE_CODE (ref1) == TARGET_MEM_REF
+ || TREE_CODE (ref2) == TARGET_MEM_REF)
+ return true;
+
+ /* Decompose the references into their base objects and the access. */
+ base1 = get_ref_base_and_extent (ref1, &offset1, &size1, &max_size1);
+ base2 = get_ref_base_and_extent (ref2, &offset2, &size2, &max_size2);
+
+ /* We can end up with registers or constants as bases for example from
+ *D.1663_44 = VIEW_CONVERT_EXPR<struct DB_LSN>(__tmp$B0F64_59);
+ which is seen as a struct copy. */
+ if (TREE_CODE (base1) == SSA_NAME
+ || CONSTANT_CLASS_P (base1)
+ || TREE_CODE (base2) == SSA_NAME
+ || CONSTANT_CLASS_P (base2))
+ return false;
+
+ var1_p = SSA_VAR_P (base1);
+ var2_p = SSA_VAR_P (base2);
+ ind1_p = INDIRECT_REF_P (base1);
+ ind2_p = INDIRECT_REF_P (base2);
+ if (var1_p && var2_p)
+ return decl_refs_may_alias_p (base1, offset1, max_size1,
+ base2, offset2, max_size2);
+ else if (var1_p && ind2_p)
+ return indirect_ref_may_alias_decl_p (ref2, TREE_OPERAND (base2, 0),
+ offset2, max_size2, -1,
+ ref1, base1,
+ offset1, max_size1, -1);
+ else if (ind1_p && var2_p)
+ return indirect_ref_may_alias_decl_p (ref1, TREE_OPERAND (base1, 0),
+ offset1, max_size1, -1,
+ ref2, base2,
+ offset2, max_size2, -1);
+ else if (ind1_p && ind2_p)
+ return indirect_refs_may_alias_p (ref1, TREE_OPERAND (base1, 0),
+ offset1, max_size1, -1,
+ ref2, TREE_OPERAND (base2, 0),
+ offset2, max_size2, -1);
+
+ gcc_unreachable ();
+}
+
+bool
+refs_may_alias_p (tree ref1, tree ref2)
+{
+ bool res = refs_may_alias_p_1 (ref1, ref2);
+ if (res)
+ ++alias_stats.refs_may_alias_p_may_alias;
+ else
+ ++alias_stats.refs_may_alias_p_no_alias;
+ return res;
+}
+
+
+/* If the call CALL may use the memory reference REF return true,
+ otherwise return false. */
+
+static bool
+ref_maybe_used_by_call_p_1 (gimple call, tree ref)
+{
+ tree base;
+ unsigned i;
+ int flags = gimple_call_flags (call);
+
+ /* Const functions without a static chain do not implicitly use memory. */
+ if (!gimple_call_chain (call)
+ && (flags & (ECF_CONST|ECF_NOVOPS)))
+ goto process_args;
+
+ /* If the reference is not based on a decl give up.
+ ??? Handle indirect references by intersecting the call-used
+ solution with that of the pointer. */
+ base = get_base_address (ref);
+ if (!base
+ || !DECL_P (base))
+ return true;
+
+ /* Check if base is a global static variable that is not read
+ by the function. */
+ if (TREE_CODE (base) == VAR_DECL
+ && TREE_STATIC (base)
+ && !TREE_PUBLIC (base))
{
- if (POINTER_TYPE_P (TREE_TYPE (var)))
- {
- tree def = gimple_default_def (cfun, var);
- if (def)
- dump_points_to_info_for (file, def);
- }
+ tree callee = gimple_call_fndecl (call);
+ bitmap not_read;
+
+ if (callee != NULL_TREE
+ && (not_read
+ = ipa_reference_get_not_read_global (cgraph_node (callee)))
+ && bitmap_bit_p (not_read, DECL_UID (base)))
+ goto process_args;
}
- /* Dump points-to information for every pointer defined in the program. */
- FOR_EACH_BB (bb)
+ /* If the base variable is call-used or call-clobbered then
+ it may be used. */
+ if (flags & (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS))
{
- for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
- {
- gimple phi = gsi_stmt (si);
- tree ptr = PHI_RESULT (phi);
- if (POINTER_TYPE_P (TREE_TYPE (ptr)))
- dump_points_to_info_for (file, ptr);
- }
+ if (is_call_used (base))
+ return true;
+ }
+ else
+ {
+ if (is_call_clobbered (base))
+ return true;
+ }
+
+ /* Inspect call arguments for passed-by-value aliases. */
+process_args:
+ for (i = 0; i < gimple_call_num_args (call); ++i)
+ {
+ tree op = gimple_call_arg (call, i);
- for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
- {
- gimple stmt = gsi_stmt (si);
- tree def;
- FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
- if (TREE_CODE (def) == SSA_NAME
- && POINTER_TYPE_P (TREE_TYPE (def)))
- dump_points_to_info_for (file, def);
- }
+ if (TREE_CODE (op) == EXC_PTR_EXPR
+ || TREE_CODE (op) == FILTER_EXPR)
+ continue;
+
+ if (TREE_CODE (op) == WITH_SIZE_EXPR)
+ op = TREE_OPERAND (op, 0);
+
+ if (TREE_CODE (op) != SSA_NAME
+ && !is_gimple_min_invariant (op)
+ && refs_may_alias_p (op, ref))
+ return true;
}
- fprintf (file, "\n");
+ return false;
}
+static bool
+ref_maybe_used_by_call_p (gimple call, tree ref)
+{
+ bool res = ref_maybe_used_by_call_p_1 (call, ref);
+ if (res)
+ ++alias_stats.ref_maybe_used_by_call_p_may_alias;
+ else
+ ++alias_stats.ref_maybe_used_by_call_p_no_alias;
+ return res;
+}
-/* Dump points-to info pointed to by PTO into STDERR. */
-void
-debug_points_to_info (void)
+/* If the statement STMT may use the memory reference REF return
+ true, otherwise return false. */
+
+bool
+ref_maybe_used_by_stmt_p (gimple stmt, tree ref)
{
- dump_points_to_info (stderr);
+ if (is_gimple_assign (stmt))
+ {
+ tree rhs;
+
+ /* All memory assign statements are single. */
+ if (!gimple_assign_single_p (stmt))
+ return false;
+
+ rhs = gimple_assign_rhs1 (stmt);
+ if (is_gimple_reg (rhs)
+ || is_gimple_min_invariant (rhs)
+ || gimple_assign_rhs_code (stmt) == CONSTRUCTOR)
+ return false;
+
+ return refs_may_alias_p (rhs, ref);
+ }
+ else if (is_gimple_call (stmt))
+ return ref_maybe_used_by_call_p (stmt, ref);
+
+ return true;
}
-/* Dump to FILE the list of variables that may be aliasing VAR. */
+/* If the call in statement CALL may clobber the memory reference REF
+ return true, otherwise return false. */
-void
-dump_may_aliases_for (FILE *file, tree var)
+static bool
+call_may_clobber_ref_p_1 (gimple call, tree ref)
{
- bitmap aliases;
-
- aliases = MTAG_ALIASES (var);
- if (aliases)
+ tree base;
+
+ /* If the call is pure or const it cannot clobber anything. */
+ if (gimple_call_flags (call)
+ & (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS))
+ return false;
+
+ base = get_base_address (ref);
+ if (!base)
+ return true;
+
+ if (TREE_CODE (base) == SSA_NAME
+ || CONSTANT_CLASS_P (base))
+ return false;
+
+ /* Check if base is a global static variable that is not written
+ by the function. */
+ if (TREE_CODE (base) == VAR_DECL
+ && TREE_STATIC (base)
+ && !TREE_PUBLIC (base))
{
- bitmap_iterator bi;
- unsigned int i;
- tree al;
+ tree callee = gimple_call_fndecl (call);
+ bitmap not_written;
- fprintf (file, "{ ");
- EXECUTE_IF_SET_IN_BITMAP (aliases, 0, i, bi)
- {
- al = referenced_var (i);
- print_generic_expr (file, al, dump_flags);
- fprintf (file, " ");
- }
- fprintf (file, "}");
+ if (callee != NULL_TREE
+ && (not_written
+ = ipa_reference_get_not_written_global (cgraph_node (callee)))
+ && bitmap_bit_p (not_written, DECL_UID (base)))
+ return false;
}
-}
+ if (DECL_P (base))
+ return is_call_clobbered (base);
-/* Dump to stderr the list of variables that may be aliasing VAR. */
+ return true;
+}
-void
-debug_may_aliases_for (tree var)
+static bool
+call_may_clobber_ref_p (gimple call, tree ref)
{
- dump_may_aliases_for (stderr, var);
+ bool res = call_may_clobber_ref_p_1 (call, ref);
+ if (res)
+ ++alias_stats.call_may_clobber_ref_p_may_alias;
+ else
+ ++alias_stats.call_may_clobber_ref_p_no_alias;
+ return res;
}
-/* Return true if VAR may be aliased. */
+
+/* If the statement STMT may clobber the memory reference REF return true,
+ otherwise return false. */
bool
-may_be_aliased (tree var)
+stmt_may_clobber_ref_p (gimple stmt, tree ref)
{
- /* Obviously. */
- if (TREE_ADDRESSABLE (var))
- return true;
+ if (is_gimple_call (stmt))
+ {
+ tree lhs = gimple_call_lhs (stmt);
+ if (lhs
+ && !is_gimple_reg (lhs)
+ && refs_may_alias_p (ref, lhs))
+ return true;
- /* Globally visible variables can have their addresses taken by other
- translation units. */
- if (MTAG_P (var)
- && MTAG_GLOBAL (var))
- return true;
- else if (!MTAG_P (var)
- && (DECL_EXTERNAL (var) || TREE_PUBLIC (var)))
+ return call_may_clobber_ref_p (stmt, ref);
+ }
+ else if (is_gimple_assign (stmt))
+ return refs_may_alias_p (ref, gimple_assign_lhs (stmt));
+ else if (gimple_code (stmt) == GIMPLE_ASM)
return true;
- /* Automatic variables can't have their addresses escape any other
- way. This must be after the check for global variables, as
- extern declarations do not have TREE_STATIC set. */
- if (!TREE_STATIC (var))
- return false;
-
return false;
}
-/* The following is based on code in add_stmt_operand to ensure that the
- same defs/uses/vdefs/vuses will be found after replacing a reference
- to var (or ARRAY_REF to var) with an INDIRECT_REF to ptr whose value
- is the address of var. Return a memtag for the ptr, after adding the
- proper may_aliases to it (which are the aliases of var, if it has any,
- or var itself). */
+static tree get_continuation_for_phi (gimple, tree, bitmap *);
-static tree
-add_may_alias_for_new_tag (tree tag, tree var)
+/* Walk the virtual use-def chain of VUSE until hitting the virtual operand
+ TARGET or a statement clobbering the memory reference REF in which
+ case false is returned. The walk starts with VUSE, one argument of PHI. */
+
+static bool
+maybe_skip_until (gimple phi, tree target, tree ref, tree vuse, bitmap *visited)
{
- bitmap aliases = NULL;
-
- if (MTAG_P (var))
- aliases = may_aliases (var);
+ if (!*visited)
+ *visited = BITMAP_ALLOC (NULL);
+
+ bitmap_set_bit (*visited, SSA_NAME_VERSION (PHI_RESULT (phi)));
- /* Case 1: |aliases| == 1 */
- if (aliases
- && bitmap_single_bit_set_p (aliases))
+ /* Walk until we hit the target. */
+ while (vuse != target)
{
- tree ali = referenced_var (bitmap_first_set_bit (aliases));
- if (TREE_CODE (ali) == SYMBOL_MEMORY_TAG)
- return ali;
+ gimple def_stmt = SSA_NAME_DEF_STMT (vuse);
+ /* Recurse for PHI nodes. */
+ if (gimple_code (def_stmt) == GIMPLE_PHI)
+ {
+ /* An already visited PHI node ends the walk successfully. */
+ if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (def_stmt))))
+ return true;
+ vuse = get_continuation_for_phi (def_stmt, ref, visited);
+ if (!vuse)
+ return false;
+ continue;
+ }
+ /* A clobbering statement or the end of the IL ends it failing. */
+ else if (gimple_nop_p (def_stmt)
+ || stmt_may_clobber_ref_p (def_stmt, ref))
+ return false;
+ vuse = gimple_vuse (def_stmt);
}
+ return true;
+}
- /* Case 2: |aliases| == 0 */
- if (aliases == NULL)
- add_may_alias (tag, var);
- else
+/* Starting from a PHI node for the virtual operand of the memory reference
+ REF find a continuation virtual operand that allows to continue walking
+ statements dominating PHI skipping only statements that cannot possibly
+ clobber REF. Returns NULL_TREE if no suitable virtual operand can
+ be found. */
+
+static tree
+get_continuation_for_phi (gimple phi, tree ref, bitmap *visited)
+{
+ unsigned nargs = gimple_phi_num_args (phi);
+
+ /* Through a single-argument PHI we can simply look through. */
+ if (nargs == 1)
+ return PHI_ARG_DEF (phi, 0);
+
+ /* For two arguments try to skip non-aliasing code until we hit
+ the phi argument definition that dominates the other one. */
+ if (nargs == 2)
{
- /* Case 3: |aliases| > 1 */
- union_alias_set_into (tag, aliases);
+ tree arg0 = PHI_ARG_DEF (phi, 0);
+ tree arg1 = PHI_ARG_DEF (phi, 1);
+ gimple def0 = SSA_NAME_DEF_STMT (arg0);
+ gimple def1 = SSA_NAME_DEF_STMT (arg1);
+
+ if (arg0 == arg1)
+ return arg0;
+ else if (gimple_nop_p (def0)
+ || (!gimple_nop_p (def1)
+ && dominated_by_p (CDI_DOMINATORS,
+ gimple_bb (def1), gimple_bb (def0))))
+ {
+ if (maybe_skip_until (phi, arg0, ref, arg1, visited))
+ return arg0;
+ }
+ else if (gimple_nop_p (def1)
+ || dominated_by_p (CDI_DOMINATORS,
+ gimple_bb (def0), gimple_bb (def1)))
+ {
+ if (maybe_skip_until (phi, arg1, ref, arg0, visited))
+ return arg1;
+ }
}
- return tag;
+
+ return NULL_TREE;
}
-/* Create a new symbol tag for PTR. Construct the may-alias list of
- this type tag so that it has the aliasing of VAR according to the
- location accessed by EXPR.
+/* Based on the memory reference REF and its virtual use VUSE call
+ WALKER for each virtual use that is equivalent to VUSE, including VUSE
+ itself. That is, for each virtual use for which its defining statement
+ does not clobber REF.
- Note, the set of aliases represented by the new symbol tag are not
- marked for renaming. */
+ WALKER is called with REF, the current virtual use and DATA. If
+ WALKER returns non-NULL the walk stops and its result is returned.
+ At the end of a non-successful walk NULL is returned.
-void
-new_type_alias (tree ptr, tree var, tree expr)
+ TODO: Cache the vector of equivalent vuses per ref, vuse pair. */
+
+void *
+walk_non_aliased_vuses (tree ref, tree vuse,
+ void *(*walker)(tree, tree, void *), void *data)
{
- tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
- tree tag;
- tree ali = NULL_TREE;
- HOST_WIDE_INT offset, size, maxsize;
- tree ref;
+ bitmap visited = NULL;
+ void *res;
- gcc_assert (symbol_mem_tag (ptr) == NULL_TREE);
- gcc_assert (!MTAG_P (var));
+ timevar_push (TV_ALIAS_STMT_WALK);
- ref = get_ref_base_and_extent (expr, &offset, &size, &maxsize);
- gcc_assert (ref);
+ do
+ {
+ gimple def_stmt;
- tag = create_memory_tag (tag_type, true);
- set_symbol_mem_tag (ptr, tag);
+ /* ??? Do we want to account this to TV_ALIAS_STMT_WALK? */
+ res = (*walker) (ref, vuse, data);
+ if (res)
+ break;
- ali = add_may_alias_for_new_tag (tag, var);
+ def_stmt = SSA_NAME_DEF_STMT (vuse);
+ if (gimple_nop_p (def_stmt))
+ break;
+ else if (gimple_code (def_stmt) == GIMPLE_PHI)
+ vuse = get_continuation_for_phi (def_stmt, ref, &visited);
+ else
+ {
+ if (stmt_may_clobber_ref_p (def_stmt, ref))
+ break;
+ vuse = gimple_vuse (def_stmt);
+ }
+ }
+ while (vuse);
- set_symbol_mem_tag (ptr, ali);
- MTAG_GLOBAL (tag) = is_global_var (var);
+ if (visited)
+ BITMAP_FREE (visited);
+
+ timevar_pop (TV_ALIAS_STMT_WALK);
+
+ return res;
}
-/* Reset the call_clobbered flags on our referenced vars. In
- theory, this only needs to be done for globals. */
+/* Based on the memory reference REF call WALKER for each vdef which
+ defining statement may clobber REF, starting with VDEF. If REF
+ is NULL_TREE, each defining statement is visited.
+
+ WALKER is called with REF, the current vdef and DATA. If WALKER
+ returns true the walk is stopped, otherwise it continues.
+
+ At PHI nodes walk_aliased_vdefs forks into one walk for reach
+ PHI argument (but only one walk continues on merge points), the
+ return value is true if any of the walks was successful.
+
+ The function returns the number of statements walked. */
static unsigned int
-reset_cc_flags (void)
+walk_aliased_vdefs_1 (tree ref, tree vdef,
+ bool (*walker)(tree, tree, void *), void *data,
+ bitmap *visited, unsigned int cnt)
{
- tree var;
- referenced_var_iterator rvi;
+ do
+ {
+ gimple def_stmt = SSA_NAME_DEF_STMT (vdef);
- FOR_EACH_REFERENCED_VAR (var, rvi)
- var_ann (var)->call_clobbered = false;
- return 0;
+ if (*visited
+ && !bitmap_set_bit (*visited, SSA_NAME_VERSION (vdef)))
+ return cnt;
+
+ if (gimple_nop_p (def_stmt))
+ return cnt;
+ else if (gimple_code (def_stmt) == GIMPLE_PHI)
+ {
+ unsigned i;
+ if (!*visited)
+ *visited = BITMAP_ALLOC (NULL);
+ for (i = 0; i < gimple_phi_num_args (def_stmt); ++i)
+ cnt += walk_aliased_vdefs_1 (ref, gimple_phi_arg_def (def_stmt, i),
+ walker, data, visited, 0);
+ return cnt;
+ }
+
+ /* ??? Do we want to account this to TV_ALIAS_STMT_WALK? */
+ cnt++;
+ if ((!ref
+ || stmt_may_clobber_ref_p (def_stmt, ref))
+ && (*walker) (ref, vdef, data))
+ return cnt;
+
+ vdef = gimple_vuse (def_stmt);
+ }
+ while (1);
}
-struct gimple_opt_pass pass_reset_cc_flags =
-{
- {
- GIMPLE_PASS,
- NULL, /* name */
- NULL, /* gate */
- reset_cc_flags, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- PROP_referenced_vars |PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
-};
-
-
-/* A dummy pass to cause aliases to be computed via TODO_rebuild_alias. */
-
-struct gimple_opt_pass pass_build_alias =
+unsigned int
+walk_aliased_vdefs (tree ref, tree vdef,
+ bool (*walker)(tree, tree, void *), void *data,
+ bitmap *visited)
{
- {
- GIMPLE_PASS,
- "alias", /* name */
- NULL, /* gate */
- NULL, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- PROP_alias, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_rebuild_alias | TODO_dump_func /* todo_flags_finish */
- }
-};
+ bitmap local_visited = NULL;
+ unsigned int ret;
+
+ timevar_push (TV_ALIAS_STMT_WALK);
+
+ ret = walk_aliased_vdefs_1 (ref, vdef, walker, data,
+ visited ? visited : &local_visited, 0);
+ if (local_visited)
+ BITMAP_FREE (local_visited);
+
+ timevar_pop (TV_ALIAS_STMT_WALK);
+
+ return ret;
+}
+