xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/tree-profile.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* Calculate branch probabilities, and basic block execution counts.
2*8feb0f0bSmrg    Copyright (C) 1990-2020 Free Software Foundation, Inc.
31debfc3dSmrg    Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
41debfc3dSmrg    based on some ideas from Dain Samples of UC Berkeley.
51debfc3dSmrg    Further mangling by Bob Manson, Cygnus Support.
61debfc3dSmrg    Converted to use trees by Dale Johannesen, Apple Computer.
71debfc3dSmrg 
81debfc3dSmrg This file is part of GCC.
91debfc3dSmrg 
101debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
111debfc3dSmrg the terms of the GNU General Public License as published by the Free
121debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
131debfc3dSmrg version.
141debfc3dSmrg 
151debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
161debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
171debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
181debfc3dSmrg for more details.
191debfc3dSmrg 
201debfc3dSmrg You should have received a copy of the GNU General Public License
211debfc3dSmrg along with GCC; see the file COPYING3.  If not see
221debfc3dSmrg <http://www.gnu.org/licenses/>.  */
231debfc3dSmrg 
241debfc3dSmrg /* Generate basic block profile instrumentation and auxiliary files.
251debfc3dSmrg    Tree-based version.  See profile.c for overview.  */
261debfc3dSmrg 
271debfc3dSmrg #include "config.h"
281debfc3dSmrg #include "system.h"
291debfc3dSmrg #include "coretypes.h"
301debfc3dSmrg #include "memmodel.h"
311debfc3dSmrg #include "backend.h"
321debfc3dSmrg #include "target.h"
331debfc3dSmrg #include "tree.h"
341debfc3dSmrg #include "gimple.h"
351debfc3dSmrg #include "cfghooks.h"
361debfc3dSmrg #include "tree-pass.h"
371debfc3dSmrg #include "ssa.h"
381debfc3dSmrg #include "cgraph.h"
391debfc3dSmrg #include "coverage.h"
401debfc3dSmrg #include "diagnostic-core.h"
411debfc3dSmrg #include "fold-const.h"
421debfc3dSmrg #include "varasm.h"
431debfc3dSmrg #include "tree-nested.h"
441debfc3dSmrg #include "gimplify.h"
451debfc3dSmrg #include "gimple-iterator.h"
461debfc3dSmrg #include "gimplify-me.h"
471debfc3dSmrg #include "tree-cfg.h"
481debfc3dSmrg #include "tree-into-ssa.h"
491debfc3dSmrg #include "value-prof.h"
501debfc3dSmrg #include "profile.h"
511debfc3dSmrg #include "tree-cfgcleanup.h"
52a2dc1f3fSmrg #include "stringpool.h"
53a2dc1f3fSmrg #include "attribs.h"
54a2dc1f3fSmrg #include "tree-pretty-print.h"
55c0a68be4Smrg #include "langhooks.h"
56c0a68be4Smrg #include "stor-layout.h"
57c0a68be4Smrg #include "xregex.h"
581debfc3dSmrg 
591debfc3dSmrg static GTY(()) tree gcov_type_node;
601debfc3dSmrg static GTY(()) tree tree_interval_profiler_fn;
611debfc3dSmrg static GTY(()) tree tree_pow2_profiler_fn;
62*8feb0f0bSmrg static GTY(()) tree tree_topn_values_profiler_fn;
631debfc3dSmrg static GTY(()) tree tree_indirect_call_profiler_fn;
641debfc3dSmrg static GTY(()) tree tree_average_profiler_fn;
651debfc3dSmrg static GTY(()) tree tree_ior_profiler_fn;
661debfc3dSmrg static GTY(()) tree tree_time_profiler_counter;
671debfc3dSmrg 
681debfc3dSmrg 
69c0a68be4Smrg static GTY(()) tree ic_tuple_var;
70c0a68be4Smrg static GTY(()) tree ic_tuple_counters_field;
71c0a68be4Smrg static GTY(()) tree ic_tuple_callee_field;
721debfc3dSmrg 
731debfc3dSmrg /* Do initialization work for the edge profiler.  */
741debfc3dSmrg 
751debfc3dSmrg /* Add code:
76*8feb0f0bSmrg    __thread gcov*	__gcov_indirect_call.counters; // pointer to actual counter
77*8feb0f0bSmrg    __thread void*	__gcov_indirect_call.callee; // actual callee address
781debfc3dSmrg    __thread int __gcov_function_counter; // time profiler function counter
791debfc3dSmrg */
801debfc3dSmrg static void
init_ic_make_global_vars(void)811debfc3dSmrg init_ic_make_global_vars (void)
821debfc3dSmrg {
831debfc3dSmrg   tree gcov_type_ptr;
841debfc3dSmrg 
851debfc3dSmrg   gcov_type_ptr = build_pointer_type (get_gcov_type ());
861debfc3dSmrg 
87c0a68be4Smrg   tree tuple_type = lang_hooks.types.make_type (RECORD_TYPE);
88c0a68be4Smrg 
89c0a68be4Smrg   /* callee */
90c0a68be4Smrg   ic_tuple_callee_field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
91c0a68be4Smrg 				      ptr_type_node);
92c0a68be4Smrg 
93c0a68be4Smrg   /* counters */
94c0a68be4Smrg   ic_tuple_counters_field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
95c0a68be4Smrg 					NULL_TREE, gcov_type_ptr);
96c0a68be4Smrg   DECL_CHAIN (ic_tuple_counters_field) = ic_tuple_callee_field;
97c0a68be4Smrg 
98c0a68be4Smrg   finish_builtin_struct (tuple_type, "indirect_call_tuple",
99c0a68be4Smrg 			 ic_tuple_counters_field, NULL_TREE);
100c0a68be4Smrg 
101c0a68be4Smrg   ic_tuple_var
1021debfc3dSmrg     = build_decl (UNKNOWN_LOCATION, VAR_DECL,
103*8feb0f0bSmrg 		  get_identifier ("__gcov_indirect_call"), tuple_type);
104c0a68be4Smrg   TREE_PUBLIC (ic_tuple_var) = 1;
105c0a68be4Smrg   DECL_ARTIFICIAL (ic_tuple_var) = 1;
106c0a68be4Smrg   DECL_INITIAL (ic_tuple_var) = NULL;
107c0a68be4Smrg   DECL_EXTERNAL (ic_tuple_var) = 1;
1081debfc3dSmrg   if (targetm.have_tls)
109c0a68be4Smrg     set_decl_tls_model (ic_tuple_var, decl_default_tls_model (ic_tuple_var));
1101debfc3dSmrg }
1111debfc3dSmrg 
1121debfc3dSmrg /* Create the type and function decls for the interface with gcov.  */
1131debfc3dSmrg 
1141debfc3dSmrg void
gimple_init_gcov_profiler(void)1151debfc3dSmrg gimple_init_gcov_profiler (void)
1161debfc3dSmrg {
1171debfc3dSmrg   tree interval_profiler_fn_type;
1181debfc3dSmrg   tree pow2_profiler_fn_type;
119*8feb0f0bSmrg   tree topn_values_profiler_fn_type;
1201debfc3dSmrg   tree gcov_type_ptr;
1211debfc3dSmrg   tree ic_profiler_fn_type;
1221debfc3dSmrg   tree average_profiler_fn_type;
1231debfc3dSmrg   const char *fn_name;
1241debfc3dSmrg 
1251debfc3dSmrg   if (!gcov_type_node)
1261debfc3dSmrg     {
1271debfc3dSmrg       const char *fn_suffix
1281debfc3dSmrg 	= flag_profile_update == PROFILE_UPDATE_ATOMIC ? "_atomic" : "";
1291debfc3dSmrg 
1301debfc3dSmrg       gcov_type_node = get_gcov_type ();
1311debfc3dSmrg       gcov_type_ptr = build_pointer_type (gcov_type_node);
1321debfc3dSmrg 
1331debfc3dSmrg       /* void (*) (gcov_type *, gcov_type, int, unsigned)  */
1341debfc3dSmrg       interval_profiler_fn_type
1351debfc3dSmrg 	      = build_function_type_list (void_type_node,
1361debfc3dSmrg 					  gcov_type_ptr, gcov_type_node,
1371debfc3dSmrg 					  integer_type_node,
1381debfc3dSmrg 					  unsigned_type_node, NULL_TREE);
1391debfc3dSmrg       fn_name = concat ("__gcov_interval_profiler", fn_suffix, NULL);
1401debfc3dSmrg       tree_interval_profiler_fn = build_fn_decl (fn_name,
1411debfc3dSmrg 						 interval_profiler_fn_type);
1421debfc3dSmrg       free (CONST_CAST (char *, fn_name));
1431debfc3dSmrg       TREE_NOTHROW (tree_interval_profiler_fn) = 1;
1441debfc3dSmrg       DECL_ATTRIBUTES (tree_interval_profiler_fn)
1451debfc3dSmrg 	= tree_cons (get_identifier ("leaf"), NULL,
1461debfc3dSmrg 		     DECL_ATTRIBUTES (tree_interval_profiler_fn));
1471debfc3dSmrg 
1481debfc3dSmrg       /* void (*) (gcov_type *, gcov_type)  */
1491debfc3dSmrg       pow2_profiler_fn_type
1501debfc3dSmrg 	      = build_function_type_list (void_type_node,
1511debfc3dSmrg 					  gcov_type_ptr, gcov_type_node,
1521debfc3dSmrg 					  NULL_TREE);
1531debfc3dSmrg       fn_name = concat ("__gcov_pow2_profiler", fn_suffix, NULL);
1541debfc3dSmrg       tree_pow2_profiler_fn = build_fn_decl (fn_name, pow2_profiler_fn_type);
1551debfc3dSmrg       free (CONST_CAST (char *, fn_name));
1561debfc3dSmrg       TREE_NOTHROW (tree_pow2_profiler_fn) = 1;
1571debfc3dSmrg       DECL_ATTRIBUTES (tree_pow2_profiler_fn)
1581debfc3dSmrg 	= tree_cons (get_identifier ("leaf"), NULL,
1591debfc3dSmrg 		     DECL_ATTRIBUTES (tree_pow2_profiler_fn));
1601debfc3dSmrg 
1611debfc3dSmrg       /* void (*) (gcov_type *, gcov_type)  */
162*8feb0f0bSmrg       topn_values_profiler_fn_type
1631debfc3dSmrg 	      = build_function_type_list (void_type_node,
1641debfc3dSmrg 					  gcov_type_ptr, gcov_type_node,
1651debfc3dSmrg 					  NULL_TREE);
166*8feb0f0bSmrg       fn_name = concat ("__gcov_topn_values_profiler", fn_suffix, NULL);
167*8feb0f0bSmrg       tree_topn_values_profiler_fn
168*8feb0f0bSmrg 	= build_fn_decl (fn_name, topn_values_profiler_fn_type);
1691debfc3dSmrg       free (CONST_CAST (char *, fn_name));
170*8feb0f0bSmrg 
171*8feb0f0bSmrg       TREE_NOTHROW (tree_topn_values_profiler_fn) = 1;
172*8feb0f0bSmrg       DECL_ATTRIBUTES (tree_topn_values_profiler_fn)
1731debfc3dSmrg 	= tree_cons (get_identifier ("leaf"), NULL,
174*8feb0f0bSmrg 		     DECL_ATTRIBUTES (tree_topn_values_profiler_fn));
1751debfc3dSmrg 
1761debfc3dSmrg       init_ic_make_global_vars ();
1771debfc3dSmrg 
1781debfc3dSmrg       /* void (*) (gcov_type, void *)  */
1791debfc3dSmrg       ic_profiler_fn_type
1801debfc3dSmrg 	       = build_function_type_list (void_type_node,
1811debfc3dSmrg 					  gcov_type_node,
182c0a68be4Smrg 					  ptr_type_node,
1831debfc3dSmrg 					  NULL_TREE);
184*8feb0f0bSmrg       fn_name = concat ("__gcov_indirect_call_profiler_v4", fn_suffix, NULL);
1851debfc3dSmrg       tree_indirect_call_profiler_fn
186*8feb0f0bSmrg 	= build_fn_decl (fn_name, ic_profiler_fn_type);
187*8feb0f0bSmrg       free (CONST_CAST (char *, fn_name));
1881debfc3dSmrg 
1891debfc3dSmrg       TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1;
1901debfc3dSmrg       DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)
1911debfc3dSmrg 	= tree_cons (get_identifier ("leaf"), NULL,
1921debfc3dSmrg 		     DECL_ATTRIBUTES (tree_indirect_call_profiler_fn));
1931debfc3dSmrg 
1941debfc3dSmrg       tree_time_profiler_counter
1951debfc3dSmrg 	= build_decl (UNKNOWN_LOCATION, VAR_DECL,
1961debfc3dSmrg 		      get_identifier ("__gcov_time_profiler_counter"),
1971debfc3dSmrg 		      get_gcov_type ());
1981debfc3dSmrg       TREE_PUBLIC (tree_time_profiler_counter) = 1;
1991debfc3dSmrg       DECL_EXTERNAL (tree_time_profiler_counter) = 1;
2001debfc3dSmrg       TREE_STATIC (tree_time_profiler_counter) = 1;
2011debfc3dSmrg       DECL_ARTIFICIAL (tree_time_profiler_counter) = 1;
2021debfc3dSmrg       DECL_INITIAL (tree_time_profiler_counter) = NULL;
2031debfc3dSmrg 
2041debfc3dSmrg       /* void (*) (gcov_type *, gcov_type)  */
2051debfc3dSmrg       average_profiler_fn_type
2061debfc3dSmrg 	      = build_function_type_list (void_type_node,
2071debfc3dSmrg 					  gcov_type_ptr, gcov_type_node, NULL_TREE);
2081debfc3dSmrg       fn_name = concat ("__gcov_average_profiler", fn_suffix, NULL);
2091debfc3dSmrg       tree_average_profiler_fn = build_fn_decl (fn_name,
2101debfc3dSmrg 						average_profiler_fn_type);
2111debfc3dSmrg       free (CONST_CAST (char *, fn_name));
2121debfc3dSmrg       TREE_NOTHROW (tree_average_profiler_fn) = 1;
2131debfc3dSmrg       DECL_ATTRIBUTES (tree_average_profiler_fn)
2141debfc3dSmrg 	= tree_cons (get_identifier ("leaf"), NULL,
2151debfc3dSmrg 		     DECL_ATTRIBUTES (tree_average_profiler_fn));
2161debfc3dSmrg       fn_name = concat ("__gcov_ior_profiler", fn_suffix, NULL);
2171debfc3dSmrg       tree_ior_profiler_fn = build_fn_decl (fn_name, average_profiler_fn_type);
2181debfc3dSmrg       free (CONST_CAST (char *, fn_name));
2191debfc3dSmrg       TREE_NOTHROW (tree_ior_profiler_fn) = 1;
2201debfc3dSmrg       DECL_ATTRIBUTES (tree_ior_profiler_fn)
2211debfc3dSmrg 	= tree_cons (get_identifier ("leaf"), NULL,
2221debfc3dSmrg 		     DECL_ATTRIBUTES (tree_ior_profiler_fn));
2231debfc3dSmrg 
2241debfc3dSmrg       /* LTO streamer needs assembler names.  Because we create these decls
2251debfc3dSmrg          late, we need to initialize them by hand.  */
2261debfc3dSmrg       DECL_ASSEMBLER_NAME (tree_interval_profiler_fn);
2271debfc3dSmrg       DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn);
228*8feb0f0bSmrg       DECL_ASSEMBLER_NAME (tree_topn_values_profiler_fn);
2291debfc3dSmrg       DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn);
2301debfc3dSmrg       DECL_ASSEMBLER_NAME (tree_average_profiler_fn);
2311debfc3dSmrg       DECL_ASSEMBLER_NAME (tree_ior_profiler_fn);
2321debfc3dSmrg     }
2331debfc3dSmrg }
2341debfc3dSmrg 
2351debfc3dSmrg /* Output instructions as GIMPLE trees to increment the edge
2361debfc3dSmrg    execution count, and insert them on E.  We rely on
2371debfc3dSmrg    gsi_insert_on_edge to preserve the order.  */
2381debfc3dSmrg 
2391debfc3dSmrg void
gimple_gen_edge_profiler(int edgeno,edge e)2401debfc3dSmrg gimple_gen_edge_profiler (int edgeno, edge e)
2411debfc3dSmrg {
2421debfc3dSmrg   tree one;
2431debfc3dSmrg 
2441debfc3dSmrg   one = build_int_cst (gcov_type_node, 1);
2451debfc3dSmrg 
2461debfc3dSmrg   if (flag_profile_update == PROFILE_UPDATE_ATOMIC)
2471debfc3dSmrg     {
2481debfc3dSmrg       /* __atomic_fetch_add (&counter, 1, MEMMODEL_RELAXED); */
2491debfc3dSmrg       tree addr = tree_coverage_counter_addr (GCOV_COUNTER_ARCS, edgeno);
2501debfc3dSmrg       tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32
2511debfc3dSmrg 				      ? BUILT_IN_ATOMIC_FETCH_ADD_8:
2521debfc3dSmrg 				      BUILT_IN_ATOMIC_FETCH_ADD_4);
2531debfc3dSmrg       gcall *stmt = gimple_build_call (f, 3, addr, one,
2541debfc3dSmrg 				       build_int_cst (integer_type_node,
2551debfc3dSmrg 						      MEMMODEL_RELAXED));
2561debfc3dSmrg       gsi_insert_on_edge (e, stmt);
2571debfc3dSmrg     }
2581debfc3dSmrg   else
2591debfc3dSmrg     {
2601debfc3dSmrg       tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
2611debfc3dSmrg       tree gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node,
2621debfc3dSmrg 						   NULL, "PROF_edge_counter");
2631debfc3dSmrg       gassign *stmt1 = gimple_build_assign (gcov_type_tmp_var, ref);
2641debfc3dSmrg       gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node,
2651debfc3dSmrg 					      NULL, "PROF_edge_counter");
2661debfc3dSmrg       gassign *stmt2 = gimple_build_assign (gcov_type_tmp_var, PLUS_EXPR,
2671debfc3dSmrg 					    gimple_assign_lhs (stmt1), one);
2681debfc3dSmrg       gassign *stmt3 = gimple_build_assign (unshare_expr (ref),
2691debfc3dSmrg 					    gimple_assign_lhs (stmt2));
2701debfc3dSmrg       gsi_insert_on_edge (e, stmt1);
2711debfc3dSmrg       gsi_insert_on_edge (e, stmt2);
2721debfc3dSmrg       gsi_insert_on_edge (e, stmt3);
2731debfc3dSmrg     }
2741debfc3dSmrg }
2751debfc3dSmrg 
2761debfc3dSmrg /* Emits code to get VALUE to instrument at GSI, and returns the
2771debfc3dSmrg    variable containing the value.  */
2781debfc3dSmrg 
2791debfc3dSmrg static tree
prepare_instrumented_value(gimple_stmt_iterator * gsi,histogram_value value)2801debfc3dSmrg prepare_instrumented_value (gimple_stmt_iterator *gsi, histogram_value value)
2811debfc3dSmrg {
2821debfc3dSmrg   tree val = value->hvalue.value;
2831debfc3dSmrg   if (POINTER_TYPE_P (TREE_TYPE (val)))
2841debfc3dSmrg     val = fold_convert (build_nonstandard_integer_type
2851debfc3dSmrg 			  (TYPE_PRECISION (TREE_TYPE (val)), 1), val);
2861debfc3dSmrg   return force_gimple_operand_gsi (gsi, fold_convert (gcov_type_node, val),
2871debfc3dSmrg 				   true, NULL_TREE, true, GSI_SAME_STMT);
2881debfc3dSmrg }
2891debfc3dSmrg 
2901debfc3dSmrg /* Output instructions as GIMPLE trees to increment the interval histogram
2911debfc3dSmrg    counter.  VALUE is the expression whose value is profiled.  TAG is the
2921debfc3dSmrg    tag of the section for counters, BASE is offset of the counter position.  */
2931debfc3dSmrg 
2941debfc3dSmrg void
gimple_gen_interval_profiler(histogram_value value,unsigned tag)295*8feb0f0bSmrg gimple_gen_interval_profiler (histogram_value value, unsigned tag)
2961debfc3dSmrg {
2971debfc3dSmrg   gimple *stmt = value->hvalue.stmt;
2981debfc3dSmrg   gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
299*8feb0f0bSmrg   tree ref = tree_coverage_counter_ref (tag, 0), ref_ptr;
3001debfc3dSmrg   gcall *call;
3011debfc3dSmrg   tree val;
3021debfc3dSmrg   tree start = build_int_cst_type (integer_type_node,
3031debfc3dSmrg 				   value->hdata.intvl.int_start);
3041debfc3dSmrg   tree steps = build_int_cst_type (unsigned_type_node,
3051debfc3dSmrg 				   value->hdata.intvl.steps);
3061debfc3dSmrg 
3071debfc3dSmrg   ref_ptr = force_gimple_operand_gsi (&gsi,
3081debfc3dSmrg 				      build_addr (ref),
3091debfc3dSmrg 				      true, NULL_TREE, true, GSI_SAME_STMT);
3101debfc3dSmrg   val = prepare_instrumented_value (&gsi, value);
3111debfc3dSmrg   call = gimple_build_call (tree_interval_profiler_fn, 4,
3121debfc3dSmrg 			    ref_ptr, val, start, steps);
3131debfc3dSmrg   gsi_insert_before (&gsi, call, GSI_NEW_STMT);
3141debfc3dSmrg }
3151debfc3dSmrg 
3161debfc3dSmrg /* Output instructions as GIMPLE trees to increment the power of two histogram
3171debfc3dSmrg    counter.  VALUE is the expression whose value is profiled.  TAG is the tag
318*8feb0f0bSmrg    of the section for counters.  */
3191debfc3dSmrg 
3201debfc3dSmrg void
gimple_gen_pow2_profiler(histogram_value value,unsigned tag)321*8feb0f0bSmrg gimple_gen_pow2_profiler (histogram_value value, unsigned tag)
3221debfc3dSmrg {
3231debfc3dSmrg   gimple *stmt = value->hvalue.stmt;
3241debfc3dSmrg   gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
325*8feb0f0bSmrg   tree ref_ptr = tree_coverage_counter_addr (tag, 0);
3261debfc3dSmrg   gcall *call;
3271debfc3dSmrg   tree val;
3281debfc3dSmrg 
3291debfc3dSmrg   ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
3301debfc3dSmrg 				      true, NULL_TREE, true, GSI_SAME_STMT);
3311debfc3dSmrg   val = prepare_instrumented_value (&gsi, value);
3321debfc3dSmrg   call = gimple_build_call (tree_pow2_profiler_fn, 2, ref_ptr, val);
3331debfc3dSmrg   gsi_insert_before (&gsi, call, GSI_NEW_STMT);
3341debfc3dSmrg }
3351debfc3dSmrg 
336*8feb0f0bSmrg /* Output instructions as GIMPLE trees for code to find the most N common
337*8feb0f0bSmrg    values.  VALUE is the expression whose value is profiled.  TAG is the tag
338*8feb0f0bSmrg    of the section for counters.  */
3391debfc3dSmrg 
3401debfc3dSmrg void
gimple_gen_topn_values_profiler(histogram_value value,unsigned tag)341*8feb0f0bSmrg gimple_gen_topn_values_profiler (histogram_value value, unsigned tag)
3421debfc3dSmrg {
3431debfc3dSmrg   gimple *stmt = value->hvalue.stmt;
3441debfc3dSmrg   gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
345*8feb0f0bSmrg   tree ref_ptr = tree_coverage_counter_addr (tag, 0);
3461debfc3dSmrg   gcall *call;
3471debfc3dSmrg   tree val;
3481debfc3dSmrg 
3491debfc3dSmrg   ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
3501debfc3dSmrg 				      true, NULL_TREE, true, GSI_SAME_STMT);
3511debfc3dSmrg   val = prepare_instrumented_value (&gsi, value);
352*8feb0f0bSmrg   call = gimple_build_call (tree_topn_values_profiler_fn, 2, ref_ptr, val);
3531debfc3dSmrg   gsi_insert_before (&gsi, call, GSI_NEW_STMT);
3541debfc3dSmrg }
3551debfc3dSmrg 
3561debfc3dSmrg 
3571debfc3dSmrg /* Output instructions as GIMPLE trees for code to find the most
3581debfc3dSmrg    common called function in indirect call.
3591debfc3dSmrg    VALUE is the call expression whose indirect callee is profiled.
360*8feb0f0bSmrg    TAG is the tag of the section for counters.  */
3611debfc3dSmrg 
3621debfc3dSmrg void
gimple_gen_ic_profiler(histogram_value value,unsigned tag)363*8feb0f0bSmrg gimple_gen_ic_profiler (histogram_value value, unsigned tag)
3641debfc3dSmrg {
3651debfc3dSmrg   tree tmp1;
3661debfc3dSmrg   gassign *stmt1, *stmt2, *stmt3;
3671debfc3dSmrg   gimple *stmt = value->hvalue.stmt;
3681debfc3dSmrg   gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
369*8feb0f0bSmrg   tree ref_ptr = tree_coverage_counter_addr (tag, 0);
3701debfc3dSmrg 
3711debfc3dSmrg   ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
3721debfc3dSmrg 				      true, NULL_TREE, true, GSI_SAME_STMT);
3731debfc3dSmrg 
3741debfc3dSmrg   /* Insert code:
3751debfc3dSmrg 
376c0a68be4Smrg     stmt1: __gcov_indirect_call.counters = get_relevant_counter_ptr ();
3771debfc3dSmrg     stmt2: tmp1 = (void *) (indirect call argument value)
378c0a68be4Smrg     stmt3: __gcov_indirect_call.callee = tmp1;
379a2dc1f3fSmrg 
380a2dc1f3fSmrg     Example:
381a2dc1f3fSmrg       f_1 = foo;
382c0a68be4Smrg       __gcov_indirect_call.counters = &__gcov4.main[0];
383a2dc1f3fSmrg       PROF_9 = f_1;
384*8feb0f0bSmrg       __gcov_indirect_call.callee = PROF_9;
385a2dc1f3fSmrg       _4 = f_1 ();
3861debfc3dSmrg    */
3871debfc3dSmrg 
388c0a68be4Smrg   tree gcov_type_ptr = build_pointer_type (get_gcov_type ());
389c0a68be4Smrg 
390c0a68be4Smrg   tree counter_ref = build3 (COMPONENT_REF, gcov_type_ptr,
391c0a68be4Smrg 			     ic_tuple_var, ic_tuple_counters_field, NULL_TREE);
392c0a68be4Smrg 
393c0a68be4Smrg   stmt1 = gimple_build_assign (counter_ref, ref_ptr);
394c0a68be4Smrg   tmp1 = make_temp_ssa_name (ptr_type_node, NULL, "PROF");
3951debfc3dSmrg   stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value));
396c0a68be4Smrg   tree callee_ref = build3 (COMPONENT_REF, ptr_type_node,
397c0a68be4Smrg 			     ic_tuple_var, ic_tuple_callee_field, NULL_TREE);
398c0a68be4Smrg   stmt3 = gimple_build_assign (callee_ref, tmp1);
3991debfc3dSmrg 
4001debfc3dSmrg   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
4011debfc3dSmrg   gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
4021debfc3dSmrg   gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT);
4031debfc3dSmrg }
4041debfc3dSmrg 
4051debfc3dSmrg 
4061debfc3dSmrg /* Output instructions as GIMPLE trees for code to find the most
4071debfc3dSmrg    common called function in indirect call. Insert instructions at the
4081debfc3dSmrg    beginning of every possible called function.
4091debfc3dSmrg   */
4101debfc3dSmrg 
4111debfc3dSmrg void
gimple_gen_ic_func_profiler(void)4121debfc3dSmrg gimple_gen_ic_func_profiler (void)
4131debfc3dSmrg {
4141debfc3dSmrg   struct cgraph_node * c_node = cgraph_node::get (current_function_decl);
4151debfc3dSmrg   gcall *stmt1;
4161debfc3dSmrg   tree tree_uid, cur_func, void0;
4171debfc3dSmrg 
4181debfc3dSmrg   if (c_node->only_called_directly_p ())
4191debfc3dSmrg     return;
4201debfc3dSmrg 
4211debfc3dSmrg   gimple_init_gcov_profiler ();
4221debfc3dSmrg 
423a2dc1f3fSmrg   basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
424a2dc1f3fSmrg   basic_block cond_bb = split_edge (single_succ_edge (entry));
425a2dc1f3fSmrg   basic_block update_bb = split_edge (single_succ_edge (cond_bb));
426a2dc1f3fSmrg 
427a2dc1f3fSmrg   /* We need to do an extra split in order to not create an input
428a2dc1f3fSmrg      for a possible PHI node.  */
429a2dc1f3fSmrg   split_edge (single_succ_edge (update_bb));
430a2dc1f3fSmrg 
431a2dc1f3fSmrg   edge true_edge = single_succ_edge (cond_bb);
432a2dc1f3fSmrg   true_edge->flags = EDGE_TRUE_VALUE;
433a2dc1f3fSmrg 
434a2dc1f3fSmrg   profile_probability probability;
435a2dc1f3fSmrg   if (DECL_VIRTUAL_P (current_function_decl))
436a2dc1f3fSmrg     probability = profile_probability::very_likely ();
437a2dc1f3fSmrg   else
438a2dc1f3fSmrg     probability = profile_probability::unlikely ();
439a2dc1f3fSmrg 
440a2dc1f3fSmrg   true_edge->probability = probability;
441a2dc1f3fSmrg   edge e = make_edge (cond_bb, single_succ_edge (update_bb)->dest,
442a2dc1f3fSmrg 		      EDGE_FALSE_VALUE);
443a2dc1f3fSmrg   e->probability = true_edge->probability.invert ();
444a2dc1f3fSmrg 
4451debfc3dSmrg   /* Insert code:
4461debfc3dSmrg 
447*8feb0f0bSmrg      if (__gcov_indirect_call.callee != NULL)
448c0a68be4Smrg        __gcov_indirect_call_profiler_v3 (profile_id, &current_function_decl);
449a2dc1f3fSmrg 
450c0a68be4Smrg      The function __gcov_indirect_call_profiler_v3 is responsible for
451*8feb0f0bSmrg      resetting __gcov_indirect_call.callee to NULL.  */
452a2dc1f3fSmrg 
453a2dc1f3fSmrg   gimple_stmt_iterator gsi = gsi_start_bb (cond_bb);
454c0a68be4Smrg   void0 = build_int_cst (ptr_type_node, 0);
455a2dc1f3fSmrg 
456c0a68be4Smrg   tree callee_ref = build3 (COMPONENT_REF, ptr_type_node,
457c0a68be4Smrg 			    ic_tuple_var, ic_tuple_callee_field, NULL_TREE);
458c0a68be4Smrg 
459c0a68be4Smrg   tree ref = force_gimple_operand_gsi (&gsi, callee_ref, true, NULL_TREE,
460a2dc1f3fSmrg 				       true, GSI_SAME_STMT);
461a2dc1f3fSmrg 
462a2dc1f3fSmrg   gcond *cond = gimple_build_cond (NE_EXPR, ref,
463a2dc1f3fSmrg 				   void0, NULL, NULL);
464a2dc1f3fSmrg   gsi_insert_before (&gsi, cond, GSI_NEW_STMT);
465a2dc1f3fSmrg 
466a2dc1f3fSmrg   gsi = gsi_after_labels (update_bb);
4671debfc3dSmrg 
4681debfc3dSmrg   cur_func = force_gimple_operand_gsi (&gsi,
4691debfc3dSmrg 				       build_addr (current_function_decl),
4701debfc3dSmrg 				       true, NULL_TREE,
4711debfc3dSmrg 				       true, GSI_SAME_STMT);
4721debfc3dSmrg   tree_uid = build_int_cst
4731debfc3dSmrg 	      (gcov_type_node,
4741debfc3dSmrg 	       cgraph_node::get (current_function_decl)->profile_id);
4751debfc3dSmrg   stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2,
4761debfc3dSmrg 			     tree_uid, cur_func);
4771debfc3dSmrg   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
4781debfc3dSmrg }
4791debfc3dSmrg 
4801debfc3dSmrg /* Output instructions as GIMPLE tree at the beginning for each function.
4811debfc3dSmrg    TAG is the tag of the section for counters, BASE is offset of the
4821debfc3dSmrg    counter position and GSI is the iterator we place the counter.  */
4831debfc3dSmrg 
4841debfc3dSmrg void
gimple_gen_time_profiler(unsigned tag)485*8feb0f0bSmrg gimple_gen_time_profiler (unsigned tag)
4861debfc3dSmrg {
4871debfc3dSmrg   tree type = get_gcov_type ();
4881debfc3dSmrg   basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
4891debfc3dSmrg   basic_block cond_bb = split_edge (single_succ_edge (entry));
4901debfc3dSmrg   basic_block update_bb = split_edge (single_succ_edge (cond_bb));
491a2dc1f3fSmrg 
492a2dc1f3fSmrg   /* We need to do an extra split in order to not create an input
493a2dc1f3fSmrg      for a possible PHI node.  */
4941debfc3dSmrg   split_edge (single_succ_edge (update_bb));
4951debfc3dSmrg 
4961debfc3dSmrg   edge true_edge = single_succ_edge (cond_bb);
4971debfc3dSmrg   true_edge->flags = EDGE_TRUE_VALUE;
498a2dc1f3fSmrg   true_edge->probability = profile_probability::unlikely ();
4991debfc3dSmrg   edge e
5001debfc3dSmrg     = make_edge (cond_bb, single_succ_edge (update_bb)->dest, EDGE_FALSE_VALUE);
501a2dc1f3fSmrg   e->probability = true_edge->probability.invert ();
5021debfc3dSmrg 
5031debfc3dSmrg   gimple_stmt_iterator gsi = gsi_start_bb (cond_bb);
504*8feb0f0bSmrg   tree original_ref = tree_coverage_counter_ref (tag, 0);
5051debfc3dSmrg   tree ref = force_gimple_operand_gsi (&gsi, original_ref, true, NULL_TREE,
5061debfc3dSmrg 				       true, GSI_SAME_STMT);
5071debfc3dSmrg   tree one = build_int_cst (type, 1);
5081debfc3dSmrg 
5091debfc3dSmrg   /* Emit: if (counters[0] != 0).  */
5101debfc3dSmrg   gcond *cond = gimple_build_cond (EQ_EXPR, ref, build_int_cst (type, 0),
5111debfc3dSmrg 				   NULL, NULL);
5121debfc3dSmrg   gsi_insert_before (&gsi, cond, GSI_NEW_STMT);
5131debfc3dSmrg 
5141debfc3dSmrg   gsi = gsi_start_bb (update_bb);
5151debfc3dSmrg 
5161debfc3dSmrg   /* Emit: counters[0] = ++__gcov_time_profiler_counter.  */
5171debfc3dSmrg   if (flag_profile_update == PROFILE_UPDATE_ATOMIC)
5181debfc3dSmrg     {
5191debfc3dSmrg       tree ptr = make_temp_ssa_name (build_pointer_type (type), NULL,
5201debfc3dSmrg 				     "time_profiler_counter_ptr");
5211debfc3dSmrg       tree addr = build1 (ADDR_EXPR, TREE_TYPE (ptr),
5221debfc3dSmrg 			  tree_time_profiler_counter);
5231debfc3dSmrg       gassign *assign = gimple_build_assign (ptr, NOP_EXPR, addr);
5241debfc3dSmrg       gsi_insert_before (&gsi, assign, GSI_NEW_STMT);
5251debfc3dSmrg       tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32
5261debfc3dSmrg 				      ? BUILT_IN_ATOMIC_ADD_FETCH_8:
5271debfc3dSmrg 				      BUILT_IN_ATOMIC_ADD_FETCH_4);
5281debfc3dSmrg       gcall *stmt = gimple_build_call (f, 3, ptr, one,
5291debfc3dSmrg 				       build_int_cst (integer_type_node,
5301debfc3dSmrg 						      MEMMODEL_RELAXED));
5311debfc3dSmrg       tree result_type = TREE_TYPE (TREE_TYPE (f));
5321debfc3dSmrg       tree tmp = make_temp_ssa_name (result_type, NULL, "time_profile");
5331debfc3dSmrg       gimple_set_lhs (stmt, tmp);
5341debfc3dSmrg       gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
5351debfc3dSmrg       tmp = make_temp_ssa_name (type, NULL, "time_profile");
5361debfc3dSmrg       assign = gimple_build_assign (tmp, NOP_EXPR,
5371debfc3dSmrg 				    gimple_call_lhs (stmt));
5381debfc3dSmrg       gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
5391debfc3dSmrg       assign = gimple_build_assign (original_ref, tmp);
5401debfc3dSmrg       gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
5411debfc3dSmrg     }
5421debfc3dSmrg   else
5431debfc3dSmrg     {
5441debfc3dSmrg       tree tmp = make_temp_ssa_name (type, NULL, "time_profile");
5451debfc3dSmrg       gassign *assign = gimple_build_assign (tmp, tree_time_profiler_counter);
5461debfc3dSmrg       gsi_insert_before (&gsi, assign, GSI_NEW_STMT);
5471debfc3dSmrg 
5481debfc3dSmrg       tmp = make_temp_ssa_name (type, NULL, "time_profile");
5491debfc3dSmrg       assign = gimple_build_assign (tmp, PLUS_EXPR, gimple_assign_lhs (assign),
5501debfc3dSmrg 				    one);
5511debfc3dSmrg       gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
5521debfc3dSmrg       assign = gimple_build_assign (original_ref, tmp);
5531debfc3dSmrg       gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
5541debfc3dSmrg       assign = gimple_build_assign (tree_time_profiler_counter, tmp);
5551debfc3dSmrg       gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
5561debfc3dSmrg     }
5571debfc3dSmrg }
5581debfc3dSmrg 
5591debfc3dSmrg /* Output instructions as GIMPLE trees to increment the average histogram
5601debfc3dSmrg    counter.  VALUE is the expression whose value is profiled.  TAG is the
5611debfc3dSmrg    tag of the section for counters, BASE is offset of the counter position.  */
5621debfc3dSmrg 
5631debfc3dSmrg void
gimple_gen_average_profiler(histogram_value value,unsigned tag)564*8feb0f0bSmrg gimple_gen_average_profiler (histogram_value value, unsigned tag)
5651debfc3dSmrg {
5661debfc3dSmrg   gimple *stmt = value->hvalue.stmt;
5671debfc3dSmrg   gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
568*8feb0f0bSmrg   tree ref_ptr = tree_coverage_counter_addr (tag, 0);
5691debfc3dSmrg   gcall *call;
5701debfc3dSmrg   tree val;
5711debfc3dSmrg 
5721debfc3dSmrg   ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
5731debfc3dSmrg 				      true, NULL_TREE,
5741debfc3dSmrg 				      true, GSI_SAME_STMT);
5751debfc3dSmrg   val = prepare_instrumented_value (&gsi, value);
5761debfc3dSmrg   call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val);
5771debfc3dSmrg   gsi_insert_before (&gsi, call, GSI_NEW_STMT);
5781debfc3dSmrg }
5791debfc3dSmrg 
5801debfc3dSmrg /* Output instructions as GIMPLE trees to increment the ior histogram
5811debfc3dSmrg    counter.  VALUE is the expression whose value is profiled.  TAG is the
5821debfc3dSmrg    tag of the section for counters, BASE is offset of the counter position.  */
5831debfc3dSmrg 
5841debfc3dSmrg void
gimple_gen_ior_profiler(histogram_value value,unsigned tag)585*8feb0f0bSmrg gimple_gen_ior_profiler (histogram_value value, unsigned tag)
5861debfc3dSmrg {
5871debfc3dSmrg   gimple *stmt = value->hvalue.stmt;
5881debfc3dSmrg   gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
589*8feb0f0bSmrg   tree ref_ptr = tree_coverage_counter_addr (tag, 0);
5901debfc3dSmrg   gcall *call;
5911debfc3dSmrg   tree val;
5921debfc3dSmrg 
5931debfc3dSmrg   ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
5941debfc3dSmrg 				      true, NULL_TREE, true, GSI_SAME_STMT);
5951debfc3dSmrg   val = prepare_instrumented_value (&gsi, value);
5961debfc3dSmrg   call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val);
5971debfc3dSmrg   gsi_insert_before (&gsi, call, GSI_NEW_STMT);
5981debfc3dSmrg }
5991debfc3dSmrg 
600c0a68be4Smrg static vec<regex_t> profile_filter_files;
601c0a68be4Smrg static vec<regex_t> profile_exclude_files;
602c0a68be4Smrg 
603c0a68be4Smrg /* Parse list of provided REGEX (separated with semi-collon) and
604c0a68be4Smrg    create expressions (of type regex_t) and save them into V vector.
605c0a68be4Smrg    If there is a regular expression parsing error, error message is
606c0a68be4Smrg    printed for FLAG_NAME.  */
607c0a68be4Smrg 
608c0a68be4Smrg static void
parse_profile_filter(const char * regex,vec<regex_t> * v,const char * flag_name)609c0a68be4Smrg parse_profile_filter (const char *regex, vec<regex_t> *v,
610c0a68be4Smrg 		      const char *flag_name)
611c0a68be4Smrg {
612c0a68be4Smrg   v->create (4);
613c0a68be4Smrg   if (regex != NULL)
614c0a68be4Smrg     {
615c0a68be4Smrg       char *str = xstrdup (regex);
616c0a68be4Smrg       for (char *p = strtok (str, ";"); p != NULL; p = strtok (NULL, ";"))
617c0a68be4Smrg 	{
618c0a68be4Smrg 	  regex_t r;
619c0a68be4Smrg 	  if (regcomp (&r, p, REG_EXTENDED | REG_NOSUB) != 0)
620c0a68be4Smrg 	    {
621c0a68be4Smrg 	      error ("invalid regular expression %qs in %qs",
622c0a68be4Smrg 		     p, flag_name);
623c0a68be4Smrg 	      return;
624c0a68be4Smrg 	    }
625c0a68be4Smrg 
626c0a68be4Smrg 	  v->safe_push (r);
627c0a68be4Smrg 	}
628c0a68be4Smrg     }
629c0a68be4Smrg }
630c0a68be4Smrg 
631c0a68be4Smrg /* Parse values of -fprofile-filter-files and -fprofile-exclude-files
632c0a68be4Smrg    options.  */
633c0a68be4Smrg 
634c0a68be4Smrg static void
parse_profile_file_filtering()635c0a68be4Smrg parse_profile_file_filtering ()
636c0a68be4Smrg {
637c0a68be4Smrg   parse_profile_filter (flag_profile_filter_files, &profile_filter_files,
638c0a68be4Smrg 			"-fprofile-filter-files");
639c0a68be4Smrg   parse_profile_filter (flag_profile_exclude_files, &profile_exclude_files,
640c0a68be4Smrg 			"-fprofile-exclude-files");
641c0a68be4Smrg }
642c0a68be4Smrg 
643c0a68be4Smrg /* Parse vectors of regular expressions.  */
644c0a68be4Smrg 
645c0a68be4Smrg static void
release_profile_file_filtering()646c0a68be4Smrg release_profile_file_filtering ()
647c0a68be4Smrg {
648c0a68be4Smrg   profile_filter_files.release ();
649c0a68be4Smrg   profile_exclude_files.release ();
650c0a68be4Smrg }
651c0a68be4Smrg 
652c0a68be4Smrg /* Return true when FILENAME should be instrumented based on
653c0a68be4Smrg    -fprofile-filter-files and -fprofile-exclude-files options.  */
654c0a68be4Smrg 
655c0a68be4Smrg static bool
include_source_file_for_profile(const char * filename)656c0a68be4Smrg include_source_file_for_profile (const char *filename)
657c0a68be4Smrg {
658c0a68be4Smrg   /* First check whether file is included in flag_profile_exclude_files.  */
659c0a68be4Smrg   for (unsigned i = 0; i < profile_exclude_files.length (); i++)
660c0a68be4Smrg     if (regexec (&profile_exclude_files[i],
661c0a68be4Smrg 		 filename, 0, NULL, 0) == REG_NOERROR)
662c0a68be4Smrg       return false;
663c0a68be4Smrg 
664c0a68be4Smrg   /* For non-empty flag_profile_filter_files include only files matching a
665c0a68be4Smrg      regex in the flag.  */
666c0a68be4Smrg   if (profile_filter_files.is_empty ())
667c0a68be4Smrg     return true;
668c0a68be4Smrg 
669c0a68be4Smrg   for (unsigned i = 0; i < profile_filter_files.length (); i++)
670c0a68be4Smrg     if (regexec (&profile_filter_files[i], filename, 0, NULL, 0) == REG_NOERROR)
671c0a68be4Smrg       return true;
672c0a68be4Smrg 
673c0a68be4Smrg   return false;
674c0a68be4Smrg }
675c0a68be4Smrg 
6761debfc3dSmrg #ifndef HAVE_sync_compare_and_swapsi
6771debfc3dSmrg #define HAVE_sync_compare_and_swapsi 0
6781debfc3dSmrg #endif
6791debfc3dSmrg #ifndef HAVE_atomic_compare_and_swapsi
6801debfc3dSmrg #define HAVE_atomic_compare_and_swapsi 0
6811debfc3dSmrg #endif
6821debfc3dSmrg 
6831debfc3dSmrg #ifndef HAVE_sync_compare_and_swapdi
6841debfc3dSmrg #define HAVE_sync_compare_and_swapdi 0
6851debfc3dSmrg #endif
6861debfc3dSmrg #ifndef HAVE_atomic_compare_and_swapdi
6871debfc3dSmrg #define HAVE_atomic_compare_and_swapdi 0
6881debfc3dSmrg #endif
6891debfc3dSmrg 
6901debfc3dSmrg /* Profile all functions in the callgraph.  */
6911debfc3dSmrg 
6921debfc3dSmrg static unsigned int
tree_profiling(void)6931debfc3dSmrg tree_profiling (void)
6941debfc3dSmrg {
6951debfc3dSmrg   struct cgraph_node *node;
6961debfc3dSmrg 
6971debfc3dSmrg   /* Verify whether we can utilize atomic update operations.  */
6981debfc3dSmrg   bool can_support_atomic = false;
6991debfc3dSmrg   unsigned HOST_WIDE_INT gcov_type_size
7001debfc3dSmrg     = tree_to_uhwi (TYPE_SIZE_UNIT (get_gcov_type ()));
7011debfc3dSmrg   if (gcov_type_size == 4)
7021debfc3dSmrg     can_support_atomic
7031debfc3dSmrg       = HAVE_sync_compare_and_swapsi || HAVE_atomic_compare_and_swapsi;
7041debfc3dSmrg   else if (gcov_type_size == 8)
7051debfc3dSmrg     can_support_atomic
7061debfc3dSmrg       = HAVE_sync_compare_and_swapdi || HAVE_atomic_compare_and_swapdi;
7071debfc3dSmrg 
7081debfc3dSmrg   if (flag_profile_update == PROFILE_UPDATE_ATOMIC
7091debfc3dSmrg       && !can_support_atomic)
7101debfc3dSmrg     {
7111debfc3dSmrg       warning (0, "target does not support atomic profile update, "
7121debfc3dSmrg 	       "single mode is selected");
7131debfc3dSmrg       flag_profile_update = PROFILE_UPDATE_SINGLE;
7141debfc3dSmrg     }
7151debfc3dSmrg   else if (flag_profile_update == PROFILE_UPDATE_PREFER_ATOMIC)
7161debfc3dSmrg     flag_profile_update = can_support_atomic
7171debfc3dSmrg       ? PROFILE_UPDATE_ATOMIC : PROFILE_UPDATE_SINGLE;
7181debfc3dSmrg 
7191debfc3dSmrg   /* This is a small-ipa pass that gets called only once, from
7201debfc3dSmrg      cgraphunit.c:ipa_passes().  */
7211debfc3dSmrg   gcc_assert (symtab->state == IPA_SSA);
7221debfc3dSmrg 
7231debfc3dSmrg   init_node_map (true);
724c0a68be4Smrg   parse_profile_file_filtering ();
7251debfc3dSmrg 
7261debfc3dSmrg   FOR_EACH_DEFINED_FUNCTION (node)
7271debfc3dSmrg     {
728a2dc1f3fSmrg       bool thunk = false;
729a2dc1f3fSmrg       if (!gimple_has_body_p (node->decl) && !node->thunk.thunk_p)
7301debfc3dSmrg 	continue;
7311debfc3dSmrg 
7321debfc3dSmrg       /* Don't profile functions produced for builtin stuff.  */
7331debfc3dSmrg       if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION)
7341debfc3dSmrg 	continue;
7351debfc3dSmrg 
7361debfc3dSmrg       if (lookup_attribute ("no_profile_instrument_function",
7371debfc3dSmrg 			    DECL_ATTRIBUTES (node->decl)))
7381debfc3dSmrg 	continue;
7391debfc3dSmrg       /* Do not instrument extern inline functions when testing coverage.
7401debfc3dSmrg 	 While this is not perfectly consistent (early inlined extern inlines
7411debfc3dSmrg 	 will get acocunted), testsuite expects that.  */
7421debfc3dSmrg       if (DECL_EXTERNAL (node->decl)
7431debfc3dSmrg 	  && flag_test_coverage)
7441debfc3dSmrg 	continue;
7451debfc3dSmrg 
746c0a68be4Smrg       const char *file = LOCATION_FILE (DECL_SOURCE_LOCATION (node->decl));
747c0a68be4Smrg       if (!include_source_file_for_profile (file))
748c0a68be4Smrg 	continue;
749c0a68be4Smrg 
750a2dc1f3fSmrg       if (node->thunk.thunk_p)
751a2dc1f3fSmrg 	{
752a2dc1f3fSmrg 	  /* We cannot expand variadic thunks to Gimple.  */
753a2dc1f3fSmrg 	  if (stdarg_p (TREE_TYPE (node->decl)))
754a2dc1f3fSmrg 	    continue;
755a2dc1f3fSmrg 	  thunk = true;
756a2dc1f3fSmrg 	  /* When generate profile, expand thunk to gimple so it can be
757a2dc1f3fSmrg 	     instrumented same way as other functions.  */
758a2dc1f3fSmrg 	  if (profile_arc_flag)
759a2dc1f3fSmrg 	    node->expand_thunk (false, true);
760a2dc1f3fSmrg 	  /* Read cgraph profile but keep function as thunk at profile-use
761a2dc1f3fSmrg 	     time.  */
762a2dc1f3fSmrg 	  else
763a2dc1f3fSmrg 	    {
764a2dc1f3fSmrg 	      read_thunk_profile (node);
765a2dc1f3fSmrg 	      continue;
766a2dc1f3fSmrg 	    }
767a2dc1f3fSmrg 	}
768a2dc1f3fSmrg 
7691debfc3dSmrg       push_cfun (DECL_STRUCT_FUNCTION (node->decl));
7701debfc3dSmrg 
771a2dc1f3fSmrg       if (dump_file)
772a2dc1f3fSmrg 	dump_function_header (dump_file, cfun->decl, dump_flags);
773a2dc1f3fSmrg 
7741debfc3dSmrg       /* Local pure-const may imply need to fixup the cfg.  */
775a2dc1f3fSmrg       if (gimple_has_body_p (node->decl)
776a2dc1f3fSmrg 	  && (execute_fixup_cfg () & TODO_cleanup_cfg))
7771debfc3dSmrg 	cleanup_tree_cfg ();
7781debfc3dSmrg 
779a2dc1f3fSmrg       branch_prob (thunk);
7801debfc3dSmrg 
7811debfc3dSmrg       if (! flag_branch_probabilities
7821debfc3dSmrg 	  && flag_profile_values)
7831debfc3dSmrg 	gimple_gen_ic_func_profiler ();
7841debfc3dSmrg 
7851debfc3dSmrg       if (flag_branch_probabilities
786a2dc1f3fSmrg 	  && !thunk
7871debfc3dSmrg 	  && flag_profile_values
788*8feb0f0bSmrg 	  && flag_value_profile_transformations
789*8feb0f0bSmrg 	  && profile_status_for_fn (cfun) == PROFILE_READ)
7901debfc3dSmrg 	gimple_value_profile_transformations ();
7911debfc3dSmrg 
7921debfc3dSmrg       /* The above could hose dominator info.  Currently there is
7931debfc3dSmrg 	 none coming in, this is a safety valve.  It should be
7941debfc3dSmrg 	 easy to adjust it, if and when there is some.  */
7951debfc3dSmrg       free_dominance_info (CDI_DOMINATORS);
7961debfc3dSmrg       free_dominance_info (CDI_POST_DOMINATORS);
7971debfc3dSmrg       pop_cfun ();
7981debfc3dSmrg     }
7991debfc3dSmrg 
800c0a68be4Smrg   release_profile_file_filtering ();
801c0a68be4Smrg 
8021debfc3dSmrg   /* Drop pure/const flags from instrumented functions.  */
8031debfc3dSmrg   if (profile_arc_flag || flag_test_coverage)
8041debfc3dSmrg     FOR_EACH_DEFINED_FUNCTION (node)
8051debfc3dSmrg       {
8061debfc3dSmrg 	if (!gimple_has_body_p (node->decl)
8071debfc3dSmrg 	    || !(!node->clone_of
8081debfc3dSmrg 	    || node->decl != node->clone_of->decl))
8091debfc3dSmrg 	  continue;
8101debfc3dSmrg 
8111debfc3dSmrg 	/* Don't profile functions produced for builtin stuff.  */
8121debfc3dSmrg 	if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION)
8131debfc3dSmrg 	  continue;
8141debfc3dSmrg 
8151debfc3dSmrg 	node->set_const_flag (false, false);
8161debfc3dSmrg 	node->set_pure_flag (false, false);
8171debfc3dSmrg       }
8181debfc3dSmrg 
8191debfc3dSmrg   /* Update call statements and rebuild the cgraph.  */
8201debfc3dSmrg   FOR_EACH_DEFINED_FUNCTION (node)
8211debfc3dSmrg     {
8221debfc3dSmrg       basic_block bb;
8231debfc3dSmrg 
8241debfc3dSmrg       if (!gimple_has_body_p (node->decl)
8251debfc3dSmrg 	  || !(!node->clone_of
8261debfc3dSmrg 	  || node->decl != node->clone_of->decl))
8271debfc3dSmrg 	continue;
8281debfc3dSmrg 
8291debfc3dSmrg       /* Don't profile functions produced for builtin stuff.  */
8301debfc3dSmrg       if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION)
8311debfc3dSmrg 	continue;
8321debfc3dSmrg 
8331debfc3dSmrg       push_cfun (DECL_STRUCT_FUNCTION (node->decl));
8341debfc3dSmrg 
8351debfc3dSmrg       FOR_EACH_BB_FN (bb, cfun)
8361debfc3dSmrg 	{
8371debfc3dSmrg 	  gimple_stmt_iterator gsi;
8381debfc3dSmrg 	  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
8391debfc3dSmrg 	    {
8401debfc3dSmrg 	      gimple *stmt = gsi_stmt (gsi);
8411debfc3dSmrg 	      if (is_gimple_call (stmt))
8421debfc3dSmrg 		update_stmt (stmt);
8431debfc3dSmrg 	    }
8441debfc3dSmrg 	}
8451debfc3dSmrg 
8461debfc3dSmrg       /* re-merge split blocks.  */
8471debfc3dSmrg       cleanup_tree_cfg ();
8481debfc3dSmrg       update_ssa (TODO_update_ssa);
8491debfc3dSmrg 
8501debfc3dSmrg       cgraph_edge::rebuild_edges ();
8511debfc3dSmrg 
8521debfc3dSmrg       pop_cfun ();
8531debfc3dSmrg     }
8541debfc3dSmrg 
8551debfc3dSmrg   handle_missing_profiles ();
8561debfc3dSmrg 
8571debfc3dSmrg   del_node_map ();
8581debfc3dSmrg   return 0;
8591debfc3dSmrg }
8601debfc3dSmrg 
8611debfc3dSmrg namespace {
8621debfc3dSmrg 
8631debfc3dSmrg const pass_data pass_data_ipa_tree_profile =
8641debfc3dSmrg {
8651debfc3dSmrg   SIMPLE_IPA_PASS, /* type */
8661debfc3dSmrg   "profile", /* name */
8671debfc3dSmrg   OPTGROUP_NONE, /* optinfo_flags */
8681debfc3dSmrg   TV_IPA_PROFILE, /* tv_id */
8691debfc3dSmrg   0, /* properties_required */
8701debfc3dSmrg   0, /* properties_provided */
8711debfc3dSmrg   0, /* properties_destroyed */
8721debfc3dSmrg   0, /* todo_flags_start */
8731debfc3dSmrg   TODO_dump_symtab, /* todo_flags_finish */
8741debfc3dSmrg };
8751debfc3dSmrg 
8761debfc3dSmrg class pass_ipa_tree_profile : public simple_ipa_opt_pass
8771debfc3dSmrg {
8781debfc3dSmrg public:
pass_ipa_tree_profile(gcc::context * ctxt)8791debfc3dSmrg   pass_ipa_tree_profile (gcc::context *ctxt)
8801debfc3dSmrg     : simple_ipa_opt_pass (pass_data_ipa_tree_profile, ctxt)
8811debfc3dSmrg   {}
8821debfc3dSmrg 
8831debfc3dSmrg   /* opt_pass methods: */
8841debfc3dSmrg   virtual bool gate (function *);
execute(function *)8851debfc3dSmrg   virtual unsigned int execute (function *) { return tree_profiling (); }
8861debfc3dSmrg 
8871debfc3dSmrg }; // class pass_ipa_tree_profile
8881debfc3dSmrg 
8891debfc3dSmrg bool
gate(function *)8901debfc3dSmrg pass_ipa_tree_profile::gate (function *)
8911debfc3dSmrg {
8921debfc3dSmrg   /* When profile instrumentation, use or test coverage shall be performed.
8931debfc3dSmrg      But for AutoFDO, this there is no instrumentation, thus this pass is
894*8feb0f0bSmrg      disabled.  */
8951debfc3dSmrg   return (!in_lto_p && !flag_auto_profile
8961debfc3dSmrg 	  && (flag_branch_probabilities || flag_test_coverage
8971debfc3dSmrg 	      || profile_arc_flag));
8981debfc3dSmrg }
8991debfc3dSmrg 
9001debfc3dSmrg } // anon namespace
9011debfc3dSmrg 
9021debfc3dSmrg simple_ipa_opt_pass *
make_pass_ipa_tree_profile(gcc::context * ctxt)9031debfc3dSmrg make_pass_ipa_tree_profile (gcc::context *ctxt)
9041debfc3dSmrg {
9051debfc3dSmrg   return new pass_ipa_tree_profile (ctxt);
9061debfc3dSmrg }
9071debfc3dSmrg 
9081debfc3dSmrg #include "gt-tree-profile.h"
909