diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7eb7a090ed7..e14eb1a913a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2012-10-09 Steven Bosscher + + * basic-block. (profile_record): New struct, moved from passes.c. + * cfghooks.h (struct cfg_hooks) : New hook. + (account_profile_record): New prototype. + * cfghooks.c (account_profile_record): New function. + * tree-cfg.c (gimple_account_profile_record): New function + (gimple_cfg_hooks): Add it. + * cfgrtl.c (rtl_account_profile_record): New function + (rtl_cfg_hooks, cfg_layout_rtl_cfg_hooks): Add it. + * passes.c (check_profile_consistency): Simplify. Move IR-dependent + code around using cfghooks machinery. + 2012-10-09 Oleg Endo PR target/54760 diff --git a/gcc/basic-block.h b/gcc/basic-block.h index a5491b03011..61351fb248d 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -101,6 +101,37 @@ typedef struct gcov_working_set_info gcov_type min_counter; } gcov_working_set_t; +/* Structure to gather statistic about profile consistency, per pass. + An array of this structure, indexed by pass static number, is allocated + in passes.c. The structure is defined here so that different CFG modes + can do their book-keeping via CFG hooks. + + For every field[2], field[0] is the count before the pass runs, and + field[1] is the post-pass count. This allows us to monitor the effect + of each individual pass on the profile consistency. + + This structure is not supposed to be used by anything other than passes.c + and one CFG hook per CFG mode. */ +struct profile_record +{ + /* The number of basic blocks where sum(freq) of the block's predecessors + doesn't match reasonably well with the incoming frequency. */ + int num_mismatched_freq_in[2]; + /* Likewise for a basic block's successors. */ + int num_mismatched_freq_out[2]; + /* The number of basic blocks where sum(count) of the block's predecessors + doesn't match reasonably well with the incoming frequency. */ + int num_mismatched_count_in[2]; + /* Likewise for a basic block's successors. */ + int num_mismatched_count_out[2]; + /* A weighted cost of the run-time of the function body. */ + gcov_type time[2]; + /* A weighted cost of the size of the function body. */ + int size[2]; + /* True iff this pass actually was run. */ + bool run; +}; + /* Declared in cfgloop.h. */ struct loop; diff --git a/gcc/cfghooks.c b/gcc/cfghooks.c index acd1f7abebc..d54dd469cf4 100644 --- a/gcc/cfghooks.c +++ b/gcc/cfghooks.c @@ -1324,3 +1324,57 @@ split_block_before_cond_jump (basic_block bb) return cfg_hooks->split_block_before_cond_jump (bb); } +/* Work-horse for passes.c:check_profile_consistency. + Do book-keeping of the CFG for the profile consistency checker. + If AFTER_PASS is 0, do pre-pass accounting, or if AFTER_PASS is 1 + then do post-pass accounting. Store the counting in RECORD. */ + +void +account_profile_record (struct profile_record *record, int after_pass) +{ + basic_block bb; + edge_iterator ei; + edge e; + int sum; + gcov_type lsum; + + FOR_ALL_BB (bb) + { + if (bb != EXIT_BLOCK_PTR_FOR_FUNCTION (cfun) + && profile_status != PROFILE_ABSENT) + { + sum = 0; + FOR_EACH_EDGE (e, ei, bb->succs) + sum += e->probability; + if (EDGE_COUNT (bb->succs) && abs (sum - REG_BR_PROB_BASE) > 100) + record->num_mismatched_freq_out[after_pass]++; + lsum = 0; + FOR_EACH_EDGE (e, ei, bb->succs) + lsum += e->count; + if (EDGE_COUNT (bb->succs) + && (lsum - bb->count > 100 || lsum - bb->count < -100)) + record->num_mismatched_count_out[after_pass]++; + } + if (bb != ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun) + && profile_status != PROFILE_ABSENT) + { + sum = 0; + FOR_EACH_EDGE (e, ei, bb->preds) + sum += EDGE_FREQUENCY (e); + if (abs (sum - bb->frequency) > 100 + || (MAX (sum, bb->frequency) > 10 + && abs ((sum - bb->frequency) * 100 / (MAX (sum, bb->frequency) + 1)) > 10)) + record->num_mismatched_freq_in[after_pass]++; + lsum = 0; + FOR_EACH_EDGE (e, ei, bb->preds) + lsum += e->count; + if (lsum - bb->count > 100 || lsum - bb->count < -100) + record->num_mismatched_count_in[after_pass]++; + } + if (bb == ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun) + || bb == EXIT_BLOCK_PTR_FOR_FUNCTION (cfun)) + continue; + gcc_assert (cfg_hooks->account_profile_record); + cfg_hooks->account_profile_record(bb, after_pass, record); + } +} diff --git a/gcc/cfghooks.h b/gcc/cfghooks.h index 951bdf6e17d..2806c4f27c5 100644 --- a/gcc/cfghooks.h +++ b/gcc/cfghooks.h @@ -145,6 +145,9 @@ struct cfg_hooks /* Split a basic block if it ends with a conditional branch and if the other part of the block is not empty. */ basic_block (*split_block_before_cond_jump) (basic_block); + + /* Do book-keeping of a basic block for the profile consistency checker. */ + void (*account_profile_record) (basic_block, int, struct profile_record *); }; extern void verify_flow_info (void); @@ -198,6 +201,8 @@ extern void copy_bbs (basic_block *, unsigned, basic_block *, edge *, unsigned, edge *, struct loop *, basic_block); +void account_profile_record (struct profile_record *, int); + extern void cfg_layout_initialize (unsigned int); extern void cfg_layout_finalize (void); diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index 7946a3fe9f4..1b578d7feeb 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -4452,6 +4452,28 @@ rtl_duplicate_bb (basic_block bb) return bb; } +/* Do book-keeping of basic block BB for the profile consistency checker. + If AFTER_PASS is 0, do pre-pass accounting, or if AFTER_PASS is 1 + then do post-pass accounting. Store the counting in RECORD. */ +static void +rtl_account_profile_record (basic_block bb, int after_pass, + struct profile_record *record) +{ + rtx insn; + FOR_BB_INSNS (bb, insn) + if (INSN_P (insn)) + { + record->size[after_pass] + += insn_rtx_cost (PATTERN (insn), false); + if (profile_status == PROFILE_READ) + record->time[after_pass] + += insn_rtx_cost (PATTERN (insn), true) * bb->count; + else if (profile_status == PROFILE_GUESSED) + record->time[after_pass] + += insn_rtx_cost (PATTERN (insn), true) * bb->frequency; + } +} + /* Implementation of CFG manipulation for linearized RTL. */ struct cfg_hooks rtl_cfg_hooks = { "rtl", @@ -4486,6 +4508,7 @@ struct cfg_hooks rtl_cfg_hooks = { NULL, /* flush_pending_stmts */ rtl_block_empty_p, /* block_empty_p */ rtl_split_block_before_cond_jump, /* split_block_before_cond_jump */ + rtl_account_profile_record, }; /* Implementation of CFG manipulation for cfg layout RTL, where @@ -4526,6 +4549,7 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = { NULL, /* flush_pending_stmts */ rtl_block_empty_p, /* block_empty_p */ rtl_split_block_before_cond_jump, /* split_block_before_cond_jump */ + rtl_account_profile_record, }; #include "gt-cfgrtl.h" diff --git a/gcc/passes.c b/gcc/passes.c index 27bdb829417..7a3d204e0d3 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -1778,30 +1778,16 @@ execute_function_dump (void *data ATTRIBUTE_UNUSED) } } -/* Make statistic about profile consistency. */ - -struct profile_record -{ - int num_mismatched_freq_in[2]; - int num_mismatched_freq_out[2]; - int num_mismatched_count_in[2]; - int num_mismatched_count_out[2]; - bool run; - gcov_type time[2]; - int size[2]; -}; - static struct profile_record *profile_record; +/* Do profile consistency book-keeping for the pass with static number INDEX. + If SUBPASS is zero, we run _before_ the pass, and if SUBPASS is one, then + we run _after_ the pass. RUN is true if the pass really runs, or FALSE + if we are only book-keeping on passes that may have selectively disabled + themselves on a given function. */ static void check_profile_consistency (int index, int subpass, bool run) { - basic_block bb; - edge_iterator ei; - edge e; - int sum; - gcov_type lsum; - if (index == -1) return; if (!profile_record) @@ -1810,79 +1796,7 @@ check_profile_consistency (int index, int subpass, bool run) gcc_assert (index < passes_by_id_size && index >= 0); gcc_assert (subpass < 2); profile_record[index].run |= run; - - FOR_ALL_BB (bb) - { - if (bb != EXIT_BLOCK_PTR_FOR_FUNCTION (cfun) - && profile_status != PROFILE_ABSENT) - { - sum = 0; - FOR_EACH_EDGE (e, ei, bb->succs) - sum += e->probability; - if (EDGE_COUNT (bb->succs) && abs (sum - REG_BR_PROB_BASE) > 100) - profile_record[index].num_mismatched_freq_out[subpass]++; - lsum = 0; - FOR_EACH_EDGE (e, ei, bb->succs) - lsum += e->count; - if (EDGE_COUNT (bb->succs) - && (lsum - bb->count > 100 || lsum - bb->count < -100)) - profile_record[index].num_mismatched_count_out[subpass]++; - } - if (bb != ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun) - && profile_status != PROFILE_ABSENT) - { - sum = 0; - FOR_EACH_EDGE (e, ei, bb->preds) - sum += EDGE_FREQUENCY (e); - if (abs (sum - bb->frequency) > 100 - || (MAX (sum, bb->frequency) > 10 - && abs ((sum - bb->frequency) * 100 / (MAX (sum, bb->frequency) + 1)) > 10)) - profile_record[index].num_mismatched_freq_in[subpass]++; - lsum = 0; - FOR_EACH_EDGE (e, ei, bb->preds) - lsum += e->count; - if (lsum - bb->count > 100 || lsum - bb->count < -100) - profile_record[index].num_mismatched_count_in[subpass]++; - } - if (bb == ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun) - || bb == EXIT_BLOCK_PTR_FOR_FUNCTION (cfun)) - continue; - if ((cfun && (cfun->curr_properties & PROP_trees))) - { - gimple_stmt_iterator i; - - for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) - { - profile_record[index].size[subpass] - += estimate_num_insns (gsi_stmt (i), &eni_size_weights); - if (profile_status == PROFILE_READ) - profile_record[index].time[subpass] - += estimate_num_insns (gsi_stmt (i), - &eni_time_weights) * bb->count; - else if (profile_status == PROFILE_GUESSED) - profile_record[index].time[subpass] - += estimate_num_insns (gsi_stmt (i), - &eni_time_weights) * bb->frequency; - } - } - else if (cfun && (cfun->curr_properties & PROP_rtl)) - { - rtx insn; - for (insn = NEXT_INSN (BB_HEAD (bb)); insn && insn != NEXT_INSN (BB_END (bb)); - insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - { - profile_record[index].size[subpass] - += insn_rtx_cost (PATTERN (insn), false); - if (profile_status == PROFILE_READ) - profile_record[index].time[subpass] - += insn_rtx_cost (PATTERN (insn), true) * bb->count; - else if (profile_status == PROFILE_GUESSED) - profile_record[index].time[subpass] - += insn_rtx_cost (PATTERN (insn), true) * bb->frequency; - } - } - } + account_profile_record (&profile_record[index], subpass); } /* Output profile consistency. */ diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index af277b79e09..7fc5a534dc7 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -7591,6 +7591,30 @@ gimple_lv_add_condition_to_bb (basic_block first_head ATTRIBUTE_UNUSED, e0->flags |= EDGE_FALSE_VALUE; } + +/* Do book-keeping of basic block BB for the profile consistency checker. + If AFTER_PASS is 0, do pre-pass accounting, or if AFTER_PASS is 1 + then do post-pass accounting. Store the counting in RECORD. */ +static void +gimple_account_profile_record (basic_block bb, int after_pass, + struct profile_record *record) +{ + gimple_stmt_iterator i; + for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) + { + record->size[after_pass] + += estimate_num_insns (gsi_stmt (i), &eni_size_weights); + if (profile_status == PROFILE_READ) + record->time[after_pass] + += estimate_num_insns (gsi_stmt (i), + &eni_time_weights) * bb->count; + else if (profile_status == PROFILE_GUESSED) + record->time[after_pass] + += estimate_num_insns (gsi_stmt (i), + &eni_time_weights) * bb->frequency; + } +} + struct cfg_hooks gimple_cfg_hooks = { "gimple", gimple_verify_flow_info, @@ -7624,6 +7648,7 @@ struct cfg_hooks gimple_cfg_hooks = { flush_pending_stmts, /* flush_pending_stmts */ gimple_empty_block_p, /* block_empty_p */ gimple_split_block_before_cond_jump, /* split_block_before_cond_jump */ + gimple_account_profile_record, };