diff options
author | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
commit | 73127104a245052cd5cf29cdaaca3e5c32c70348 (patch) | |
tree | 8e28b63e478c43c252f18b49836dff7313affe54 /0309-CSPGO-Add-context-sensitive-PGO.patch | |
parent | 49d3feaf4665cdb07576fc1a2382a4d82a612d35 (diff) |
automatic import of gccopeneuler24.03_LTS_SP1
Diffstat (limited to '0309-CSPGO-Add-context-sensitive-PGO.patch')
-rw-r--r-- | 0309-CSPGO-Add-context-sensitive-PGO.patch | 1337 |
1 files changed, 1337 insertions, 0 deletions
diff --git a/0309-CSPGO-Add-context-sensitive-PGO.patch b/0309-CSPGO-Add-context-sensitive-PGO.patch new file mode 100644 index 0000000..04174af --- /dev/null +++ b/0309-CSPGO-Add-context-sensitive-PGO.patch @@ -0,0 +1,1337 @@ +From 45a424e51c4c5de46062f2d7f355da8a99604d71 Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Tue, 19 Nov 2024 22:06:48 +0800 +Subject: [PATCH] [CSPGO] Add context sensitive PGO + +Same as LLVM, GCC PGO profile counts are not context sensitive. Therefore, +CSPGO is added to collect the profile again after PGO to obtain accurate +execution information after inline for better performance. +--- + gcc/auto-profile.cc | 2 +- + gcc/cgraph.cc | 47 ++++++++++ + gcc/cgraph.h | 8 +- + gcc/cgraphunit.cc | 63 ++++++++++++- + gcc/common.opt | 20 ++++ + gcc/coverage.cc | 162 +++++++++++++++++++++++--------- + gcc/coverage.h | 5 +- + gcc/gcc.cc | 5 +- + gcc/ipa-profile.cc | 4 +- + gcc/lto-cgraph.cc | 7 ++ + gcc/opts.cc | 18 ++++ + gcc/passes.cc | 71 ++++++++++++++ + gcc/passes.def | 1 + + gcc/profile.cc | 27 +++--- + gcc/profile.h | 2 +- + gcc/timevar.def | 1 + + gcc/tree-pass.h | 2 + + gcc/tree-profile.cc | 223 +++++++++++++++++++++++++++++++++++++++++++- + gcc/value-prof.cc | 9 +- + gcc/value-prof.h | 4 +- + 20 files changed, 611 insertions(+), 70 deletions(-) + +diff --git a/gcc/auto-profile.cc b/gcc/auto-profile.cc +index f45f0ec66..5e85381ce 100644 +--- a/gcc/auto-profile.cc ++++ b/gcc/auto-profile.cc +@@ -1775,7 +1775,7 @@ auto_profile (void) + if (symtab->state == FINISHED) + return 0; + +- init_node_map (true); ++ init_node_map (true, false); + profile_info = autofdo::afdo_profile_info; + + FOR_EACH_FUNCTION (node) +diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc +index 7d738b891..95619aefa 100644 +--- a/gcc/cgraph.cc ++++ b/gcc/cgraph.cc +@@ -4076,6 +4076,53 @@ cgraph_node::get_body (void) + return updated; + } + ++/* Prepare function body. When doing LTO, read cgraph_node's body from disk ++ if it is not already present. When some IPA transformations are scheduled, ++ apply them. ++ Flag is used to control only skipping or enabling cspgo. */ ++ ++bool ++cgraph_node::ipa_transform_for_cspgo (bool is_cspgo) ++{ ++ bool updated; ++ ++ bitmap_obstack_initialize (NULL); ++ updated = get_untransformed_body (); ++ ++ /* Getting transformed body makes no sense for inline clones; ++ we should never use this on real clones because they are materialized ++ early. ++ TODO: Materializing clones here will likely lead to smaller LTRANS ++ footprint. */ ++ gcc_assert (!inlined_to && !clone_of); ++ if (ipa_transforms_to_apply.exists ()) ++ { ++ opt_pass *saved_current_pass = current_pass; ++ FILE *saved_dump_file = dump_file; ++ const char *saved_dump_file_name = dump_file_name; ++ dump_flags_t saved_dump_flags = dump_flags; ++ dump_file_name = NULL; ++ set_dump_file (NULL); ++ ++ push_cfun (DECL_STRUCT_FUNCTION (decl)); ++ ++ update_ssa (TODO_update_ssa_only_virtuals); ++ execute_all_ipa_transforms_for_cspgo (is_cspgo); ++ cgraph_edge::rebuild_edges (); ++ free_dominance_info (CDI_DOMINATORS); ++ free_dominance_info (CDI_POST_DOMINATORS); ++ pop_cfun (); ++ updated = true; ++ ++ current_pass = saved_current_pass; ++ set_dump_file (saved_dump_file); ++ dump_file_name = saved_dump_file_name; ++ dump_flags = saved_dump_flags; ++ } ++ bitmap_obstack_release (NULL); ++ return updated; ++} ++ + /* Return the DECL_STRUCT_FUNCTION of the function. */ + + struct function * +diff --git a/gcc/cgraph.h b/gcc/cgraph.h +index 2332539e5..3fdf36769 100644 +--- a/gcc/cgraph.h ++++ b/gcc/cgraph.h +@@ -1097,11 +1097,17 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node + present. */ + bool get_untransformed_body (); + +- /* Prepare function body. When doing LTO, read cgraph_node's body from disk ++ /* Prepare function body. When doing LTO, read cgraph_node's body from disk + if it is not already present. When some IPA transformations are scheduled, + apply them. */ + bool get_body (); + ++ /* Prepare function body. When doing LTO, read cgraph_node's body from disk ++ if it is not already present. When some IPA transformations are scheduled, ++ apply them. ++ Flag is used to control only skipping or enabling cspgo. */ ++ bool ipa_transform_for_cspgo (bool); ++ + void materialize_clone (void); + + /* Release memory used to represent body of function. +diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc +index 5aa7b57c9..37cc83eab 100644 +--- a/gcc/cgraphunit.cc ++++ b/gcc/cgraphunit.cc +@@ -208,6 +208,7 @@ along with GCC; see the file COPYING3. If not see + #include "ipa-inline.h" + #include "omp-offload.h" + #include "symtab-thunks.h" ++#include "profile.h" // for del_node_map + + /* Queue of cgraph nodes scheduled to be added into cgraph. This is a + secondary queue used during optimization to accommodate passes that +@@ -1928,6 +1929,29 @@ tp_first_run_node_cmp (const void *pa, const void *pb) + return tp_first_run_a - tp_first_run_b; + } + ++static bool ++expand_node_with_cspgo (cgraph_node *node, bool is_cspgo) ++{ ++ gcc_assert (node); ++ /* Nodes in other partition, inline to, and clone of are not ++ interesting in cspgo. */ ++ if (!node->has_gimple_body_p () ++ || node->in_other_partition ++ || node->inlined_to ++ || node->clone_of) ++ { ++ if (dump_file) ++ fprintf (dump_file, "[cspgo] node %s will not do" ++ " transform\n", node->dump_name ()); ++ return false; ++ } ++ ++ if (node->process) ++ node->ipa_transform_for_cspgo (is_cspgo); ++ return true; ++} ++ ++ + /* Expand all functions that must be output. + + Attempt to topologically sort the nodes so function is output when +@@ -1968,6 +1992,39 @@ expand_all_functions (void) + /* First output functions with time profile in specified order. */ + qsort (tp_first_run_order, tp_first_run_order_pos, + sizeof (cgraph_node *), tp_first_run_node_cmp); ++ ++ if (flag_csprofile_generate || flag_csprofile_use) ++ { ++ bool is_cspgo = false; ++ ++ /* We need to execute loop twice. The first performs all transforms ++ except cspgo, and the second performs cspgo transform. */ ++ for (int idx = 0; idx < 2; idx++) ++ { ++ for (i = 0; i < tp_first_run_order_pos; i++) ++ { ++ node = tp_first_run_order[i]; ++ if (!expand_node_with_cspgo (node, is_cspgo)) ++ continue; ++ } ++ ++ for (i = new_order_pos - 1; i >= 0; i--) ++ { ++ node = order[i]; ++ if (!expand_node_with_cspgo (node, is_cspgo)) ++ continue; ++ } ++ ++ is_cspgo = true; ++ } ++ ++ if (flag_csprofile_use) ++ handle_missing_profiles (); ++ ++ if (coverage_node_map_initialized_p ()) ++ del_node_map (); ++ } ++ + for (i = 0; i < tp_first_run_order_pos; i++) + { + node = tp_first_run_order[i]; +@@ -2009,6 +2066,10 @@ expand_all_functions (void) + fprintf (symtab->dump_file, "Expanded functions with time profile:%u/%u\n", + profiled_func_count, expanded_func_count); + ++ /* Generate coverage variables and constructor for cspgo. */ ++ if (flag_csprofile_generate) ++ coverage_finish (true); ++ + symtab->process_new_functions (); + free_gimplify_stack (); + delete ipa_saved_clone_sources; +@@ -2176,7 +2237,7 @@ ipa_passes (void) + if (!in_lto_p) + { + /* Generate coverage variables and constructors. */ +- coverage_finish (); ++ coverage_finish (false); + + /* Process new functions added. */ + set_cfun (NULL); +diff --git a/gcc/common.opt b/gcc/common.opt +index be5fcc681..fc2920cee 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -2397,6 +2397,10 @@ Common Joined RejectNegative Var(profile_data_prefix) + Set the top-level directory for storing the profile data. + The default is 'pwd'. + ++fcfgo-csprofile-dir= ++Common Joined RejectNegative Var(csprofile_data_prefix) ++Set the top-level directory for storing the cs profile data. ++ + fprofile-note= + Common Joined RejectNegative Var(profile_note_location) + Select the name for storing the profile note file. +@@ -2461,6 +2465,14 @@ fprofile-generate= + Common Joined RejectNegative + Enable common options for generating profile info for profile feedback directed optimizations, and set -fprofile-dir=. + ++fcfgo-csprofile-generate ++Common Var(flag_csprofile_generate) ++Enable common options for generating context sensitive profile info for profile feedback directed optimizations. ++ ++fcfgo-csprofile-generate= ++Common Joined RejectNegative ++Enable common options for generating context sensitive profile info for profile feedback directed optimizations, and set -fcfgo-csprofile-dir=. ++ + fkernel-pgo + Common Var(flag_kernel_pgo) Optimization Init(0) + Disable TLS setting of instrumentation variables to support PGO kernel compilation in -fprofile-generate, as kernel does not support TLS. +@@ -2485,6 +2497,14 @@ fprofile-use= + Common Joined RejectNegative + Enable common options for performing profile feedback directed optimizations, and set -fprofile-dir=. + ++fcfgo-csprofile-use ++Common Var(flag_csprofile_use) ++Enable common options for performing context sensitive profile feedback directed optimizations. ++ ++fcfgo-csprofile-use= ++Common Joined RejectNegative ++Enable common options for performing context sensitive profile feedback directed optimizations, and set -fcfgo-csprofile-dir=. ++ + fprofile-values + Common Var(flag_profile_values) + Insert code to profile values of expressions. +diff --git a/gcc/coverage.cc b/gcc/coverage.cc +index 8ece5db68..1a7fcb5df 100644 +--- a/gcc/coverage.cc ++++ b/gcc/coverage.cc +@@ -86,7 +86,6 @@ struct counts_entry : pointer_hash <counts_entry> + + static GTY(()) struct coverage_data *functions_head = 0; + static struct coverage_data **functions_tail = &functions_head; +-static unsigned no_coverage = 0; + + /* Cumulative counter information for whole program. */ + static unsigned prg_ctr_mask; /* Mask of counter types generated. */ +@@ -114,6 +113,9 @@ static unsigned bbg_file_stamp; + /* Name of the count data (gcda) file. */ + static char *da_file_name; + ++/* Name of the cs count data (gcda) file. */ ++static char *cs_da_file_name; ++ + /* The names of merge functions for counters. */ + #define STR(str) #str + #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) STR(__gcov_merge ## FN_TYPE), +@@ -173,23 +175,28 @@ counts_entry::remove (counts_entry *entry) + /* Hash table of count data. */ + static hash_table<counts_entry> *counts_hash; + ++/* Hash table of cs count data. */ ++static hash_table<counts_entry> *cs_counts_hash; ++ + /* Read in the counts file, if available. */ + + static void +-read_counts_file (void) ++read_counts_file (bool is_cspgo) + { + gcov_unsigned_t fn_ident = 0; + gcov_unsigned_t tag; + int is_error = 0; + unsigned lineno_checksum = 0; + unsigned cfg_checksum = 0; ++ char *gcda_file_name = (is_cspgo ? cs_da_file_name : da_file_name); + +- if (!gcov_open (da_file_name, 1)) ++ if (!gcov_open (gcda_file_name, 1)) + return; + + if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC)) + { +- warning (0, "%qs is not a gcov data file", da_file_name); ++ warning (0, "%qs is not a %s data file", gcda_file_name, ++ (is_cspgo ? "cs gcov" : "gcov")); + gcov_close (); + return; + } +@@ -201,7 +208,7 @@ read_counts_file (void) + GCOV_UNSIGNED2STRING (e, GCOV_VERSION); + + warning (0, "%qs is version %q.*s, expected version %q.*s", +- da_file_name, 4, v, 4, e); ++ gcda_file_name, 4, v, 4, e); + gcov_close (); + return; + } +@@ -213,7 +220,7 @@ read_counts_file (void) + /* Read checksum. */ + gcov_read_unsigned (); + +- counts_hash = new hash_table<counts_entry> (10); ++ (is_cspgo ? cs_counts_hash : counts_hash) = new hash_table<counts_entry> (10); + while ((tag = gcov_read_unsigned ())) + { + gcov_unsigned_t length; +@@ -234,9 +241,18 @@ read_counts_file (void) + } + else if (tag == GCOV_TAG_OBJECT_SUMMARY) + { +- profile_info = XCNEW (gcov_summary); +- profile_info->runs = gcov_read_unsigned (); +- profile_info->sum_max = gcov_read_unsigned (); ++ if (is_cspgo) ++ { ++ /* TODO: runs and sum_max need better handling for cspgo. */ ++ gcov_unsigned_t runs = gcov_read_unsigned (); ++ gcov_unsigned_t sum_max = gcov_read_unsigned (); ++ } ++ else ++ { ++ profile_info = XCNEW (gcov_summary); ++ profile_info->runs = gcov_read_unsigned (); ++ profile_info->sum_max = gcov_read_unsigned (); ++ } + } + else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident) + { +@@ -249,7 +265,9 @@ read_counts_file (void) + elt.ident = fn_ident; + elt.ctr = GCOV_COUNTER_FOR_TAG (tag); + +- slot = counts_hash->find_slot (&elt, INSERT); ++ slot = (is_cspgo ? cs_counts_hash->find_slot (&elt, INSERT) : ++ counts_hash->find_slot (&elt, INSERT)); ++ + entry = *slot; + if (!entry) + { +@@ -264,12 +282,21 @@ read_counts_file (void) + else if (entry->lineno_checksum != lineno_checksum + || entry->cfg_checksum != cfg_checksum) + { +- error ("profile data for function %u is corrupted", fn_ident); ++ error ("%s data for function %u is corrupted", ++ (is_cspgo ? "cs profile" : "profile"), fn_ident); + error ("checksum is (%x,%x) instead of (%x,%x)", + entry->lineno_checksum, entry->cfg_checksum, + lineno_checksum, cfg_checksum); +- delete counts_hash; +- counts_hash = NULL; ++ if (is_cspgo) ++ { ++ delete cs_counts_hash; ++ cs_counts_hash = NULL; ++ } ++ else ++ { ++ delete counts_hash; ++ counts_hash = NULL; ++ } + break; + } + if (read_length > 0) +@@ -282,9 +309,17 @@ read_counts_file (void) + error (is_error < 0 + ? G_("%qs has overflowed") + : G_("%qs is corrupted"), +- da_file_name); +- delete counts_hash; +- counts_hash = NULL; ++ gcda_file_name); ++ if (is_cspgo) ++ { ++ delete cs_counts_hash; ++ cs_counts_hash = NULL; ++ } ++ else ++ { ++ delete counts_hash; ++ counts_hash = NULL; ++ } + break; + } + } +@@ -296,26 +331,30 @@ read_counts_file (void) + + gcov_type * + get_coverage_counts (unsigned counter, unsigned cfg_checksum, +- unsigned lineno_checksum, unsigned int n_counts) ++ unsigned lineno_checksum, unsigned int n_counts, ++ bool is_cspgo) + { + counts_entry *entry, elt; ++ char *gcda_file_name = (is_cspgo ? cs_da_file_name : da_file_name); + + /* No hash table, no counts. */ +- if (!counts_hash) ++ if ((is_cspgo ? (!cs_counts_hash) : (!counts_hash))) + { + static int warned = 0; + + if (!warned++) + { + warning (OPT_Wmissing_profile, +- "%qs profile count data file not found", +- da_file_name); ++ "%qs %s count data file not found", ++ gcda_file_name, (is_cspgo ? "cs profile" : "profile")); + if (dump_enabled_p ()) + { + dump_user_location_t loc + = dump_user_location_t::from_location_t (input_location); + dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, +- "file %s not found, %s\n", da_file_name, ++ "%s file %s not found, %s\n", ++ (is_cspgo ? "cs profile" : "profile"), ++ gcda_file_name, + (flag_guess_branch_prob + ? "execution counts estimated" + : "execution counts assumed to be zero")); +@@ -331,13 +370,14 @@ get_coverage_counts (unsigned counter, unsigned cfg_checksum, + elt.ident = cgraph_node::get (current_function_decl)->profile_id; + } + elt.ctr = counter; +- entry = counts_hash->find (&elt); ++ entry = (is_cspgo ? cs_counts_hash->find (&elt) : counts_hash->find (&elt)); + if (!entry) + { + if (counter == GCOV_COUNTER_ARCS) + warning_at (DECL_SOURCE_LOCATION (current_function_decl), + OPT_Wmissing_profile, +- "profile for function %qD not found in profile data", ++ "%s for function %qD not found in profile data", ++ (is_cspgo ? "cs profile" : "profile"), + current_function_decl); + /* The function was not emitted, or is weak and not chosen in the + final executable. Silently fail, because there's nothing we +@@ -357,9 +397,10 @@ get_coverage_counts (unsigned counter, unsigned cfg_checksum, + warning_printed = + warning_at (DECL_SOURCE_LOCATION (current_function_decl), + OPT_Wcoverage_mismatch, +- "number of counters in profile data for function %qD " ++ "number of counters in %s data for function %qD " + "does not match " + "its profile data (counter %qs, expected %i and have %i)", ++ (is_cspgo ? "cs profile" : "profile"), + current_function_decl, + ctr_names[counter], entry->n_counts, n_counts); + else +@@ -367,7 +408,8 @@ get_coverage_counts (unsigned counter, unsigned cfg_checksum, + warning_at (DECL_SOURCE_LOCATION (current_function_decl), + OPT_Wcoverage_mismatch, + "the control flow of function %qD does not match " +- "its profile data (counter %qs)", current_function_decl, ++ "its %s data (counter %qs)", current_function_decl, ++ (is_cspgo ? "cs profile" : "profile"), + ctr_names[counter]); + if (warning_printed && dump_enabled_p ()) + { +@@ -413,9 +455,6 @@ get_coverage_counts (unsigned counter, unsigned cfg_checksum, + int + coverage_counter_alloc (unsigned counter, unsigned num) + { +- if (no_coverage) +- return 0; +- + if (!num) + return 1; + +@@ -623,7 +662,7 @@ coverage_begin_function (unsigned lineno_checksum, unsigned cfg_checksum) + { + /* We don't need to output .gcno file unless we're under -ftest-coverage + (e.g. -fprofile-arcs/generate/use don't need .gcno to work). */ +- if (no_coverage || !bbg_file_name) ++ if (!bbg_file_name) + return 0; + + expanded_location startloc +@@ -981,7 +1020,8 @@ build_info_type (tree type, tree fn_info_ptr_type) + function info objects. */ + + static tree +-build_info (tree info_type, tree fn_ary, unsigned object_checksum) ++build_info (tree info_type, tree fn_ary, unsigned object_checksum, ++ bool is_cspgo) + { + tree info_fields = TYPE_FIELDS (info_type); + tree merge_fn_type, n_funcs; +@@ -1014,8 +1054,16 @@ build_info (tree info_type, tree fn_ary, unsigned object_checksum) + info_fields = DECL_CHAIN (info_fields); + + /* Filename */ +- da_file_name_len = strlen (da_file_name); +- filename_string = build_string (da_file_name_len + 1, da_file_name); ++ if (is_cspgo) ++ { ++ da_file_name_len = strlen (cs_da_file_name); ++ filename_string = build_string (da_file_name_len + 1, cs_da_file_name); ++ } ++ else ++ { ++ da_file_name_len = strlen (da_file_name); ++ filename_string = build_string (da_file_name_len + 1, da_file_name); ++ } + TREE_TYPE (filename_string) = build_array_type + (char_type_node, build_index_type (size_int (da_file_name_len))); + CONSTRUCTOR_APPEND_ELT (v1, info_fields, +@@ -1142,7 +1190,7 @@ build_gcov_info_var_registration (tree gcov_info_type) + for the object. Returns TRUE if coverage data is being emitted. */ + + static bool +-coverage_obj_init (void) ++coverage_obj_init (bool is_cspgo) + { + tree gcov_info_type; + unsigned n_counters = 0; +@@ -1151,8 +1199,6 @@ coverage_obj_init (void) + struct coverage_data **fn_prev; + char name_buf[32]; + +- no_coverage = 1; /* Disable any further coverage. */ +- + if (!prg_ctr_mask) + return false; + +@@ -1161,7 +1207,9 @@ coverage_obj_init (void) + + /* Prune functions. */ + for (fn_prev = &functions_head; (fn = *fn_prev);) +- if (DECL_STRUCT_FUNCTION (fn->fn_decl)) ++ /* In cspgo, the DECL_STRUCT_FUNCTION attribute has been checked in ++ csprofile_transform. */ ++ if (is_cspgo || DECL_STRUCT_FUNCTION (fn->fn_decl)) + fn_prev = &fn->next; + else + /* The function is not being emitted, remove from list. */ +@@ -1225,7 +1273,7 @@ coverage_obj_fn (vec<constructor_elt, va_gc> *ctor, tree fn, + + static void + coverage_obj_finish (vec<constructor_elt, va_gc> *ctor, +- unsigned object_checksum) ++ unsigned object_checksum, bool is_cspgo) + { + unsigned n_functions = vec_safe_length (ctor); + tree fn_info_ary_type = build_array_type +@@ -1242,7 +1290,8 @@ coverage_obj_finish (vec<constructor_elt, va_gc> *ctor, + varpool_node::finalize_decl (fn_info_ary); + + DECL_INITIAL (gcov_info_var) +- = build_info (TREE_TYPE (gcov_info_var), fn_info_ary, object_checksum); ++ = build_info (TREE_TYPE (gcov_info_var), fn_info_ary, object_checksum, ++ is_cspgo); + varpool_node::finalize_decl (gcov_info_var); + } + +@@ -1310,11 +1359,32 @@ coverage_init (const char *filename) + memcpy (da_file_name + prefix_len, filename, len); + strcpy (da_file_name + prefix_len + len, GCOV_DATA_SUFFIX); + ++ /* Name of cspgo da file. */ ++ if (flag_csprofile_generate || flag_csprofile_use) ++ { ++ if (csprofile_data_prefix) ++ prefix_len = strlen (csprofile_data_prefix); ++ ++ cs_da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX) ++ + prefix_len + 2); ++ ++ if (csprofile_data_prefix) ++ { ++ memcpy (cs_da_file_name, csprofile_data_prefix, prefix_len); ++ cs_da_file_name[prefix_len++] = *separator; ++ } ++ memcpy (cs_da_file_name + prefix_len, filename, len); ++ strcpy (cs_da_file_name + prefix_len + len, GCOV_DATA_SUFFIX); ++ } ++ + bbg_file_stamp = local_tick; + if (flag_auto_profile) + read_autofdo_file (); + else if (flag_branch_probabilities) +- read_counts_file (); ++ read_counts_file (false); ++ ++ if (flag_csprofile_use) ++ read_counts_file (true); + + /* Name of bbg file. */ + if (flag_test_coverage && !flag_compare_debug) +@@ -1354,7 +1424,7 @@ coverage_init (const char *filename) + variables and constructor. */ + + void +-coverage_finish (void) ++coverage_finish (bool is_cspgo) + { + if (bbg_file_name && gcov_close ()) + unlink (bbg_file_name); +@@ -1368,7 +1438,7 @@ coverage_finish (void) + /* Global GCDA checksum that aggregates all functions. */ + unsigned object_checksum = 0; + +- if (coverage_obj_init ()) ++ if (coverage_obj_init (is_cspgo)) + { + vec<constructor_elt, va_gc> *fn_ctor = NULL; + struct coverage_data *fn; +@@ -1382,11 +1452,17 @@ coverage_finish (void) + fn->lineno_checksum); + object_checksum = crc32_unsigned (object_checksum, fn->cfg_checksum); + } +- coverage_obj_finish (fn_ctor, object_checksum); ++ coverage_obj_finish (fn_ctor, object_checksum, is_cspgo); + } + +- XDELETEVEC (da_file_name); ++ if (da_file_name) ++ XDELETEVEC (da_file_name); + da_file_name = NULL; ++ if (is_cspgo) ++ { ++ XDELETEVEC (cs_da_file_name); ++ cs_da_file_name = NULL; ++ } + } + + #include "gt-coverage.h" +diff --git a/gcc/coverage.h b/gcc/coverage.h +index 0ac046c88..a4e90e8bd 100644 +--- a/gcc/coverage.h ++++ b/gcc/coverage.h +@@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see + #include "gcov-io.h" + + extern void coverage_init (const char *); +-extern void coverage_finish (void); ++extern void coverage_finish (bool); + extern void coverage_remove_note_file (void); + + /* Start outputting coverage information for the current +@@ -53,7 +53,8 @@ extern tree tree_coverage_counter_addr (unsigned /*counter*/, unsigned/*num*/); + extern gcov_type *get_coverage_counts (unsigned /*counter*/, + unsigned /*cfg_checksum*/, + unsigned /*lineno_checksum*/, +- unsigned /*n_counts*/); ++ unsigned /*n_counts*/, ++ bool /*is_cspgo*/); + + extern tree get_gcov_type (void); + extern bool coverage_node_map_initialized_p (void); +diff --git a/gcc/gcc.cc b/gcc/gcc.cc +index 32e45adc2..b37b50be2 100644 +--- a/gcc/gcc.cc ++++ b/gcc/gcc.cc +@@ -1147,7 +1147,8 @@ proper position among the other output files. */ + %:include(libgomp.spec)%(link_gomp)}\ + %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\ + %(mflib) " STACK_SPLIT_SPEC "\ +- %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} " SANITIZER_SPEC " \ ++ %{fprofile-arcs|fprofile-generate*|fcfgo-csprofile-generate*|coverage:-lgcov} \ ++ " SANITIZER_SPEC " \ + %{!nostdlib:%{!r:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}}\ + %{!nostdlib:%{!r:%{!nostartfiles:%E}}} %{T*} \n%(post_link) }}}}}}" + #endif +@@ -1265,7 +1266,7 @@ static const char *cc1_options = + %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}}\ + %{fsyntax-only:-o %j} %{-param*}\ + %{coverage:-fprofile-arcs -ftest-coverage}\ +- %{fprofile-arcs|fprofile-generate*|coverage:\ ++ %{fprofile-arcs|fprofile-generate*|fcfgo-csprofile-generate*|coverage:\ + %{!fprofile-update=single:\ + %{pthread:-fprofile-update=prefer-atomic}}}"; + +diff --git a/gcc/ipa-profile.cc b/gcc/ipa-profile.cc +index ffdcb4476..27554e507 100644 +--- a/gcc/ipa-profile.cc ++++ b/gcc/ipa-profile.cc +@@ -827,7 +827,7 @@ ipa_profile (void) + if (dump_file) + { + if (!node_map_initialized) +- init_node_map (false); ++ init_node_map (false, false); + node_map_initialized = true; + + ipa_profile_dump_all_summaries (dump_file); +@@ -850,7 +850,7 @@ ipa_profile (void) + if (spec_count) + { + if (!node_map_initialized) +- init_node_map (false); ++ init_node_map (false, false); + node_map_initialized = true; + ncommon++; + +diff --git a/gcc/lto-cgraph.cc b/gcc/lto-cgraph.cc +index 237743ef0..fd41941d1 100644 +--- a/gcc/lto-cgraph.cc ++++ b/gcc/lto-cgraph.cc +@@ -1677,6 +1677,13 @@ merge_profile_summaries (struct lto_file_decl_data **file_data_vec) + if (flag_ltrans) + return; + ++ /* TODO: The different max_run values obtained during the cspgo GEN and USE ++ stages with unknown bug resulted in different scaling results, which led ++ different optimization decisions and finally led to coverage mismatch. ++ Therefore, skip the following processing steps when doing cspgo. */ ++ if (flag_csprofile_generate || flag_csprofile_use) ++ return; ++ + /* Now compute count_materialization_scale of each node. + During LTRANS we already have values of count_materialization_scale + computed, so just update them. */ +diff --git a/gcc/opts.cc b/gcc/opts.cc +index d97f6079f..7900a658f 100644 +--- a/gcc/opts.cc ++++ b/gcc/opts.cc +@@ -3016,6 +3016,15 @@ common_handle_option (struct gcc_options *opts, + false); + break; + ++ case OPT_fcfgo_csprofile_use_: ++ opts->x_csprofile_data_prefix = xstrdup (arg); ++ value = true; ++ /* No break here - do -fcfgo-csprofile-use processing. */ ++ /* FALLTHRU */ ++ case OPT_fcfgo_csprofile_use: ++ SET_OPTION_IF_UNSET (opts, opts_set, flag_csprofile_use, value); ++ break; ++ + case OPT_fauto_profile_: + opts->x_auto_profile_file = xstrdup (arg); + opts->x_flag_auto_profile = true; +@@ -3059,6 +3068,15 @@ common_handle_option (struct gcc_options *opts, + SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_bit_cp, value); + break; + ++ case OPT_fcfgo_csprofile_generate_: ++ opts->x_csprofile_data_prefix = xstrdup (arg); ++ value = true; ++ /* No break here - do -fcfgo-csprofile-generate processing. */ ++ /* FALLTHRU */ ++ case OPT_fcfgo_csprofile_generate: ++ SET_OPTION_IF_UNSET (opts, opts_set, flag_csprofile_generate, value); ++ break; ++ + case OPT_fprofile_info_section: + opts->x_profile_info_section = ".gcov_info"; + break; +diff --git a/gcc/passes.cc b/gcc/passes.cc +index 36e5b4ac4..154690d02 100644 +--- a/gcc/passes.cc ++++ b/gcc/passes.cc +@@ -2410,6 +2410,77 @@ execute_all_ipa_transforms (bool do_not_collect) + node->ipa_transforms_to_apply.release (); + } + ++/* When is_cspgo is true, execute all passes except cspgo and save the pointer ++ for the next execution. */ ++ ++void ++execute_all_ipa_transforms_for_cspgo (bool is_cspgo) ++{ ++ struct cgraph_node *node; ++ ipa_opt_pass_d *cspgo_pass = NULL; ++ node = cgraph_node::get (current_function_decl); ++ ++ cgraph_node *next_clone; ++ for (cgraph_node *n = node->clones; n; n = next_clone) ++ { ++ next_clone = n->next_sibling_clone; ++ if (n->decl != node->decl) ++ n->materialize_clone (); ++ } ++ ++ int j = 0; ++ gcc::pass_manager *passes = g->get_passes (); ++ bool report = profile_report && (cfun->curr_properties & PROP_gimple) != 0; ++ ++ if (report) ++ push_cfun (DECL_STRUCT_FUNCTION (node->decl)); ++ ++ for (auto p : node->ipa_transforms_to_apply) ++ { ++ /* Execute all passes except cspgo, and save the pointer of cspgo pass ++ for the next execution. */ ++ if (!is_cspgo && strstr (p->name, "csprofile") != NULL) ++ { ++ cspgo_pass = p; ++ continue; ++ } ++ /* To get consistent statistics, we need to account each functio ++ to each IPA pass. */ ++ if (report) ++ { ++ for (;j < p->static_pass_number; j++) ++ if (passes->get_pass_for_id (j) ++ && passes->get_pass_for_id (j)->type == IPA_PASS ++ && ((ipa_opt_pass_d *)passes->get_pass_for_id (j)) ++ ->function_transform) ++ { ++ check_profile_consistency (j, true); ++ account_profile (j, true); ++ } ++ gcc_checking_assert (passes->get_pass_for_id (j) == p); ++ } ++ execute_one_ipa_transform_pass (node, p, true); ++ } ++ /* Account remaining IPA passes. */ ++ if (report) ++ { ++ for (;!passes->get_pass_for_id (j) ++ || passes->get_pass_for_id (j)->type != RTL_PASS; j++) ++ if (passes->get_pass_for_id (j) ++ && passes->get_pass_for_id (j)->type == IPA_PASS ++ && ((ipa_opt_pass_d *)passes->get_pass_for_id (j)) ++ ->function_transform) ++ { ++ check_profile_consistency (j, true); ++ account_profile (j, true); ++ } ++ pop_cfun (); ++ } ++ node->ipa_transforms_to_apply.release (); ++ if (!is_cspgo) ++ node->ipa_transforms_to_apply.safe_push (cspgo_pass); ++} ++ + /* Check if PASS is explicitly disabled or enabled and return + the gate status. FUNC is the function to be processed, and + GATE_STATUS is the gate status determined by pass manager by +diff --git a/gcc/passes.def b/gcc/passes.def +index e945af96a..862ef0d8f 100644 +--- a/gcc/passes.def ++++ b/gcc/passes.def +@@ -164,6 +164,7 @@ along with GCC; see the file COPYING3. If not see + NEXT_PASS (pass_ipa_cdtor_merge); + NEXT_PASS (pass_ipa_fn_summary); + NEXT_PASS (pass_ipa_inline); ++ NEXT_PASS (pass_ipa_csprofile); + NEXT_PASS (pass_ipa_pure_const); + NEXT_PASS (pass_ipa_modref); + NEXT_PASS (pass_ipa_free_fn_summary, false /* small_p */); +diff --git a/gcc/profile.cc b/gcc/profile.cc +index 40e105258..0ffc1ba4f 100644 +--- a/gcc/profile.cc ++++ b/gcc/profile.cc +@@ -201,7 +201,7 @@ instrument_values (histogram_values values) + CFG_CHECKSUM is the precomputed checksum for the CFG. */ + + static gcov_type * +-get_exec_counts (unsigned cfg_checksum, unsigned lineno_checksum) ++get_exec_counts (unsigned cfg_checksum, unsigned lineno_checksum, bool is_cspgo) + { + unsigned num_edges = 0; + basic_block bb; +@@ -219,7 +219,7 @@ get_exec_counts (unsigned cfg_checksum, unsigned lineno_checksum) + } + + counts = get_coverage_counts (GCOV_COUNTER_ARCS, cfg_checksum, +- lineno_checksum, num_edges); ++ lineno_checksum, num_edges, is_cspgo); + if (!counts) + return NULL; + +@@ -418,7 +418,8 @@ cmp_stats (const void *ptr1, const void *ptr2) + CFG_CHECKSUM is the precomputed checksum for the CFG. */ + + static void +-compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum) ++compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum, ++ bool is_cspgo) + { + basic_block bb; + int i; +@@ -427,7 +428,8 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum) + int passes; + int hist_br_prob[20]; + int num_branches; +- gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum); ++ gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum, ++ is_cspgo); + int inconsistent = 0; + + /* Very simple sanity checks so we catch bugs in our profiling code. */ +@@ -868,7 +870,7 @@ sort_hist_values (histogram_value hist) + + static void + compute_value_histograms (histogram_values values, unsigned cfg_checksum, +- unsigned lineno_checksum) ++ unsigned lineno_checksum, bool is_cspgo) + { + unsigned i, j, t, any; + unsigned n_histogram_counters[GCOV_N_VALUE_COUNTERS]; +@@ -898,7 +900,8 @@ compute_value_histograms (histogram_values values, unsigned cfg_checksum, + histogram_counts[t] = get_coverage_counts (COUNTER_FOR_HIST_TYPE (t), + cfg_checksum, + lineno_checksum, +- n_histogram_counters[t]); ++ n_histogram_counters[t], ++ is_cspgo); + if (histogram_counts[t]) + any = 1; + act_count[t] = histogram_counts[t]; +@@ -1128,11 +1131,12 @@ compare_freqs (const void *p1, const void *p2) + /* Only read execution count for thunks. */ + + void +-read_thunk_profile (struct cgraph_node *node) ++read_thunk_profile (struct cgraph_node *node, bool is_cspgo) + { + tree old = current_function_decl; + current_function_decl = node->decl; +- gcov_type *counts = get_coverage_counts (GCOV_COUNTER_ARCS, 0, 0, 1); ++ gcov_type *counts = get_coverage_counts (GCOV_COUNTER_ARCS, 0, 0, 1, ++ is_cspgo); + if (counts) + { + node->callees->count = node->count +@@ -1164,7 +1168,7 @@ read_thunk_profile (struct cgraph_node *node) + Main entry point of this file. */ + + void +-branch_prob (bool thunk) ++branch_prob (bool thunk, bool is_cspgo) + { + basic_block bb; + unsigned i; +@@ -1507,9 +1511,10 @@ branch_prob (bool thunk) + + if (flag_branch_probabilities) + { +- compute_branch_probabilities (cfg_checksum, lineno_checksum); ++ compute_branch_probabilities (cfg_checksum, lineno_checksum, is_cspgo); + if (flag_profile_values) +- compute_value_histograms (values, cfg_checksum, lineno_checksum); ++ compute_value_histograms (values, cfg_checksum, lineno_checksum, ++ is_cspgo); + } + + remove_fake_edges (); +diff --git a/gcc/profile.h b/gcc/profile.h +index c5b6f4889..e92d6154c 100644 +--- a/gcc/profile.h ++++ b/gcc/profile.h +@@ -68,7 +68,7 @@ extern void mcf_smooth_cfg (void); + + extern gcov_type sum_edge_counts (vec<edge, va_gc> *edges); + +-extern void init_node_map (bool); ++extern void init_node_map (bool, bool); + extern void del_node_map (void); + + extern void get_working_sets (void); +diff --git a/gcc/timevar.def b/gcc/timevar.def +index fc2b1e1e7..6fdb2c767 100644 +--- a/gcc/timevar.def ++++ b/gcc/timevar.def +@@ -104,6 +104,7 @@ DEFTIMEVAR (TV_WHOPR_PARTITIONING , "whopr partitioning") + DEFTIMEVAR (TV_WHOPR_LTRANS , "whopr ltrans") + DEFTIMEVAR (TV_IPA_REFERENCE , "ipa reference") + DEFTIMEVAR (TV_IPA_PROFILE , "ipa profile") ++DEFTIMEVAR (TV_IPA_CSPROFILE , "ipa csprofile") + DEFTIMEVAR (TV_IPA_AUTOFDO , "auto profile") + DEFTIMEVAR (TV_IPA_PURE_CONST , "ipa pure const") + DEFTIMEVAR (TV_IPA_ICF , "ipa icf") +diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h +index 18b0f8022..f9c2eed8b 100644 +--- a/gcc/tree-pass.h ++++ b/gcc/tree-pass.h +@@ -519,6 +519,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_increase_alignment (gcc::context + *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_fn_summary (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_inline (gcc::context *ctxt); ++extern ipa_opt_pass_d *make_pass_ipa_csprofile (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_free_lang_data (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_free_fn_summary (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_cp (gcc::context *ctxt); +@@ -667,6 +668,7 @@ extern void execute_pass_list (function *, opt_pass *); + extern void execute_ipa_pass_list (opt_pass *); + extern void execute_ipa_summary_passes (ipa_opt_pass_d *); + extern void execute_all_ipa_transforms (bool); ++extern void execute_all_ipa_transforms_for_cspgo (bool); + extern void execute_all_ipa_stmt_fixups (struct cgraph_node *, gimple **); + extern bool pass_init_dump_file (opt_pass *); + extern void pass_fini_dump_file (opt_pass *); +diff --git a/gcc/tree-profile.cc b/gcc/tree-profile.cc +index e7646f1a1..aa3a2b3a9 100644 +--- a/gcc/tree-profile.cc ++++ b/gcc/tree-profile.cc +@@ -725,7 +725,7 @@ tree_profiling (void) + cgraphunit.cc:ipa_passes(). */ + gcc_assert (symtab->state == IPA_SSA); + +- init_node_map (true); ++ init_node_map (true, false); + parse_profile_file_filtering (); + + FOR_EACH_DEFINED_FUNCTION (node) +@@ -766,7 +766,7 @@ tree_profiling (void) + time. */ + else + { +- read_thunk_profile (node); ++ read_thunk_profile (node, false); + continue; + } + } +@@ -781,7 +781,7 @@ tree_profiling (void) + && (execute_fixup_cfg () & TODO_cleanup_cfg)) + cleanup_tree_cfg (); + +- branch_prob (thunk); ++ branch_prob (thunk, false); + + if (! flag_branch_probabilities + && flag_profile_values) +@@ -863,6 +863,170 @@ tree_profiling (void) + return 0; + } + ++/* Profile all functions in the callgraph with cs profile. */ ++ ++static unsigned int ++csprofile_transform (struct cgraph_node *node) ++{ ++ basic_block bb; ++ bool thunk = false; ++ ++ parse_profile_file_filtering (); ++ ++ if (dump_file) ++ { ++ fprintf (dump_file, "[cspgo] trying cspgo on function:\n"); ++ dump_function_header (dump_file, cfun->decl, dump_flags); ++ } ++ ++ if (!DECL_STRUCT_FUNCTION (current_function_decl)) ++ { ++ if (dump_file) ++ fprintf (dump_file, "[cspgo] %s without function decl, skip.\n", ++ node->dump_name ()); ++ return 0; ++ } ++ ++ if (!gimple_has_body_p (node->decl) && !node->thunk) ++ { ++ if (dump_file) ++ fprintf (dump_file, "[cspgo] %s without gimple body, skip.\n", ++ node->dump_name ()); ++ return 0; ++ } ++ ++ /* Don't profile functions produced for builtin stuff. */ ++ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) ++ { ++ if (dump_file) ++ fprintf (dump_file, "[cspgo] %s with BUILTINS_LOCATION, skip.\n", ++ node->dump_name ()); ++ return 0; ++ } ++ ++ const char *file = LOCATION_FILE (DECL_SOURCE_LOCATION (node->decl)); ++ if (!file || !include_source_file_for_profile (file)) ++ { ++ if (dump_file) ++ fprintf (dump_file, "[cspgo] %s is sub func or in filter-files, " ++ "skip.\n", node->dump_name ()); ++ return 0; ++ } ++ ++ if (lookup_attribute ("no_profile_instrument_function", ++ DECL_ATTRIBUTES (node->decl))) ++ { ++ if (dump_file) ++ fprintf (dump_file, "[cspgo] %s is no_profile_instrument_function," ++ " skip.\n", node->dump_name ()); ++ return 0; ++ } ++ ++ /* Do not instrument extern inline functions. */ ++ if (DECL_EXTERNAL (node->decl)) ++ { ++ if (dump_file) ++ fprintf (dump_file, "[cspgo] %s is DECL_EXTERNAL, skip.\n", ++ node->dump_name ()); ++ return 0; ++ } ++ ++ if (!coverage_node_map_initialized_p ()) ++ init_node_map (true, true); ++ ++ /* Node without profile id should skip. */ ++ if (!node->profile_id) ++ { ++ if (dump_file) ++ fprintf (dump_file, "[cspgo] %s does not has profile_id, skip.\n", ++ node->dump_name ()); ++ return 0; ++ } ++ ++ if (flag_csprofile_generate) ++ { ++ profile_arc_flag = 1; ++ flag_branch_probabilities = 0; ++ } ++ ++ /* Process thunk function. */ ++ if (node->thunk) ++ { ++ /* We cannot expand variadic thunks to Gimple. */ ++ if (stdarg_p (TREE_TYPE (node->decl))) ++ { ++ if (dump_file) ++ fprintf (dump_file, "[cspgo] %s is DECL_EXTERNAL, skip.\n", ++ node->dump_name ()); ++ return 0; ++ } ++ thunk = true; ++ /* When generate profile, expand thunk to gimple so it can be ++ instrumented same way as other functions. */ ++ if (profile_arc_flag) ++ expand_thunk (node, false, true); ++ /* Read cgraph profile but keep function as thunk at profile-use ++ time. */ ++ else ++ { ++ read_thunk_profile (node, true); ++ return 0; ++ } ++ } ++ ++ /* Local pure-const may imply need to fixup the cfg. */ ++ if (gimple_has_body_p (node->decl) ++ && (execute_fixup_cfg () & TODO_cleanup_cfg)) ++ cleanup_tree_cfg (); ++ ++ branch_prob (thunk, true); ++ ++ if (! flag_branch_probabilities ++ && flag_profile_values) ++ gimple_gen_ic_func_profiler (); ++ ++ if (flag_branch_probabilities ++ && !thunk ++ && flag_profile_values ++ && flag_value_profile_transformations ++ && profile_status_for_fn (cfun) == PROFILE_READ) ++ gimple_value_profile_transformations (); ++ ++ /* The above could hose dominator info. Currently there is ++ none coming in, this is a safety valve. It should be ++ easy to adjust it, if and when there is some. */ ++ free_dominance_info (CDI_DOMINATORS); ++ free_dominance_info (CDI_POST_DOMINATORS); ++ ++ release_profile_file_filtering (); ++ ++ if (flag_csprofile_generate) ++ { ++ profile_arc_flag = 0; ++ flag_branch_probabilities = 1; ++ } ++ ++ /* Update call statements and rebuild the cgraph. */ ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ gimple_stmt_iterator gsi; ++ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gimple *stmt = gsi_stmt (gsi); ++ if (is_gimple_call (stmt)) ++ update_stmt (stmt); ++ } ++ } ++ ++ /* re-merge split blocks. */ ++ cleanup_tree_cfg (); ++ update_ssa (TODO_update_ssa); ++ ++ cgraph_edge::rebuild_edges (); ++ ++ return 0; ++} ++ + namespace { + + const pass_data pass_data_ipa_tree_profile = +@@ -910,4 +1074,57 @@ make_pass_ipa_tree_profile (gcc::context *ctxt) + return new pass_ipa_tree_profile (ctxt); + } + ++namespace { ++ ++const pass_data pass_data_ipa_csprofile = ++{ ++ IPA_PASS, /* type */ ++ "csprofile", /* name */ ++ OPTGROUP_NONE, /* optinfo_flags */ ++ TV_IPA_CSPROFILE, /* tv_id */ ++ 0, /* properties_required */ ++ 0, /* properties_provided */ ++ 0, /* properties_destroyed */ ++ 0, /* todo_flags_start */ ++ 0, /* todo_flags_finish */ ++}; ++ ++class pass_ipa_csprofile : public ipa_opt_pass_d ++{ ++public: ++ pass_ipa_csprofile (gcc::context *ctxt) ++ : ipa_opt_pass_d (pass_data_ipa_csprofile, ctxt, ++ NULL, /* generate_summary */ ++ NULL, /* write_summary */ ++ NULL, /* read_summary */ ++ NULL, /* write_optimization_summary */ ++ NULL, /* read_optimization_summary */ ++ NULL, /* stmt_fixup */ ++ 0, /* function_transform_todo_flags_start */ ++ csprofile_transform, /* function_transform */ ++ NULL) /* variable_transform */ ++ {} ++ ++ /* opt_pass methods: */ ++ virtual bool gate (function *) ++ { ++ return (flag_csprofile_generate || flag_csprofile_use); ++ } ++ /* The main process of cspgo is in csprofile_transform, execute does not need ++ to do anything. */ ++ virtual unsigned int execute (function *) ++ { ++ return 0; ++ } ++ ++}; // class pass_ipa_csprofile ++ ++} // anon namespace ++ ++ipa_opt_pass_d * ++make_pass_ipa_csprofile (gcc::context *ctxt) ++{ ++ return new pass_ipa_csprofile (ctxt); ++} ++ + #include "gt-tree-profile.h" +diff --git a/gcc/value-prof.cc b/gcc/value-prof.cc +index c240a1863..9c7191287 100644 +--- a/gcc/value-prof.cc ++++ b/gcc/value-prof.cc +@@ -1234,7 +1234,7 @@ coverage_node_map_initialized_p (void) + that the PROFILE_IDs was already assigned. */ + + void +-init_node_map (bool local) ++init_node_map (bool local, bool is_cspgo) + { + struct cgraph_node *n; + cgraph_node_map = new hash_map<profile_id_hash, cgraph_node *>; +@@ -1245,6 +1245,12 @@ init_node_map (bool local) + cgraph_node **val; + dump_user_location_t loc + = dump_user_location_t::from_function_decl (n->decl); ++ ++ /* In cspgo, inline and clone functions will not be expand, ++ so skipped. */ ++ if (is_cspgo && (n->inlined_to || n->clone_of)) ++ continue; ++ + if (local) + { + n->profile_id = coverage_compute_profile_id (n); +@@ -1290,6 +1296,7 @@ void + del_node_map (void) + { + delete cgraph_node_map; ++ cgraph_node_map = 0; + } + + /* Return cgraph node for function with pid */ +diff --git a/gcc/value-prof.h b/gcc/value-prof.h +index d852c41f3..0fe3821c3 100644 +--- a/gcc/value-prof.h ++++ b/gcc/value-prof.h +@@ -112,8 +112,8 @@ extern struct cgraph_node* find_func_by_profile_id (int func_id); + + /* In profile.cc. */ + extern void init_branch_prob (void); +-extern void branch_prob (bool); +-extern void read_thunk_profile (struct cgraph_node *); ++extern void branch_prob (bool, bool); ++extern void read_thunk_profile (struct cgraph_node *, bool); + extern void end_branch_prob (void); + + #endif /* GCC_VALUE_PROF_H */ +-- +2.25.1 + |