138fd1498Szrj /* Calculate branch probabilities, and basic block execution counts.
238fd1498Szrj Copyright (C) 1990-2018 Free Software Foundation, Inc.
338fd1498Szrj Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
438fd1498Szrj based on some ideas from Dain Samples of UC Berkeley.
538fd1498Szrj Further mangling by Bob Manson, Cygnus Support.
638fd1498Szrj Converted to use trees by Dale Johannesen, Apple Computer.
738fd1498Szrj
838fd1498Szrj This file is part of GCC.
938fd1498Szrj
1038fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
1138fd1498Szrj the terms of the GNU General Public License as published by the Free
1238fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1338fd1498Szrj version.
1438fd1498Szrj
1538fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1638fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1738fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1838fd1498Szrj for more details.
1938fd1498Szrj
2038fd1498Szrj You should have received a copy of the GNU General Public License
2138fd1498Szrj along with GCC; see the file COPYING3. If not see
2238fd1498Szrj <http://www.gnu.org/licenses/>. */
2338fd1498Szrj
2438fd1498Szrj /* Generate basic block profile instrumentation and auxiliary files.
2538fd1498Szrj Tree-based version. See profile.c for overview. */
2638fd1498Szrj
2738fd1498Szrj #include "config.h"
2838fd1498Szrj #include "system.h"
2938fd1498Szrj #include "coretypes.h"
3038fd1498Szrj #include "memmodel.h"
3138fd1498Szrj #include "backend.h"
3238fd1498Szrj #include "target.h"
3338fd1498Szrj #include "tree.h"
3438fd1498Szrj #include "gimple.h"
3538fd1498Szrj #include "cfghooks.h"
3638fd1498Szrj #include "tree-pass.h"
3738fd1498Szrj #include "ssa.h"
3838fd1498Szrj #include "cgraph.h"
3938fd1498Szrj #include "coverage.h"
4038fd1498Szrj #include "diagnostic-core.h"
4138fd1498Szrj #include "fold-const.h"
4238fd1498Szrj #include "varasm.h"
4338fd1498Szrj #include "tree-nested.h"
4438fd1498Szrj #include "gimplify.h"
4538fd1498Szrj #include "gimple-iterator.h"
4638fd1498Szrj #include "gimplify-me.h"
4738fd1498Szrj #include "tree-cfg.h"
4838fd1498Szrj #include "tree-into-ssa.h"
4938fd1498Szrj #include "value-prof.h"
5038fd1498Szrj #include "profile.h"
5138fd1498Szrj #include "tree-cfgcleanup.h"
5238fd1498Szrj #include "params.h"
5338fd1498Szrj #include "stringpool.h"
5438fd1498Szrj #include "attribs.h"
5538fd1498Szrj #include "tree-pretty-print.h"
5638fd1498Szrj
5738fd1498Szrj static GTY(()) tree gcov_type_node;
5838fd1498Szrj static GTY(()) tree tree_interval_profiler_fn;
5938fd1498Szrj static GTY(()) tree tree_pow2_profiler_fn;
6038fd1498Szrj static GTY(()) tree tree_one_value_profiler_fn;
6138fd1498Szrj static GTY(()) tree tree_indirect_call_profiler_fn;
6238fd1498Szrj static GTY(()) tree tree_average_profiler_fn;
6338fd1498Szrj static GTY(()) tree tree_ior_profiler_fn;
6438fd1498Szrj static GTY(()) tree tree_time_profiler_counter;
6538fd1498Szrj
6638fd1498Szrj
6738fd1498Szrj static GTY(()) tree ic_void_ptr_var;
6838fd1498Szrj static GTY(()) tree ic_gcov_type_ptr_var;
6938fd1498Szrj static GTY(()) tree ptr_void;
7038fd1498Szrj
7138fd1498Szrj /* Do initialization work for the edge profiler. */
7238fd1498Szrj
7338fd1498Szrj /* Add code:
7438fd1498Szrj __thread gcov* __gcov_indirect_call_counters; // pointer to actual counter
7538fd1498Szrj __thread void* __gcov_indirect_call_callee; // actual callee address
7638fd1498Szrj __thread int __gcov_function_counter; // time profiler function counter
7738fd1498Szrj */
7838fd1498Szrj static void
init_ic_make_global_vars(void)7938fd1498Szrj init_ic_make_global_vars (void)
8038fd1498Szrj {
8138fd1498Szrj tree gcov_type_ptr;
8238fd1498Szrj
8338fd1498Szrj ptr_void = build_pointer_type (void_type_node);
8438fd1498Szrj
8538fd1498Szrj ic_void_ptr_var
8638fd1498Szrj = build_decl (UNKNOWN_LOCATION, VAR_DECL,
8738fd1498Szrj get_identifier (
8838fd1498Szrj (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
8938fd1498Szrj "__gcov_indirect_call_topn_callee" :
9038fd1498Szrj "__gcov_indirect_call_callee")),
9138fd1498Szrj ptr_void);
9238fd1498Szrj TREE_PUBLIC (ic_void_ptr_var) = 1;
9338fd1498Szrj DECL_EXTERNAL (ic_void_ptr_var) = 1;
9438fd1498Szrj TREE_STATIC (ic_void_ptr_var) = 1;
9538fd1498Szrj DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
9638fd1498Szrj DECL_INITIAL (ic_void_ptr_var) = NULL;
9738fd1498Szrj if (targetm.have_tls)
9838fd1498Szrj set_decl_tls_model (ic_void_ptr_var, decl_default_tls_model (ic_void_ptr_var));
9938fd1498Szrj
10038fd1498Szrj gcov_type_ptr = build_pointer_type (get_gcov_type ());
10138fd1498Szrj
10238fd1498Szrj ic_gcov_type_ptr_var
10338fd1498Szrj = build_decl (UNKNOWN_LOCATION, VAR_DECL,
10438fd1498Szrj get_identifier (
10538fd1498Szrj (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
10638fd1498Szrj "__gcov_indirect_call_topn_counters" :
10738fd1498Szrj "__gcov_indirect_call_counters")),
10838fd1498Szrj gcov_type_ptr);
10938fd1498Szrj TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
11038fd1498Szrj DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1;
11138fd1498Szrj TREE_STATIC (ic_gcov_type_ptr_var) = 1;
11238fd1498Szrj DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1;
11338fd1498Szrj DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
11438fd1498Szrj if (targetm.have_tls)
11538fd1498Szrj set_decl_tls_model (ic_gcov_type_ptr_var, decl_default_tls_model (ic_gcov_type_ptr_var));
11638fd1498Szrj }
11738fd1498Szrj
11838fd1498Szrj /* Create the type and function decls for the interface with gcov. */
11938fd1498Szrj
12038fd1498Szrj void
gimple_init_gcov_profiler(void)12138fd1498Szrj gimple_init_gcov_profiler (void)
12238fd1498Szrj {
12338fd1498Szrj tree interval_profiler_fn_type;
12438fd1498Szrj tree pow2_profiler_fn_type;
12538fd1498Szrj tree one_value_profiler_fn_type;
12638fd1498Szrj tree gcov_type_ptr;
12738fd1498Szrj tree ic_profiler_fn_type;
12838fd1498Szrj tree average_profiler_fn_type;
12938fd1498Szrj const char *profiler_fn_name;
13038fd1498Szrj const char *fn_name;
13138fd1498Szrj
13238fd1498Szrj if (!gcov_type_node)
13338fd1498Szrj {
13438fd1498Szrj const char *fn_suffix
13538fd1498Szrj = flag_profile_update == PROFILE_UPDATE_ATOMIC ? "_atomic" : "";
13638fd1498Szrj
13738fd1498Szrj gcov_type_node = get_gcov_type ();
13838fd1498Szrj gcov_type_ptr = build_pointer_type (gcov_type_node);
13938fd1498Szrj
14038fd1498Szrj /* void (*) (gcov_type *, gcov_type, int, unsigned) */
14138fd1498Szrj interval_profiler_fn_type
14238fd1498Szrj = build_function_type_list (void_type_node,
14338fd1498Szrj gcov_type_ptr, gcov_type_node,
14438fd1498Szrj integer_type_node,
14538fd1498Szrj unsigned_type_node, NULL_TREE);
14638fd1498Szrj fn_name = concat ("__gcov_interval_profiler", fn_suffix, NULL);
14738fd1498Szrj tree_interval_profiler_fn = build_fn_decl (fn_name,
14838fd1498Szrj interval_profiler_fn_type);
14938fd1498Szrj free (CONST_CAST (char *, fn_name));
15038fd1498Szrj TREE_NOTHROW (tree_interval_profiler_fn) = 1;
15138fd1498Szrj DECL_ATTRIBUTES (tree_interval_profiler_fn)
15238fd1498Szrj = tree_cons (get_identifier ("leaf"), NULL,
15338fd1498Szrj DECL_ATTRIBUTES (tree_interval_profiler_fn));
15438fd1498Szrj
15538fd1498Szrj /* void (*) (gcov_type *, gcov_type) */
15638fd1498Szrj pow2_profiler_fn_type
15738fd1498Szrj = build_function_type_list (void_type_node,
15838fd1498Szrj gcov_type_ptr, gcov_type_node,
15938fd1498Szrj NULL_TREE);
16038fd1498Szrj fn_name = concat ("__gcov_pow2_profiler", fn_suffix, NULL);
16138fd1498Szrj tree_pow2_profiler_fn = build_fn_decl (fn_name, pow2_profiler_fn_type);
16238fd1498Szrj free (CONST_CAST (char *, fn_name));
16338fd1498Szrj TREE_NOTHROW (tree_pow2_profiler_fn) = 1;
16438fd1498Szrj DECL_ATTRIBUTES (tree_pow2_profiler_fn)
16538fd1498Szrj = tree_cons (get_identifier ("leaf"), NULL,
16638fd1498Szrj DECL_ATTRIBUTES (tree_pow2_profiler_fn));
16738fd1498Szrj
16838fd1498Szrj /* void (*) (gcov_type *, gcov_type) */
16938fd1498Szrj one_value_profiler_fn_type
17038fd1498Szrj = build_function_type_list (void_type_node,
17138fd1498Szrj gcov_type_ptr, gcov_type_node,
17238fd1498Szrj NULL_TREE);
17338fd1498Szrj fn_name = concat ("__gcov_one_value_profiler", fn_suffix, NULL);
17438fd1498Szrj tree_one_value_profiler_fn = build_fn_decl (fn_name,
17538fd1498Szrj one_value_profiler_fn_type);
17638fd1498Szrj free (CONST_CAST (char *, fn_name));
17738fd1498Szrj TREE_NOTHROW (tree_one_value_profiler_fn) = 1;
17838fd1498Szrj DECL_ATTRIBUTES (tree_one_value_profiler_fn)
17938fd1498Szrj = tree_cons (get_identifier ("leaf"), NULL,
18038fd1498Szrj DECL_ATTRIBUTES (tree_one_value_profiler_fn));
18138fd1498Szrj
18238fd1498Szrj init_ic_make_global_vars ();
18338fd1498Szrj
18438fd1498Szrj /* void (*) (gcov_type, void *) */
18538fd1498Szrj ic_profiler_fn_type
18638fd1498Szrj = build_function_type_list (void_type_node,
18738fd1498Szrj gcov_type_node,
18838fd1498Szrj ptr_void,
18938fd1498Szrj NULL_TREE);
19038fd1498Szrj profiler_fn_name = "__gcov_indirect_call_profiler_v2";
19138fd1498Szrj if (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE))
19238fd1498Szrj profiler_fn_name = "__gcov_indirect_call_topn_profiler";
19338fd1498Szrj
19438fd1498Szrj tree_indirect_call_profiler_fn
19538fd1498Szrj = build_fn_decl (profiler_fn_name, ic_profiler_fn_type);
19638fd1498Szrj
19738fd1498Szrj TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1;
19838fd1498Szrj DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)
19938fd1498Szrj = tree_cons (get_identifier ("leaf"), NULL,
20038fd1498Szrj DECL_ATTRIBUTES (tree_indirect_call_profiler_fn));
20138fd1498Szrj
20238fd1498Szrj tree_time_profiler_counter
20338fd1498Szrj = build_decl (UNKNOWN_LOCATION, VAR_DECL,
20438fd1498Szrj get_identifier ("__gcov_time_profiler_counter"),
20538fd1498Szrj get_gcov_type ());
20638fd1498Szrj TREE_PUBLIC (tree_time_profiler_counter) = 1;
20738fd1498Szrj DECL_EXTERNAL (tree_time_profiler_counter) = 1;
20838fd1498Szrj TREE_STATIC (tree_time_profiler_counter) = 1;
20938fd1498Szrj DECL_ARTIFICIAL (tree_time_profiler_counter) = 1;
21038fd1498Szrj DECL_INITIAL (tree_time_profiler_counter) = NULL;
21138fd1498Szrj
21238fd1498Szrj /* void (*) (gcov_type *, gcov_type) */
21338fd1498Szrj average_profiler_fn_type
21438fd1498Szrj = build_function_type_list (void_type_node,
21538fd1498Szrj gcov_type_ptr, gcov_type_node, NULL_TREE);
21638fd1498Szrj fn_name = concat ("__gcov_average_profiler", fn_suffix, NULL);
21738fd1498Szrj tree_average_profiler_fn = build_fn_decl (fn_name,
21838fd1498Szrj average_profiler_fn_type);
21938fd1498Szrj free (CONST_CAST (char *, fn_name));
22038fd1498Szrj TREE_NOTHROW (tree_average_profiler_fn) = 1;
22138fd1498Szrj DECL_ATTRIBUTES (tree_average_profiler_fn)
22238fd1498Szrj = tree_cons (get_identifier ("leaf"), NULL,
22338fd1498Szrj DECL_ATTRIBUTES (tree_average_profiler_fn));
22438fd1498Szrj fn_name = concat ("__gcov_ior_profiler", fn_suffix, NULL);
22538fd1498Szrj tree_ior_profiler_fn = build_fn_decl (fn_name, average_profiler_fn_type);
22638fd1498Szrj free (CONST_CAST (char *, fn_name));
22738fd1498Szrj TREE_NOTHROW (tree_ior_profiler_fn) = 1;
22838fd1498Szrj DECL_ATTRIBUTES (tree_ior_profiler_fn)
22938fd1498Szrj = tree_cons (get_identifier ("leaf"), NULL,
23038fd1498Szrj DECL_ATTRIBUTES (tree_ior_profiler_fn));
23138fd1498Szrj
23238fd1498Szrj /* LTO streamer needs assembler names. Because we create these decls
23338fd1498Szrj late, we need to initialize them by hand. */
23438fd1498Szrj DECL_ASSEMBLER_NAME (tree_interval_profiler_fn);
23538fd1498Szrj DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn);
23638fd1498Szrj DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn);
23738fd1498Szrj DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn);
23838fd1498Szrj DECL_ASSEMBLER_NAME (tree_average_profiler_fn);
23938fd1498Szrj DECL_ASSEMBLER_NAME (tree_ior_profiler_fn);
24038fd1498Szrj }
24138fd1498Szrj }
24238fd1498Szrj
24338fd1498Szrj /* Output instructions as GIMPLE trees to increment the edge
24438fd1498Szrj execution count, and insert them on E. We rely on
24538fd1498Szrj gsi_insert_on_edge to preserve the order. */
24638fd1498Szrj
24738fd1498Szrj void
gimple_gen_edge_profiler(int edgeno,edge e)24838fd1498Szrj gimple_gen_edge_profiler (int edgeno, edge e)
24938fd1498Szrj {
25038fd1498Szrj tree one;
25138fd1498Szrj
25238fd1498Szrj one = build_int_cst (gcov_type_node, 1);
25338fd1498Szrj
25438fd1498Szrj if (flag_profile_update == PROFILE_UPDATE_ATOMIC)
25538fd1498Szrj {
25638fd1498Szrj /* __atomic_fetch_add (&counter, 1, MEMMODEL_RELAXED); */
25738fd1498Szrj tree addr = tree_coverage_counter_addr (GCOV_COUNTER_ARCS, edgeno);
25838fd1498Szrj tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32
25938fd1498Szrj ? BUILT_IN_ATOMIC_FETCH_ADD_8:
26038fd1498Szrj BUILT_IN_ATOMIC_FETCH_ADD_4);
26138fd1498Szrj gcall *stmt = gimple_build_call (f, 3, addr, one,
26238fd1498Szrj build_int_cst (integer_type_node,
26338fd1498Szrj MEMMODEL_RELAXED));
26438fd1498Szrj gsi_insert_on_edge (e, stmt);
26538fd1498Szrj }
26638fd1498Szrj else
26738fd1498Szrj {
26838fd1498Szrj tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
26938fd1498Szrj tree gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node,
27038fd1498Szrj NULL, "PROF_edge_counter");
27138fd1498Szrj gassign *stmt1 = gimple_build_assign (gcov_type_tmp_var, ref);
27238fd1498Szrj gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node,
27338fd1498Szrj NULL, "PROF_edge_counter");
27438fd1498Szrj gassign *stmt2 = gimple_build_assign (gcov_type_tmp_var, PLUS_EXPR,
27538fd1498Szrj gimple_assign_lhs (stmt1), one);
27638fd1498Szrj gassign *stmt3 = gimple_build_assign (unshare_expr (ref),
27738fd1498Szrj gimple_assign_lhs (stmt2));
27838fd1498Szrj gsi_insert_on_edge (e, stmt1);
27938fd1498Szrj gsi_insert_on_edge (e, stmt2);
28038fd1498Szrj gsi_insert_on_edge (e, stmt3);
28138fd1498Szrj }
28238fd1498Szrj }
28338fd1498Szrj
28438fd1498Szrj /* Emits code to get VALUE to instrument at GSI, and returns the
28538fd1498Szrj variable containing the value. */
28638fd1498Szrj
28738fd1498Szrj static tree
prepare_instrumented_value(gimple_stmt_iterator * gsi,histogram_value value)28838fd1498Szrj prepare_instrumented_value (gimple_stmt_iterator *gsi, histogram_value value)
28938fd1498Szrj {
29038fd1498Szrj tree val = value->hvalue.value;
29138fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (val)))
29238fd1498Szrj val = fold_convert (build_nonstandard_integer_type
29338fd1498Szrj (TYPE_PRECISION (TREE_TYPE (val)), 1), val);
29438fd1498Szrj return force_gimple_operand_gsi (gsi, fold_convert (gcov_type_node, val),
29538fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
29638fd1498Szrj }
29738fd1498Szrj
29838fd1498Szrj /* Output instructions as GIMPLE trees to increment the interval histogram
29938fd1498Szrj counter. VALUE is the expression whose value is profiled. TAG is the
30038fd1498Szrj tag of the section for counters, BASE is offset of the counter position. */
30138fd1498Szrj
30238fd1498Szrj void
gimple_gen_interval_profiler(histogram_value value,unsigned tag,unsigned base)30338fd1498Szrj gimple_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
30438fd1498Szrj {
30538fd1498Szrj gimple *stmt = value->hvalue.stmt;
30638fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
30738fd1498Szrj tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
30838fd1498Szrj gcall *call;
30938fd1498Szrj tree val;
31038fd1498Szrj tree start = build_int_cst_type (integer_type_node,
31138fd1498Szrj value->hdata.intvl.int_start);
31238fd1498Szrj tree steps = build_int_cst_type (unsigned_type_node,
31338fd1498Szrj value->hdata.intvl.steps);
31438fd1498Szrj
31538fd1498Szrj ref_ptr = force_gimple_operand_gsi (&gsi,
31638fd1498Szrj build_addr (ref),
31738fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
31838fd1498Szrj val = prepare_instrumented_value (&gsi, value);
31938fd1498Szrj call = gimple_build_call (tree_interval_profiler_fn, 4,
32038fd1498Szrj ref_ptr, val, start, steps);
32138fd1498Szrj gsi_insert_before (&gsi, call, GSI_NEW_STMT);
32238fd1498Szrj }
32338fd1498Szrj
32438fd1498Szrj /* Output instructions as GIMPLE trees to increment the power of two histogram
32538fd1498Szrj counter. VALUE is the expression whose value is profiled. TAG is the tag
32638fd1498Szrj of the section for counters, BASE is offset of the counter position. */
32738fd1498Szrj
32838fd1498Szrj void
gimple_gen_pow2_profiler(histogram_value value,unsigned tag,unsigned base)32938fd1498Szrj gimple_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
33038fd1498Szrj {
33138fd1498Szrj gimple *stmt = value->hvalue.stmt;
33238fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
33338fd1498Szrj tree ref_ptr = tree_coverage_counter_addr (tag, base);
33438fd1498Szrj gcall *call;
33538fd1498Szrj tree val;
33638fd1498Szrj
33738fd1498Szrj ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
33838fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
33938fd1498Szrj val = prepare_instrumented_value (&gsi, value);
34038fd1498Szrj call = gimple_build_call (tree_pow2_profiler_fn, 2, ref_ptr, val);
34138fd1498Szrj gsi_insert_before (&gsi, call, GSI_NEW_STMT);
34238fd1498Szrj }
34338fd1498Szrj
34438fd1498Szrj /* Output instructions as GIMPLE trees for code to find the most common value.
34538fd1498Szrj VALUE is the expression whose value is profiled. TAG is the tag of the
34638fd1498Szrj section for counters, BASE is offset of the counter position. */
34738fd1498Szrj
34838fd1498Szrj void
gimple_gen_one_value_profiler(histogram_value value,unsigned tag,unsigned base)34938fd1498Szrj gimple_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
35038fd1498Szrj {
35138fd1498Szrj gimple *stmt = value->hvalue.stmt;
35238fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
35338fd1498Szrj tree ref_ptr = tree_coverage_counter_addr (tag, base);
35438fd1498Szrj gcall *call;
35538fd1498Szrj tree val;
35638fd1498Szrj
35738fd1498Szrj ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
35838fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
35938fd1498Szrj val = prepare_instrumented_value (&gsi, value);
36038fd1498Szrj call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val);
36138fd1498Szrj gsi_insert_before (&gsi, call, GSI_NEW_STMT);
36238fd1498Szrj }
36338fd1498Szrj
36438fd1498Szrj
36538fd1498Szrj /* Output instructions as GIMPLE trees for code to find the most
36638fd1498Szrj common called function in indirect call.
36738fd1498Szrj VALUE is the call expression whose indirect callee is profiled.
36838fd1498Szrj TAG is the tag of the section for counters, BASE is offset of the
36938fd1498Szrj counter position. */
37038fd1498Szrj
37138fd1498Szrj void
gimple_gen_ic_profiler(histogram_value value,unsigned tag,unsigned base)37238fd1498Szrj gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base)
37338fd1498Szrj {
37438fd1498Szrj tree tmp1;
37538fd1498Szrj gassign *stmt1, *stmt2, *stmt3;
37638fd1498Szrj gimple *stmt = value->hvalue.stmt;
37738fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
37838fd1498Szrj tree ref_ptr = tree_coverage_counter_addr (tag, base);
37938fd1498Szrj
38038fd1498Szrj if ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) &&
38138fd1498Szrj tag == GCOV_COUNTER_V_INDIR) ||
38238fd1498Szrj (!PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) &&
38338fd1498Szrj tag == GCOV_COUNTER_ICALL_TOPNV))
38438fd1498Szrj return;
38538fd1498Szrj
38638fd1498Szrj ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
38738fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
38838fd1498Szrj
38938fd1498Szrj /* Insert code:
39038fd1498Szrj
39138fd1498Szrj stmt1: __gcov_indirect_call_counters = get_relevant_counter_ptr ();
39238fd1498Szrj stmt2: tmp1 = (void *) (indirect call argument value)
39338fd1498Szrj stmt3: __gcov_indirect_call_callee = tmp1;
39438fd1498Szrj
39538fd1498Szrj Example:
39638fd1498Szrj f_1 = foo;
39738fd1498Szrj __gcov_indirect_call_counters = &__gcov4.main[0];
39838fd1498Szrj PROF_9 = f_1;
39938fd1498Szrj __gcov_indirect_call_callee = PROF_9;
40038fd1498Szrj _4 = f_1 ();
40138fd1498Szrj */
40238fd1498Szrj
40338fd1498Szrj stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr);
40438fd1498Szrj tmp1 = make_temp_ssa_name (ptr_void, NULL, "PROF");
40538fd1498Szrj stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value));
40638fd1498Szrj stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2));
40738fd1498Szrj
40838fd1498Szrj gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
40938fd1498Szrj gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
41038fd1498Szrj gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT);
41138fd1498Szrj }
41238fd1498Szrj
41338fd1498Szrj
41438fd1498Szrj /* Output instructions as GIMPLE trees for code to find the most
41538fd1498Szrj common called function in indirect call. Insert instructions at the
41638fd1498Szrj beginning of every possible called function.
41738fd1498Szrj */
41838fd1498Szrj
41938fd1498Szrj void
gimple_gen_ic_func_profiler(void)42038fd1498Szrj gimple_gen_ic_func_profiler (void)
42138fd1498Szrj {
42238fd1498Szrj struct cgraph_node * c_node = cgraph_node::get (current_function_decl);
42338fd1498Szrj gcall *stmt1;
42438fd1498Szrj tree tree_uid, cur_func, void0;
42538fd1498Szrj
42638fd1498Szrj if (c_node->only_called_directly_p ())
42738fd1498Szrj return;
42838fd1498Szrj
42938fd1498Szrj gimple_init_gcov_profiler ();
43038fd1498Szrj
43138fd1498Szrj basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
43238fd1498Szrj basic_block cond_bb = split_edge (single_succ_edge (entry));
43338fd1498Szrj basic_block update_bb = split_edge (single_succ_edge (cond_bb));
43438fd1498Szrj
43538fd1498Szrj /* We need to do an extra split in order to not create an input
43638fd1498Szrj for a possible PHI node. */
43738fd1498Szrj split_edge (single_succ_edge (update_bb));
43838fd1498Szrj
43938fd1498Szrj edge true_edge = single_succ_edge (cond_bb);
44038fd1498Szrj true_edge->flags = EDGE_TRUE_VALUE;
44138fd1498Szrj
44238fd1498Szrj profile_probability probability;
44338fd1498Szrj if (DECL_VIRTUAL_P (current_function_decl))
44438fd1498Szrj probability = profile_probability::very_likely ();
44538fd1498Szrj else
44638fd1498Szrj probability = profile_probability::unlikely ();
44738fd1498Szrj
44838fd1498Szrj true_edge->probability = probability;
44938fd1498Szrj edge e = make_edge (cond_bb, single_succ_edge (update_bb)->dest,
45038fd1498Szrj EDGE_FALSE_VALUE);
45138fd1498Szrj e->probability = true_edge->probability.invert ();
45238fd1498Szrj
45338fd1498Szrj /* Insert code:
45438fd1498Szrj
45538fd1498Szrj if (__gcov_indirect_call_callee != NULL)
45638fd1498Szrj __gcov_indirect_call_profiler_v2 (profile_id, ¤t_function_decl);
45738fd1498Szrj
45838fd1498Szrj The function __gcov_indirect_call_profiler_v2 is responsible for
45938fd1498Szrj resetting __gcov_indirect_call_callee to NULL. */
46038fd1498Szrj
46138fd1498Szrj gimple_stmt_iterator gsi = gsi_start_bb (cond_bb);
46238fd1498Szrj void0 = build_int_cst (build_pointer_type (void_type_node), 0);
46338fd1498Szrj
46438fd1498Szrj tree ref = force_gimple_operand_gsi (&gsi, ic_void_ptr_var, true, NULL_TREE,
46538fd1498Szrj true, GSI_SAME_STMT);
46638fd1498Szrj
46738fd1498Szrj gcond *cond = gimple_build_cond (NE_EXPR, ref,
46838fd1498Szrj void0, NULL, NULL);
46938fd1498Szrj gsi_insert_before (&gsi, cond, GSI_NEW_STMT);
47038fd1498Szrj
47138fd1498Szrj gsi = gsi_after_labels (update_bb);
47238fd1498Szrj
47338fd1498Szrj cur_func = force_gimple_operand_gsi (&gsi,
47438fd1498Szrj build_addr (current_function_decl),
47538fd1498Szrj true, NULL_TREE,
47638fd1498Szrj true, GSI_SAME_STMT);
47738fd1498Szrj tree_uid = build_int_cst
47838fd1498Szrj (gcov_type_node,
47938fd1498Szrj cgraph_node::get (current_function_decl)->profile_id);
48038fd1498Szrj stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2,
48138fd1498Szrj tree_uid, cur_func);
48238fd1498Szrj gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
48338fd1498Szrj }
48438fd1498Szrj
48538fd1498Szrj /* Output instructions as GIMPLE tree at the beginning for each function.
48638fd1498Szrj TAG is the tag of the section for counters, BASE is offset of the
48738fd1498Szrj counter position and GSI is the iterator we place the counter. */
48838fd1498Szrj
48938fd1498Szrj void
gimple_gen_time_profiler(unsigned tag,unsigned base)49038fd1498Szrj gimple_gen_time_profiler (unsigned tag, unsigned base)
49138fd1498Szrj {
49238fd1498Szrj tree type = get_gcov_type ();
49338fd1498Szrj basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
49438fd1498Szrj basic_block cond_bb = split_edge (single_succ_edge (entry));
49538fd1498Szrj basic_block update_bb = split_edge (single_succ_edge (cond_bb));
49638fd1498Szrj
49738fd1498Szrj /* We need to do an extra split in order to not create an input
49838fd1498Szrj for a possible PHI node. */
49938fd1498Szrj split_edge (single_succ_edge (update_bb));
50038fd1498Szrj
50138fd1498Szrj edge true_edge = single_succ_edge (cond_bb);
50238fd1498Szrj true_edge->flags = EDGE_TRUE_VALUE;
50338fd1498Szrj true_edge->probability = profile_probability::unlikely ();
50438fd1498Szrj edge e
50538fd1498Szrj = make_edge (cond_bb, single_succ_edge (update_bb)->dest, EDGE_FALSE_VALUE);
50638fd1498Szrj e->probability = true_edge->probability.invert ();
50738fd1498Szrj
50838fd1498Szrj gimple_stmt_iterator gsi = gsi_start_bb (cond_bb);
50938fd1498Szrj tree original_ref = tree_coverage_counter_ref (tag, base);
51038fd1498Szrj tree ref = force_gimple_operand_gsi (&gsi, original_ref, true, NULL_TREE,
51138fd1498Szrj true, GSI_SAME_STMT);
51238fd1498Szrj tree one = build_int_cst (type, 1);
51338fd1498Szrj
51438fd1498Szrj /* Emit: if (counters[0] != 0). */
51538fd1498Szrj gcond *cond = gimple_build_cond (EQ_EXPR, ref, build_int_cst (type, 0),
51638fd1498Szrj NULL, NULL);
51738fd1498Szrj gsi_insert_before (&gsi, cond, GSI_NEW_STMT);
51838fd1498Szrj
51938fd1498Szrj gsi = gsi_start_bb (update_bb);
52038fd1498Szrj
52138fd1498Szrj /* Emit: counters[0] = ++__gcov_time_profiler_counter. */
52238fd1498Szrj if (flag_profile_update == PROFILE_UPDATE_ATOMIC)
52338fd1498Szrj {
52438fd1498Szrj tree ptr = make_temp_ssa_name (build_pointer_type (type), NULL,
52538fd1498Szrj "time_profiler_counter_ptr");
52638fd1498Szrj tree addr = build1 (ADDR_EXPR, TREE_TYPE (ptr),
52738fd1498Szrj tree_time_profiler_counter);
52838fd1498Szrj gassign *assign = gimple_build_assign (ptr, NOP_EXPR, addr);
52938fd1498Szrj gsi_insert_before (&gsi, assign, GSI_NEW_STMT);
53038fd1498Szrj tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32
53138fd1498Szrj ? BUILT_IN_ATOMIC_ADD_FETCH_8:
53238fd1498Szrj BUILT_IN_ATOMIC_ADD_FETCH_4);
53338fd1498Szrj gcall *stmt = gimple_build_call (f, 3, ptr, one,
53438fd1498Szrj build_int_cst (integer_type_node,
53538fd1498Szrj MEMMODEL_RELAXED));
53638fd1498Szrj tree result_type = TREE_TYPE (TREE_TYPE (f));
53738fd1498Szrj tree tmp = make_temp_ssa_name (result_type, NULL, "time_profile");
53838fd1498Szrj gimple_set_lhs (stmt, tmp);
53938fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
54038fd1498Szrj tmp = make_temp_ssa_name (type, NULL, "time_profile");
54138fd1498Szrj assign = gimple_build_assign (tmp, NOP_EXPR,
54238fd1498Szrj gimple_call_lhs (stmt));
54338fd1498Szrj gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
54438fd1498Szrj assign = gimple_build_assign (original_ref, tmp);
54538fd1498Szrj gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
54638fd1498Szrj }
54738fd1498Szrj else
54838fd1498Szrj {
54938fd1498Szrj tree tmp = make_temp_ssa_name (type, NULL, "time_profile");
55038fd1498Szrj gassign *assign = gimple_build_assign (tmp, tree_time_profiler_counter);
55138fd1498Szrj gsi_insert_before (&gsi, assign, GSI_NEW_STMT);
55238fd1498Szrj
55338fd1498Szrj tmp = make_temp_ssa_name (type, NULL, "time_profile");
55438fd1498Szrj assign = gimple_build_assign (tmp, PLUS_EXPR, gimple_assign_lhs (assign),
55538fd1498Szrj one);
55638fd1498Szrj gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
55738fd1498Szrj assign = gimple_build_assign (original_ref, tmp);
55838fd1498Szrj gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
55938fd1498Szrj assign = gimple_build_assign (tree_time_profiler_counter, tmp);
56038fd1498Szrj gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
56138fd1498Szrj }
56238fd1498Szrj }
56338fd1498Szrj
56438fd1498Szrj /* Output instructions as GIMPLE trees to increment the average histogram
56538fd1498Szrj counter. VALUE is the expression whose value is profiled. TAG is the
56638fd1498Szrj tag of the section for counters, BASE is offset of the counter position. */
56738fd1498Szrj
56838fd1498Szrj void
gimple_gen_average_profiler(histogram_value value,unsigned tag,unsigned base)56938fd1498Szrj gimple_gen_average_profiler (histogram_value value, unsigned tag, unsigned base)
57038fd1498Szrj {
57138fd1498Szrj gimple *stmt = value->hvalue.stmt;
57238fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
57338fd1498Szrj tree ref_ptr = tree_coverage_counter_addr (tag, base);
57438fd1498Szrj gcall *call;
57538fd1498Szrj tree val;
57638fd1498Szrj
57738fd1498Szrj ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
57838fd1498Szrj true, NULL_TREE,
57938fd1498Szrj true, GSI_SAME_STMT);
58038fd1498Szrj val = prepare_instrumented_value (&gsi, value);
58138fd1498Szrj call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val);
58238fd1498Szrj gsi_insert_before (&gsi, call, GSI_NEW_STMT);
58338fd1498Szrj }
58438fd1498Szrj
58538fd1498Szrj /* Output instructions as GIMPLE trees to increment the ior histogram
58638fd1498Szrj counter. VALUE is the expression whose value is profiled. TAG is the
58738fd1498Szrj tag of the section for counters, BASE is offset of the counter position. */
58838fd1498Szrj
58938fd1498Szrj void
gimple_gen_ior_profiler(histogram_value value,unsigned tag,unsigned base)59038fd1498Szrj gimple_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base)
59138fd1498Szrj {
59238fd1498Szrj gimple *stmt = value->hvalue.stmt;
59338fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
59438fd1498Szrj tree ref_ptr = tree_coverage_counter_addr (tag, base);
59538fd1498Szrj gcall *call;
59638fd1498Szrj tree val;
59738fd1498Szrj
59838fd1498Szrj ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
59938fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
60038fd1498Szrj val = prepare_instrumented_value (&gsi, value);
60138fd1498Szrj call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val);
60238fd1498Szrj gsi_insert_before (&gsi, call, GSI_NEW_STMT);
60338fd1498Szrj }
60438fd1498Szrj
60538fd1498Szrj #ifndef HAVE_sync_compare_and_swapsi
60638fd1498Szrj #define HAVE_sync_compare_and_swapsi 0
60738fd1498Szrj #endif
60838fd1498Szrj #ifndef HAVE_atomic_compare_and_swapsi
60938fd1498Szrj #define HAVE_atomic_compare_and_swapsi 0
61038fd1498Szrj #endif
61138fd1498Szrj
61238fd1498Szrj #ifndef HAVE_sync_compare_and_swapdi
61338fd1498Szrj #define HAVE_sync_compare_and_swapdi 0
61438fd1498Szrj #endif
61538fd1498Szrj #ifndef HAVE_atomic_compare_and_swapdi
61638fd1498Szrj #define HAVE_atomic_compare_and_swapdi 0
61738fd1498Szrj #endif
61838fd1498Szrj
61938fd1498Szrj /* Profile all functions in the callgraph. */
62038fd1498Szrj
62138fd1498Szrj static unsigned int
tree_profiling(void)62238fd1498Szrj tree_profiling (void)
62338fd1498Szrj {
62438fd1498Szrj struct cgraph_node *node;
62538fd1498Szrj
62638fd1498Szrj /* Verify whether we can utilize atomic update operations. */
62738fd1498Szrj bool can_support_atomic = false;
62838fd1498Szrj unsigned HOST_WIDE_INT gcov_type_size
62938fd1498Szrj = tree_to_uhwi (TYPE_SIZE_UNIT (get_gcov_type ()));
63038fd1498Szrj if (gcov_type_size == 4)
63138fd1498Szrj can_support_atomic
63238fd1498Szrj = HAVE_sync_compare_and_swapsi || HAVE_atomic_compare_and_swapsi;
63338fd1498Szrj else if (gcov_type_size == 8)
63438fd1498Szrj can_support_atomic
63538fd1498Szrj = HAVE_sync_compare_and_swapdi || HAVE_atomic_compare_and_swapdi;
63638fd1498Szrj
63738fd1498Szrj if (flag_profile_update == PROFILE_UPDATE_ATOMIC
63838fd1498Szrj && !can_support_atomic)
63938fd1498Szrj {
64038fd1498Szrj warning (0, "target does not support atomic profile update, "
64138fd1498Szrj "single mode is selected");
64238fd1498Szrj flag_profile_update = PROFILE_UPDATE_SINGLE;
64338fd1498Szrj }
64438fd1498Szrj else if (flag_profile_update == PROFILE_UPDATE_PREFER_ATOMIC)
64538fd1498Szrj flag_profile_update = can_support_atomic
64638fd1498Szrj ? PROFILE_UPDATE_ATOMIC : PROFILE_UPDATE_SINGLE;
64738fd1498Szrj
64838fd1498Szrj /* This is a small-ipa pass that gets called only once, from
64938fd1498Szrj cgraphunit.c:ipa_passes(). */
65038fd1498Szrj gcc_assert (symtab->state == IPA_SSA);
65138fd1498Szrj
65238fd1498Szrj init_node_map (true);
65338fd1498Szrj
65438fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
65538fd1498Szrj {
656*58e805e6Szrj bool thunk = false;
657*58e805e6Szrj if (!gimple_has_body_p (node->decl) && !node->thunk.thunk_p)
65838fd1498Szrj continue;
65938fd1498Szrj
66038fd1498Szrj /* Don't profile functions produced for builtin stuff. */
66138fd1498Szrj if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION)
66238fd1498Szrj continue;
66338fd1498Szrj
66438fd1498Szrj if (lookup_attribute ("no_profile_instrument_function",
66538fd1498Szrj DECL_ATTRIBUTES (node->decl)))
66638fd1498Szrj continue;
66738fd1498Szrj /* Do not instrument extern inline functions when testing coverage.
66838fd1498Szrj While this is not perfectly consistent (early inlined extern inlines
66938fd1498Szrj will get acocunted), testsuite expects that. */
67038fd1498Szrj if (DECL_EXTERNAL (node->decl)
67138fd1498Szrj && flag_test_coverage)
67238fd1498Szrj continue;
67338fd1498Szrj
674*58e805e6Szrj if (node->thunk.thunk_p)
675*58e805e6Szrj {
676*58e805e6Szrj /* We can not expand variadic thunks to Gimple. */
677*58e805e6Szrj if (stdarg_p (TREE_TYPE (node->decl)))
678*58e805e6Szrj continue;
679*58e805e6Szrj thunk = true;
680*58e805e6Szrj /* When generate profile, expand thunk to gimple so it can be
681*58e805e6Szrj instrumented same way as other functions. */
682*58e805e6Szrj if (profile_arc_flag)
683*58e805e6Szrj node->expand_thunk (false, true);
684*58e805e6Szrj /* Read cgraph profile but keep function as thunk at profile-use
685*58e805e6Szrj time. */
686*58e805e6Szrj else
687*58e805e6Szrj {
688*58e805e6Szrj read_thunk_profile (node);
689*58e805e6Szrj continue;
690*58e805e6Szrj }
691*58e805e6Szrj }
692*58e805e6Szrj
69338fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (node->decl));
69438fd1498Szrj
69538fd1498Szrj if (dump_file)
69638fd1498Szrj dump_function_header (dump_file, cfun->decl, dump_flags);
69738fd1498Szrj
69838fd1498Szrj /* Local pure-const may imply need to fixup the cfg. */
699*58e805e6Szrj if (gimple_has_body_p (node->decl)
700*58e805e6Szrj && (execute_fixup_cfg () & TODO_cleanup_cfg))
70138fd1498Szrj cleanup_tree_cfg ();
70238fd1498Szrj
703*58e805e6Szrj branch_prob (thunk);
70438fd1498Szrj
70538fd1498Szrj if (! flag_branch_probabilities
70638fd1498Szrj && flag_profile_values)
70738fd1498Szrj gimple_gen_ic_func_profiler ();
70838fd1498Szrj
70938fd1498Szrj if (flag_branch_probabilities
710*58e805e6Szrj && !thunk
71138fd1498Szrj && flag_profile_values
71238fd1498Szrj && flag_value_profile_transformations)
71338fd1498Szrj gimple_value_profile_transformations ();
71438fd1498Szrj
71538fd1498Szrj /* The above could hose dominator info. Currently there is
71638fd1498Szrj none coming in, this is a safety valve. It should be
71738fd1498Szrj easy to adjust it, if and when there is some. */
71838fd1498Szrj free_dominance_info (CDI_DOMINATORS);
71938fd1498Szrj free_dominance_info (CDI_POST_DOMINATORS);
72038fd1498Szrj pop_cfun ();
72138fd1498Szrj }
72238fd1498Szrj
72338fd1498Szrj /* Drop pure/const flags from instrumented functions. */
72438fd1498Szrj if (profile_arc_flag || flag_test_coverage)
72538fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
72638fd1498Szrj {
72738fd1498Szrj if (!gimple_has_body_p (node->decl)
72838fd1498Szrj || !(!node->clone_of
72938fd1498Szrj || node->decl != node->clone_of->decl))
73038fd1498Szrj continue;
73138fd1498Szrj
73238fd1498Szrj /* Don't profile functions produced for builtin stuff. */
73338fd1498Szrj if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION)
73438fd1498Szrj continue;
73538fd1498Szrj
73638fd1498Szrj node->set_const_flag (false, false);
73738fd1498Szrj node->set_pure_flag (false, false);
73838fd1498Szrj }
73938fd1498Szrj
74038fd1498Szrj /* Update call statements and rebuild the cgraph. */
74138fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
74238fd1498Szrj {
74338fd1498Szrj basic_block bb;
74438fd1498Szrj
74538fd1498Szrj if (!gimple_has_body_p (node->decl)
74638fd1498Szrj || !(!node->clone_of
74738fd1498Szrj || node->decl != node->clone_of->decl))
74838fd1498Szrj continue;
74938fd1498Szrj
75038fd1498Szrj /* Don't profile functions produced for builtin stuff. */
75138fd1498Szrj if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION)
75238fd1498Szrj continue;
75338fd1498Szrj
75438fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (node->decl));
75538fd1498Szrj
75638fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
75738fd1498Szrj {
75838fd1498Szrj gimple_stmt_iterator gsi;
75938fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
76038fd1498Szrj {
76138fd1498Szrj gimple *stmt = gsi_stmt (gsi);
76238fd1498Szrj if (is_gimple_call (stmt))
76338fd1498Szrj update_stmt (stmt);
76438fd1498Szrj }
76538fd1498Szrj }
76638fd1498Szrj
76738fd1498Szrj /* re-merge split blocks. */
76838fd1498Szrj cleanup_tree_cfg ();
76938fd1498Szrj update_ssa (TODO_update_ssa);
77038fd1498Szrj
77138fd1498Szrj cgraph_edge::rebuild_edges ();
77238fd1498Szrj
77338fd1498Szrj pop_cfun ();
77438fd1498Szrj }
77538fd1498Szrj
77638fd1498Szrj handle_missing_profiles ();
77738fd1498Szrj
77838fd1498Szrj del_node_map ();
77938fd1498Szrj return 0;
78038fd1498Szrj }
78138fd1498Szrj
78238fd1498Szrj namespace {
78338fd1498Szrj
78438fd1498Szrj const pass_data pass_data_ipa_tree_profile =
78538fd1498Szrj {
78638fd1498Szrj SIMPLE_IPA_PASS, /* type */
78738fd1498Szrj "profile", /* name */
78838fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
78938fd1498Szrj TV_IPA_PROFILE, /* tv_id */
79038fd1498Szrj 0, /* properties_required */
79138fd1498Szrj 0, /* properties_provided */
79238fd1498Szrj 0, /* properties_destroyed */
79338fd1498Szrj 0, /* todo_flags_start */
79438fd1498Szrj TODO_dump_symtab, /* todo_flags_finish */
79538fd1498Szrj };
79638fd1498Szrj
79738fd1498Szrj class pass_ipa_tree_profile : public simple_ipa_opt_pass
79838fd1498Szrj {
79938fd1498Szrj public:
pass_ipa_tree_profile(gcc::context * ctxt)80038fd1498Szrj pass_ipa_tree_profile (gcc::context *ctxt)
80138fd1498Szrj : simple_ipa_opt_pass (pass_data_ipa_tree_profile, ctxt)
80238fd1498Szrj {}
80338fd1498Szrj
80438fd1498Szrj /* opt_pass methods: */
80538fd1498Szrj virtual bool gate (function *);
execute(function *)80638fd1498Szrj virtual unsigned int execute (function *) { return tree_profiling (); }
80738fd1498Szrj
80838fd1498Szrj }; // class pass_ipa_tree_profile
80938fd1498Szrj
81038fd1498Szrj bool
gate(function *)81138fd1498Szrj pass_ipa_tree_profile::gate (function *)
81238fd1498Szrj {
81338fd1498Szrj /* When profile instrumentation, use or test coverage shall be performed.
81438fd1498Szrj But for AutoFDO, this there is no instrumentation, thus this pass is
81538fd1498Szrj diabled. */
81638fd1498Szrj return (!in_lto_p && !flag_auto_profile
81738fd1498Szrj && (flag_branch_probabilities || flag_test_coverage
81838fd1498Szrj || profile_arc_flag));
81938fd1498Szrj }
82038fd1498Szrj
82138fd1498Szrj } // anon namespace
82238fd1498Szrj
82338fd1498Szrj simple_ipa_opt_pass *
make_pass_ipa_tree_profile(gcc::context * ctxt)82438fd1498Szrj make_pass_ipa_tree_profile (gcc::context *ctxt)
82538fd1498Szrj {
82638fd1498Szrj return new pass_ipa_tree_profile (ctxt);
82738fd1498Szrj }
82838fd1498Szrj
82938fd1498Szrj #include "gt-tree-profile.h"
830