https://codereview.appspot.com/8814043/diff/1/gcc/auto-profile.c File gcc/auto-profile.c (right):
https://codereview.appspot.com/8814043/diff/1/gcc/auto-profile.c#newcode161 gcc/auto-profile.c:161: }; Why not sharing the same hist_type enum in value-prof.h? https://codereview.appspot.com/8814043/diff/1/gcc/auto-profile.c#newcode171 gcc/auto-profile.c:171: int count; int --> gcov_type? https://codereview.appspot.com/8814043/diff/1/gcc/auto-profile.c#newcode519 gcc/auto-profile.c:519: static void New line above. https://codereview.appspot.com/8814043/diff/1/gcc/auto-profile.c#newcode550 gcc/auto-profile.c:550: if (actual_count < 2) Are the targets sorted? https://codereview.appspot.com/8814043/diff/1/gcc/auto-profile.c#newcode570 gcc/auto-profile.c:570: static void afdo_vpt (gimple stmt, struct gcov_hist *v, int hist_size) New line. https://codereview.appspot.com/8814043/diff/1/gcc/auto-profile.c#newcode914 gcc/auto-profile.c:914: for the given POS_STACK. */ Document new parameters. https://codereview.appspot.com/8814043/diff/1/gcc/auto-profile.c#newcode1193 gcc/auto-profile.c:1193: gcov_functions[i].stacks[j].hist_size = gcov_read_unsigned (); Why is the data not optional? https://codereview.appspot.com/8814043/diff/1/gcc/auto-profile.c#newcode1203 gcc/auto-profile.c:1203: file_names[gcov_read_counter()]; missing white space (many other instances) https://codereview.appspot.com/8814043/diff/1/gcc/tree-inline.c File gcc/tree-inline.c (right): https://codereview.appspot.com/8814043/diff/1/gcc/tree-inline.c#newcode1833 gcc/tree-inline.c:1833: gcov_type count = afdo_get_bb_count (copy_basic_block, false); comment about the 'false' parameter. https://codereview.appspot.com/8814043/diff/1/gcc/value-prof.c File gcc/value-prof.c (right): https://codereview.appspot.com/8814043/diff/1/gcc/value-prof.c#newcode1223 gcc/value-prof.c:1223: if (!strcmp(fname, name)) You can use assembler_name_hash to find the cgraph_node https://codereview.appspot.com/8814043/diff/1/gcc/value-prof.c#newcode1626 gcc/value-prof.c:1626: direct_call1 = find_func_by_global_id (val1); May be add a parameter to find_func_by_global_id (val, is_auto_fdo)? https://codereview.appspot.com/8814043/ On Tue, Apr 16, 2013 at 8:41 PM, Dehao Chen <de...@google.com> wrote: > This patch implements indirect call promotion for AutoFDO. > > Bootstrapped and passed gcc regression tests. > > Is it okay for gcc-4_7 branch? > > Thanks, > Dehao > > http://codereview.appspot.com/8814043 > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index d17b250..c217846 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -3039,7 +3039,7 @@ coverage.o : coverage.c $(GCOV_IO_H) $(CONFIG_H) > $(SYSTEM_H) coretypes.h \ > $(DIAGNOSTIC_CORE_H) intl.h gt-coverage.h $(TARGET_H) $(AUTO_PROFILE_H) > auto-profile.o : auto-profile.c $(CONFIG_H) $(SYSTEM_H) $(FLAGS_H) \ > $(BASIC_BLOCK_H) $(DIAGNOSTIC_CORE_H) $(GCOV_IO_H) $(INPUT_H) > $(PROFILE_H) \ > - $(LANGHOOKS_H) $(OPTS_H) $(TREE_PASS_H) $(CGRAPH_H) $(GIMPLE_H) \ > + $(LANGHOOKS_H) $(OPTS_H) $(TREE_PASS_H) $(CGRAPH_H) $(GIMPLE_H) > value-prof.h \ > $(AUTO_PROFILE_H) > cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ > $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h $(RECOG_H) \ > diff --git a/gcc/auto-profile.c b/gcc/auto-profile.c > index cf17370..38f4209 100644 > --- a/gcc/auto-profile.c > +++ b/gcc/auto-profile.c > @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see > #include "gimple.h" > #include "cgraph.h" > #include "tree-flow.h" > +#include "value-prof.h" > #include "auto-profile.h" > > /* The following routines implements AutoFDO optimization. > @@ -109,6 +110,8 @@ struct gcov_stack > const char *callee_name; > struct gcov_callsite_pos *stack; > gcov_unsigned_t size; > + struct gcov_hist *hist; > + gcov_unsigned_t hist_size; > gcov_type num_inst; > gcov_type count; > gcov_type max_count; > @@ -150,6 +153,24 @@ struct afdo_module > char **strings; > }; > > +enum afdo_histogram_type > +{ > + CALL_HIST = 1, > + STRINGOP_HIST, > + DIVMOD_HIST > +}; > + > +struct gcov_hist > +{ > + enum afdo_histogram_type type; > + union > + { > + const char *func_name; > + unsigned long long value; > + } value; > + int count; > +}; > + > /* Store the file name strings read from the profile data file. */ > static const char **file_names; > > @@ -493,6 +514,64 @@ read_aux_modules (void) > } > } > > +/* From AutoFDO profiles, find values inside STMT for that we want to measure > + histograms for indirect-call optimization. */ > +static void > +afdo_indirect_call (gimple stmt, struct gcov_hist *values, int hist_size) > +{ > + tree callee; > + int i, total = 0; > + int actual_count = 0; > + histogram_value hist; > + > + if (gimple_code (stmt) != GIMPLE_CALL > + || gimple_call_fndecl (stmt) != NULL_TREE) > + return; > + > + callee = gimple_call_fn (stmt); > + > + for (i = 0; i < hist_size; i++) > + if (values[i].type == CALL_HIST) > + break; > + > + if (i == hist_size) > + return; > + > + hist = gimple_alloc_histogram_value (cfun, HIST_TYPE_INDIR_CALL_TOPN, > + stmt, callee); > + hist->n_counters = (GCOV_ICALL_TOPN_VAL << 2) + 1; > + hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters); > + gimple_add_histogram_value (cfun, stmt, hist); > + > + for (i = 0; i < hist_size; i++) > + if (values[i].type == CALL_HIST) > + { > + total += values[i].count; > + if (actual_count < 2) > + { > + hist->hvalue.counters[actual_count * 2 + 1] = > + (unsigned long long) values[i].value.func_name; > + hist->hvalue.counters[actual_count * 2 + 2] = values[i].count; > + actual_count ++; > + } > + } > + > + hist->hvalue.counters[0] = total; > + > + if (actual_count == 1) > + { > + hist->hvalue.counters[3] = 0; > + hist->hvalue.counters[4] = 0; > + } > +} > + > +/* From AutoFDO profiles, find values inside STMT for that we want to measure > + histograms and adds them to list VALUES. */ > +static void afdo_vpt (gimple stmt, struct gcov_hist *v, int hist_size) > +{ > + afdo_indirect_call (stmt, v, hist_size); > +} > + > /* Return the size of the inline stack of the STMT. */ > > static int > @@ -838,7 +917,8 @@ static bool > get_stack_count (struct gcov_callsite_pos *pos_stack, > const char *callee_name, > int size, > - gcov_type *count, gcov_type *max_count, gcov_type *num_inst) > + gcov_type *count, gcov_type *max_count, gcov_type *num_inst, > + gcov_unsigned_t *hist_size, struct gcov_hist **hist) > { > int i; > > @@ -858,6 +938,11 @@ get_stack_count (struct gcov_callsite_pos *pos_stack, > *num_inst = entry->num_inst; > if (max_count) > *max_count = entry->max_count; > + if (hist_size) > + { > + *hist_size = entry->hist_size; > + *hist = entry->hist; > + } > return true; > } > else > @@ -876,6 +961,11 @@ get_stack_count (struct gcov_callsite_pos *pos_stack, > *num_inst = entry->num_inst; > if (max_count) > *max_count = entry->max_count; > + if (hist_size) > + { > + *hist_size = entry->hist_size; > + *hist = entry->hist; > + } > return true; > } > } > @@ -885,6 +975,11 @@ get_stack_count (struct gcov_callsite_pos *pos_stack, > *num_inst = 0; > if (max_count) > *max_count = 0; > + if (hist_size) > + { > + *hist_size = 0; > + *hist = 0; > + } > return false; > } > > @@ -892,7 +987,8 @@ get_stack_count (struct gcov_callsite_pos *pos_stack, > Return FALSE if profile is not found for STMT. */ > > static bool > -get_stmt_count (gimple stmt, gcov_type *count, gcov_type *num_inst) > +get_stmt_count (gimple stmt, gcov_type *count, gcov_type *num_inst, > + gcov_unsigned_t *hist_size, struct gcov_hist **hist) > { > struct gcov_callsite_pos *pos_stack; > int size; > @@ -910,7 +1006,8 @@ get_stmt_count (gimple stmt, gcov_type *count, > gcov_type *num_inst) > > get_inline_stack_by_stmt (stmt, current_function_decl, pos_stack, true); > > - return get_stack_count (pos_stack, NULL, size, count, NULL, num_inst); > + return get_stack_count (pos_stack, NULL, size, count, NULL, num_inst, > + hist_size, hist); > } > > /* For a given EDGE, if IS_TOTAL is true, save EDGE->callee's total count > @@ -938,13 +1035,13 @@ afdo_get_callsite_count (struct cgraph_edge > *edge, gcov_type *count, > get_discriminator_from_locus(gimple_location(edge->call_stmt)); > > return get_stack_count (pos_stack, callee_name, > - size, count, max_count, &num_inst); > + size, count, max_count, &num_inst, NULL, NULL); > } > > /* For a given BB, return its execution count. */ > > gcov_type > -afdo_get_bb_count (basic_block bb) > +afdo_get_bb_count (basic_block bb, bool annotate_vpt) > { > gimple_stmt_iterator gsi; > gcov_type max_count = 0; > @@ -953,12 +1050,16 @@ afdo_get_bb_count (basic_block bb) > for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) > { > gcov_type count, num_inst; > + gcov_unsigned_t hist_size; > + struct gcov_hist *hist; > gimple stmt = gsi_stmt (gsi); > - if (get_stmt_count (stmt, &count, &num_inst)) > + if (get_stmt_count (stmt, &count, &num_inst, &hist_size, &hist)) > { > if (count > max_count) > max_count = count; > has_annotated = true; > + if (annotate_vpt && hist_size > 0) > + afdo_vpt (stmt, hist, hist_size); > } > } > if (has_annotated) > @@ -980,7 +1081,7 @@ afdo_annotate_cfg (void) > > FOR_EACH_BB (bb) > { > - bb->count = afdo_get_bb_count (bb); > + bb->count = afdo_get_bb_count (bb, true); > if (bb->count > max_count) > max_count = bb->count; > } > @@ -992,6 +1093,8 @@ afdo_annotate_cfg (void) > afdo_calculate_branch_prob (); > profile_status = PROFILE_READ; > } > + if (flag_value_profile_transformations) > + gimple_value_profile_transformations (); > } > > extern gcov_working_set_t *gcov_working_sets; > @@ -1055,7 +1158,7 @@ read_profile (void) > xmalloc (function_num * sizeof (struct gcov_function)); > for (i = 0; i < function_num; i++) > { > - gcov_functions[i].name = xstrdup (gcov_read_string ()); > + gcov_functions[i].name = file_names[gcov_read_unsigned ()]; > gcov_functions[i].file = file_names[gcov_read_unsigned ()]; > gcov_functions[i].total_count = gcov_read_counter (); > gcov_functions[i].entry_count = gcov_read_counter (); > @@ -1087,6 +1190,22 @@ read_profile (void) > } > gcov_functions[i].stacks[j].count = gcov_read_counter (); > gcov_functions[i].stacks[j].num_inst = gcov_read_counter (); > + gcov_functions[i].stacks[j].hist_size = gcov_read_unsigned (); > + gcov_functions[i].stacks[j].hist = (struct gcov_hist *) > + xmalloc (gcov_functions[i].stacks[j].hist_size > + * sizeof (struct gcov_hist)); > + for (k = 0; k < gcov_functions[i].stacks[j].hist_size; k++) > + { > + gcov_functions[i].stacks[j].hist[k].type = > + (enum afdo_histogram_type) gcov_read_unsigned(); > + if (gcov_functions[i].stacks[j].hist[k].type == CALL_HIST) > + gcov_functions[i].stacks[j].hist[k].value.func_name = > + file_names[gcov_read_counter()]; > + else > + gcov_functions[i].stacks[j].hist[k].value.value = > + gcov_read_counter(); > + gcov_functions[i].stacks[j].hist[k].count = gcov_read_counter(); > + } > } > } > > @@ -1698,6 +1817,7 @@ auto_profile (void) > > afdo_annotate_cfg (); > compute_function_frequency (); > + update_ssa (TODO_update_ssa); > > current_function_decl = NULL; > pop_cfun (); > diff --git a/gcc/auto-profile.h b/gcc/auto-profile.h > index 8e0a670..f7175ff 100644 > --- a/gcc/auto-profile.h > +++ b/gcc/auto-profile.h > @@ -43,5 +43,5 @@ extern bool afdo_get_callsite_count (struct > cgraph_edge *, gcov_type *, > gcov_type *, bool); > > /* Calculate basic block count. */ > -extern gcov_type afdo_get_bb_count (basic_block); > +extern gcov_type afdo_get_bb_count (basic_block, bool); > #endif /* AUTO_PROFILE_H */ > diff --git a/gcc/opts.c b/gcc/opts.c > index 4657d6a..dab2564 100644 > --- a/gcc/opts.c > +++ b/gcc/opts.c > @@ -1665,6 +1665,8 @@ common_handle_option (struct gcc_options *opts, > opts->x_flag_unroll_loops = value; > if (!opts_set->x_flag_peel_loops) > opts->x_flag_peel_loops = value; > + if (!opts_set->x_flag_value_profile_transformations) > + opts->x_flag_value_profile_transformations = value; > if (!opts_set->x_flag_inline_functions) > opts->x_flag_inline_functions = value; > if (!opts_set->x_flag_ipa_cp) > diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c > index f09f201..62180fc 100644 > --- a/gcc/tree-inline.c > +++ b/gcc/tree-inline.c > @@ -1830,7 +1830,7 @@ copy_bb (copy_body_data *id, basic_block bb, int > frequency_scale, > { > /* If the same inline happens in the profile-collection binary, use > that instance's profile count. Otherwise use the scaled count. */ > - gcov_type count = afdo_get_bb_count (copy_basic_block); > + gcov_type count = afdo_get_bb_count (copy_basic_block, false); > if (copy_basic_block->flags & BB_ANNOTATED) > copy_basic_block->count = count; > else if (bb->flags & BB_ANNOTATED) > diff --git a/gcc/value-prof.c b/gcc/value-prof.c > index 81465bc..c20d13a 100644 > --- a/gcc/value-prof.c > +++ b/gcc/value-prof.c > @@ -94,7 +94,7 @@ static bool gimple_ic_transform (gimple); > > /* Allocate histogram value. */ > > -static histogram_value > +histogram_value > gimple_alloc_histogram_value (struct function *fun ATTRIBUTE_UNUSED, > enum hist_type type, gimple stmt, tree value) > { > @@ -1205,6 +1205,33 @@ find_func_by_funcdef_no (int func_id) > return VEC_index (cgraph_node_ptr, cgraph_node_map, func_id); > } > > +/* Return cgraph node for function with name. We need this because > + AutoFDO doesn't record the function id for each function > + in the profile. > + TODO: need to transform this lookup method to hash table. */ > + > +static struct cgraph_node * > +find_func_by_name (char *name) > +{ > + struct cgraph_node *n; > + struct cgraph_node *ret = NULL; > + int match = 0; > + > + for (n = cgraph_nodes; n; n = n->next) > + { > + const char *fname = IDENTIFIER_POINTER (decl_assembler_name (n->decl)); > + if (!strcmp(fname, name)) > + { > + match ++; > + ret = n; > + } > + } > + if (match == 1) > + return ret; > + else > + return NULL; > +} > + > /* Initialize map of gids (gid -> cgraph node) */ > > static htab_t gid_map = NULL; > @@ -1562,7 +1589,8 @@ gimple_ic_transform_mult_targ (gimple stmt, > histogram_value histogram) > count1 = histogram->hvalue.counters [2]; > val2 = histogram->hvalue.counters [3]; > count2 = histogram->hvalue.counters [4]; > - bb_all = gimple_bb (stmt)->count; > + bb_all = flag_auto_profile ? histogram->hvalue.counters[0] > + : gimple_bb (stmt)->count; > all = bb_all; > > gimple_remove_histogram_value (cfun, stmt, histogram); > @@ -1592,18 +1620,26 @@ gimple_ic_transform_mult_targ (gimple stmt, > histogram_value histogram) > else > prob1 = prob2 = 0; > > - direct_call1 = find_func_by_global_id (val1); > + if (flag_auto_profile) > + direct_call1 = find_func_by_name ((char *) val1); > + else > + direct_call1 = find_func_by_global_id (val1); > > if (val2 && (100 * count2 >= all * perc_threshold) > && count2 > count_threshold) > - direct_call2 = find_func_by_global_id (val2); > + { > + if (flag_auto_profile) > + direct_call2 = find_func_by_name ((char *) val2); > + else > + direct_call2 = find_func_by_global_id (val2); > + } > > locus = (stmt != NULL) ? gimple_location (stmt) > : DECL_SOURCE_LOCATION (current_function_decl); > if (direct_call1 == NULL > || !check_ic_target (stmt, direct_call1)) > { > - if (flag_opt_info >= OPT_INFO_MAX) > + if (flag_opt_info >= OPT_INFO_MAX && !flag_auto_profile) > { > if (!direct_call1) > inform (locus, "Can not find indirect call target decl " > @@ -1645,9 +1681,12 @@ gimple_ic_transform_mult_targ (gimple stmt, > histogram_value histogram) > print_generic_expr (dump_file, gimple_call_fn (stmt), TDF_SLIM); > fprintf (dump_file, "=> "); > print_generic_expr (dump_file, direct_call1->decl, TDF_SLIM); > - fprintf (dump_file, " (module_id:%d, func_id:%d)\n", > - EXTRACT_MODULE_ID_FROM_GLOBAL_ID (val1), > - EXTRACT_FUNC_ID_FROM_GLOBAL_ID (val1)); > + if (flag_auto_profile) > + fprintf (dump_file, " (%s)\n", (char *) val1); > + else > + fprintf (dump_file, " (module_id:%d, func_id:%d)\n", > + EXTRACT_MODULE_ID_FROM_GLOBAL_ID (val1), > + EXTRACT_FUNC_ID_FROM_GLOBAL_ID (val1)); > fprintf (dump_file, "Transformation on insn:\n"); > print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); > fprintf (dump_file, "==>\n"); > @@ -1683,9 +1722,12 @@ gimple_ic_transform_mult_targ (gimple stmt, > histogram_value histogram) > print_generic_expr (dump_file, gimple_call_fn (stmt), TDF_SLIM); > fprintf (dump_file, "=> "); > print_generic_expr (dump_file, direct_call2->decl, TDF_SLIM); > - fprintf (dump_file, " (module_id:%d, func_id:%d)\n", > - EXTRACT_MODULE_ID_FROM_GLOBAL_ID (val2), > - EXTRACT_FUNC_ID_FROM_GLOBAL_ID (val2)); > + if (flag_auto_profile) > + fprintf (dump_file, " (%s)\n", (char *) val2); > + else > + fprintf (dump_file, " (module_id:%d, func_id:%d)\n", > + EXTRACT_MODULE_ID_FROM_GLOBAL_ID (val2), > + EXTRACT_FUNC_ID_FROM_GLOBAL_ID (val2)); > fprintf (dump_file, "Transformation on insn\n"); > print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); > fprintf (dump_file, "=>\n"); > diff --git a/gcc/value-prof.h b/gcc/value-prof.h > index 9425e25..2d84fe9 100644 > --- a/gcc/value-prof.h > +++ b/gcc/value-prof.h > @@ -77,6 +77,8 @@ typedef VEC(histogram_value,heap) *histogram_values; > extern void gimple_find_values_to_profile (histogram_values *); > extern bool gimple_value_profile_transformations (void); > > +histogram_value gimple_alloc_histogram_value (struct function *, enum > hist_type, > + gimple stmt, tree); > histogram_value gimple_histogram_value (struct function *, gimple); > histogram_value gimple_histogram_value_of_type (struct function *, gimple, > enum hist_type);