xref: /dflybsd-src/contrib/gcc-8.0/gcc/tree-profile.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
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, &current_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