diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-10-05 10:42:24 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-10-05 10:42:24 +0000 |
commit | 85344eeb1a722e91178c011ce3c56904c9bfdd31 (patch) | |
tree | ff7a8ef56d2fdbc4a060af939444fce16b626c97 /gcc/tree-profile.c | |
parent | 33d033da15b856fdbdfe2c2b7b07c29580a1df11 (diff) | |
download | gcc-85344eeb1a722e91178c011ce3c56904c9bfdd31.tar.gz |
2010-10-05 Richard Guenther <rguenther@suse.de>
* value-prof.c (gimple_divmod_fixed_value): Work on SSA form.
(gimple_mod_pow2): Likewise.
(gimple_mod_subtract): Likewise.
(gimple_ic): Likewise.
(gimple_stringop_fixed_value): Likewise.
* tree-profile.c (tree_init_edge_profiler): Mark profile
functions nothrow and leaf.
(add_abnormal_goto_call_edges): Remove.
(tree_gen_edge_profiler): Work on SSA form.
(tree_gen_ic_profiler): Likewise. Simplify.
(do_tree_profiling): Update SSA form.
(pass_tree_profile): Remove.
(do_tree_profiling): Likewise.
(gate_tree_profile_ipa): New function.
(pass_ipa_tree_profile): New.
(tree_profiling): Re-write as IPA pass. Properly drop const/pure
state of instrumented functions.
* passes.c (init_optimization_passes): Remove early non-SSA
inlining. Move profiling after early optimizations.
* ipa-inline.c (cgraph_gate_ipa_early_inlining): Remove.
(pass_ipa_early_inline): Likewise.
* tree-pass.h (pass_ipa_early_inline): Remove.
(pass_tree_profile): Likewise.
(pass_ipa_tree_profile): Declare.
* gcc.dg/tree-prof/val-prof-1.c: Adjust.
* gcc.dg/tree-prof/val-prof-2.c: Likewise.
* gcc.dg/tree-prof/val-prof-3.c: Likewise.
* gcc.dg/tree-prof/val-prof-4.c: Likewise.
* gcc.dg/tree-prof/val-prof-5.c: Likewise.
* gcc.dg/tree-prof/val-prof-7.c: Likewise.
* gcc.dg/tree-prof/stringop-1.c: Likewise.
* gcc.dg/tree-prof/stringop-2.c: Likewise.
* gcc.dg/tree-prof/ic-misattribution-1.c: Likewise.
* gcc.dg/tree-prof/indir-call-prof.c: Likewise.
* gcc.dg/tree-prof/update-loopch.c: Likewise.
* g++.dg/tree-prof/indir-call-prof.C: Likewise.
* g++.dg/tree-prof/inline_mismatch_args.C: Likewise.
* gcc.dg/tree-prof/tracer-1.c: Likewise.
* gcc.dg/tree-ssa/inline-4.c: Likewise.
* gcc.dg/tree-ssa/inline-3.c: Likewise.
* gcc.dg/tree-ssa/20080530.c: Likewise.
* g++.dg/tree-ssa/inline-3.C: Likewise.
* g++.dg/tree-ssa/inline-1.C: Likewise.
* g++.dg/tree-ssa/inline-2.C: Likewise.
* gcc.dg/profile-dir-1.c: Likewise.
* gcc.dg/profile-dir-2.c: Likewise.
* gcc.dg/profile-dir-3.c: Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@164986 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-profile.c')
-rw-r--r-- | gcc/tree-profile.c | 300 |
1 files changed, 185 insertions, 115 deletions
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c index 50ce013830d..5b7c12bad4d 100644 --- a/gcc/tree-profile.c +++ b/gcc/tree-profile.c @@ -120,6 +120,10 @@ tree_init_edge_profiler (void) tree_interval_profiler_fn = build_fn_decl ("__gcov_interval_profiler", interval_profiler_fn_type); + TREE_NOTHROW (tree_interval_profiler_fn) = 1; + DECL_ATTRIBUTES (tree_interval_profiler_fn) + = tree_cons (get_identifier ("leaf"), NULL, + DECL_ATTRIBUTES (tree_interval_profiler_fn)); /* void (*) (gcov_type *, gcov_type) */ pow2_profiler_fn_type @@ -128,6 +132,10 @@ tree_init_edge_profiler (void) NULL_TREE); tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler", pow2_profiler_fn_type); + TREE_NOTHROW (tree_pow2_profiler_fn) = 1; + DECL_ATTRIBUTES (tree_pow2_profiler_fn) + = tree_cons (get_identifier ("leaf"), NULL, + DECL_ATTRIBUTES (tree_pow2_profiler_fn)); /* void (*) (gcov_type *, gcov_type) */ one_value_profiler_fn_type @@ -137,6 +145,10 @@ tree_init_edge_profiler (void) tree_one_value_profiler_fn = build_fn_decl ("__gcov_one_value_profiler", one_value_profiler_fn_type); + TREE_NOTHROW (tree_one_value_profiler_fn) = 1; + DECL_ATTRIBUTES (tree_one_value_profiler_fn) + = tree_cons (get_identifier ("leaf"), NULL, + DECL_ATTRIBUTES (tree_one_value_profiler_fn)); tree_init_ic_make_global_vars (); @@ -149,6 +161,11 @@ tree_init_edge_profiler (void) tree_indirect_call_profiler_fn = build_fn_decl ("__gcov_indirect_call_profiler", ic_profiler_fn_type); + TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1; + DECL_ATTRIBUTES (tree_indirect_call_profiler_fn) + = tree_cons (get_identifier ("leaf"), NULL, + DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)); + /* void (*) (gcov_type *, gcov_type) */ average_profiler_fn_type = build_function_type_list (void_type_node, @@ -156,9 +173,18 @@ tree_init_edge_profiler (void) tree_average_profiler_fn = build_fn_decl ("__gcov_average_profiler", average_profiler_fn_type); + TREE_NOTHROW (tree_average_profiler_fn) = 1; + DECL_ATTRIBUTES (tree_average_profiler_fn) + = tree_cons (get_identifier ("leaf"), NULL, + DECL_ATTRIBUTES (tree_average_profiler_fn)); tree_ior_profiler_fn = build_fn_decl ("__gcov_ior_profiler", average_profiler_fn_type); + TREE_NOTHROW (tree_ior_profiler_fn) = 1; + DECL_ATTRIBUTES (tree_ior_profiler_fn) + = tree_cons (get_identifier ("leaf"), NULL, + DECL_ATTRIBUTES (tree_ior_profiler_fn)); + /* LTO streamer needs assembler names. Because we create these decls late, we need to initialize them by hand. */ DECL_ASSEMBLER_NAME (tree_interval_profiler_fn); @@ -170,20 +196,6 @@ tree_init_edge_profiler (void) } } -/* New call was added, make goto call edges if neccesary. */ - -static void -add_abnormal_goto_call_edges (gimple_stmt_iterator gsi) -{ - gimple stmt = gsi_stmt (gsi); - - if (!stmt_can_make_abnormal_goto (stmt)) - return; - if (!gsi_end_p (gsi)) - split_block (gimple_bb (stmt), stmt); - make_abnormal_goto_edges (gimple_bb (stmt), true); -} - /* Output instructions as GIMPLE trees to increment the edge execution count, and insert them on E. We rely on gsi_insert_on_edge to preserve the order. */ @@ -197,13 +209,15 @@ tree_gen_edge_profiler (int edgeno, edge e) /* We share one temporary variable declaration per function. This gets re-set in tree_profiling. */ if (gcov_type_tmp_var == NULL_TREE) - gcov_type_tmp_var = create_tmp_var (gcov_type_node, "PROF_edge_counter"); + gcov_type_tmp_var = create_tmp_reg (gcov_type_node, "PROF_edge_counter"); ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); one = build_int_cst (gcov_type_node, 1); stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); + gimple_assign_set_lhs (stmt1, make_ssa_name (gcov_type_tmp_var, stmt1)); stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, gcov_type_tmp_var, - gcov_type_tmp_var, one); - stmt3 = gimple_build_assign (unshare_expr (ref), gcov_type_tmp_var); + gimple_assign_lhs (stmt1), one); + gimple_assign_set_lhs (stmt2, make_ssa_name (gcov_type_tmp_var, stmt2)); + stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); gsi_insert_on_edge (e, stmt1); gsi_insert_on_edge (e, stmt2); gsi_insert_on_edge (e, stmt3); @@ -246,7 +260,6 @@ tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) call = gimple_build_call (tree_interval_profiler_fn, 4, ref_ptr, val, start, steps); gsi_insert_before (&gsi, call, GSI_NEW_STMT); - add_abnormal_goto_call_edges (gsi); } /* Output instructions as GIMPLE trees to increment the power of two histogram @@ -267,7 +280,6 @@ tree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base) val = prepare_instrumented_value (&gsi, value); call = gimple_build_call (tree_pow2_profiler_fn, 2, ref_ptr, val); gsi_insert_before (&gsi, call, GSI_NEW_STMT); - add_abnormal_goto_call_edges (gsi); } /* Output instructions as GIMPLE trees for code to find the most common value. @@ -288,7 +300,6 @@ tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base) val = prepare_instrumented_value (&gsi, value); call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val); gsi_insert_before (&gsi, call, GSI_NEW_STMT); - add_abnormal_goto_call_edges (gsi); } @@ -316,10 +327,11 @@ tree_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base) __gcov_indirect_call_callee = (void *) indirect call argument; */ - tmp1 = create_tmp_var (ptr_void, "PROF"); + tmp1 = create_tmp_reg (ptr_void, "PROF"); stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr); stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value)); - stmt3 = gimple_build_assign (ic_void_ptr_var, tmp1); + gimple_assign_set_lhs (stmt2, make_ssa_name (tmp1, stmt2)); + stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2)); gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); @@ -337,51 +349,38 @@ tree_gen_ic_func_profiler (void) { struct cgraph_node * c_node = cgraph_node (current_function_decl); gimple_stmt_iterator gsi; - edge e; - basic_block bb; - edge_iterator ei; gimple stmt1, stmt2; - tree tree_uid, cur_func, counter_ptr, ptr_var; + tree tree_uid, cur_func, counter_ptr, ptr_var, void0; if (cgraph_only_called_directly_p (c_node)) return; tree_init_edge_profiler (); - FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) - { - tree void0; - - bb = split_edge (e); - gsi = gsi_start_bb (bb); - - cur_func = force_gimple_operand_gsi (&gsi, - build_addr (current_function_decl, - current_function_decl), - true, NULL_TREE, - true, GSI_NEW_STMT); - counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var, - true, NULL_TREE, false, - GSI_NEW_STMT); - ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var, - true, NULL_TREE, false, - GSI_NEW_STMT); - tree_uid = build_int_cst (gcov_type_node, c_node->pid); - stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4, - counter_ptr, tree_uid, cur_func, ptr_var); - gsi_insert_after (&gsi, stmt1, GSI_NEW_STMT); - gcc_assert (EDGE_COUNT (bb->succs) == 1); - bb = split_edge (EDGE_I (bb->succs, 0)); - add_abnormal_goto_call_edges (gsi); - - gsi = gsi_start_bb (bb); - /* Set __gcov_indirect_call_callee to 0, - so that calls from other modules won't get misattributed - to the last caller of the current callee. */ - void0 = build_int_cst (build_pointer_type (void_type_node), 0); - stmt2 = gimple_build_assign (ic_void_ptr_var, void0); - gsi_insert_after (&gsi, stmt2, GSI_NEW_STMT); - } + gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR)); + + cur_func = force_gimple_operand_gsi (&gsi, + build_addr (current_function_decl, + current_function_decl), + true, NULL_TREE, + true, GSI_SAME_STMT); + counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var, + true, NULL_TREE, true, + GSI_SAME_STMT); + ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var, + true, NULL_TREE, true, + GSI_SAME_STMT); + tree_uid = build_int_cst (gcov_type_node, c_node->pid); + stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4, + counter_ptr, tree_uid, cur_func, ptr_var); + gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); + + /* Set __gcov_indirect_call_callee to 0, + so that calls from other modules won't get misattributed + to the last caller of the current callee. */ + void0 = build_int_cst (build_pointer_type (void_type_node), 0); + stmt2 = gimple_build_assign (ic_void_ptr_var, void0); + gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); } /* Output instructions as GIMPLE trees for code to find the most common value @@ -420,7 +419,6 @@ tree_gen_average_profiler (histogram_value value, unsigned tag, unsigned base) val = prepare_instrumented_value (&gsi, value); call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val); gsi_insert_before (&gsi, call, GSI_NEW_STMT); - add_abnormal_goto_call_edges (gsi); } /* Output instructions as GIMPLE trees to increment the ior histogram @@ -441,81 +439,153 @@ tree_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base) val = prepare_instrumented_value (&gsi, value); call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val); gsi_insert_before (&gsi, call, GSI_NEW_STMT); - add_abnormal_goto_call_edges (gsi); } -/* Return 1 if tree-based profiling is in effect, else 0. - If it is, set up hooks for tree-based profiling. - Gate for pass_tree_profile. */ - -static bool -do_tree_profiling (void) -{ - if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) - { - tree_register_profile_hooks (); - gimple_register_value_prof_hooks (); - return true; - } - return false; -} +/* Profile all functions in the callgraph. */ static unsigned int tree_profiling (void) { + struct cgraph_node *node; + /* Don't profile functions produced at destruction time, particularly the gcov datastructure initializer. Don't profile if it has been already instrumented either (when OpenMP expansion creates child function from already instrumented body). */ - if (cgraph_state == CGRAPH_STATE_FINISHED - || cfun->after_tree_profile) + if (cgraph_state == CGRAPH_STATE_FINISHED) return 0; - /* Don't profile functions produced for builtin stuff. */ - if (DECL_SOURCE_LOCATION (current_function_decl) == BUILTINS_LOCATION) - return 0; + tree_register_profile_hooks (); + gimple_register_value_prof_hooks (); + + for (node = cgraph_nodes; node; node = node->next) + { + if (!node->analyzed + || !gimple_has_body_p (node->decl) + || !(!node->clone_of || node->decl != node->clone_of->decl)) + continue; + + /* Don't profile functions produced for builtin stuff. */ + if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION + || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) + continue; + + push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + current_function_decl = node->decl; + + /* Re-set global shared temporary variable for edge-counters. */ + gcov_type_tmp_var = NULL_TREE; + + branch_prob (); + + if (! flag_branch_probabilities + && flag_profile_values) + tree_gen_ic_func_profiler (); + + if (flag_branch_probabilities + && flag_profile_values + && flag_value_profile_transformations) + value_profile_transformations (); + + /* The above could hose dominator info. Currently there is + none coming in, this is a safety valve. It should be + easy to adjust it, if and when there is some. */ + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + + current_function_decl = NULL; + pop_cfun (); + } + + /* Drop pure/const flags from instrumented functions. */ + for (node = cgraph_nodes; node; node = node->next) + { + if (!node->analyzed + || !gimple_has_body_p (node->decl) + || !(!node->clone_of || node->decl != node->clone_of->decl)) + continue; + + /* Don't profile functions produced for builtin stuff. */ + if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION + || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) + continue; + + cgraph_set_readonly_flag (node, false); + cgraph_set_pure_flag (node, false); + cgraph_set_looping_const_or_pure_flag (node, false); + } + + /* Update call statements and rebuild the cgraph. */ + for (node = cgraph_nodes; node; node = node->next) + { + basic_block bb; + + if (!node->analyzed + || !gimple_has_body_p (node->decl) + || !(!node->clone_of || node->decl != node->clone_of->decl)) + continue; + + /* Don't profile functions produced for builtin stuff. */ + if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION + || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) + continue; + + push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + current_function_decl = node->decl; + + FOR_EACH_BB (bb) + { + gimple_stmt_iterator gsi; + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (is_gimple_call (stmt)) + update_stmt (stmt); + } + } + + cfun->after_tree_profile = 1; + update_ssa (TODO_update_ssa); + + rebuild_cgraph_edges (); + + current_function_decl = NULL; + pop_cfun (); + } - /* Re-set global shared temporary variable for edge-counters. */ - gcov_type_tmp_var = NULL_TREE; - - branch_prob (); - - if (! flag_branch_probabilities - && flag_profile_values) - tree_gen_ic_func_profiler (); - - if (flag_branch_probabilities - && flag_profile_values - && flag_value_profile_transformations) - value_profile_transformations (); - /* The above could hose dominator info. Currently there is - none coming in, this is a safety valve. It should be - easy to adjust it, if and when there is some. */ - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - cfun->after_tree_profile = 1; return 0; } -struct gimple_opt_pass pass_tree_profile = +/* When profile instrumentation, use or test coverage shall be performed. */ + +static bool +gate_tree_profile_ipa (void) +{ + return (!in_lto_p + && (flag_branch_probabilities || flag_test_coverage + || profile_arc_flag)); +} + +struct simple_ipa_opt_pass pass_ipa_tree_profile = { { - GIMPLE_PASS, - "tree_profile", /* name */ - do_tree_profiling, /* gate */ - tree_profiling, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_BRANCH_PROB, /* tv_id */ - PROP_gimple_leh | PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_verify_stmts | TODO_dump_func /* todo_flags_finish */ + SIMPLE_IPA_PASS, + "tree_profile_ipa", /* name */ + gate_tree_profile_ipa, /* gate */ + tree_profiling, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_IPA_PROFILE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ } }; + struct profile_hooks tree_profile_hooks = { tree_init_edge_profiler, /* init_edge_profiler */ |