]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
* basic-block. (profile_record): New struct, moved from passes.c.
authorSteven Bosscher <steven@gcc.gnu.org>
Tue, 9 Oct 2012 20:37:11 +0000 (20:37 +0000)
committerSteven Bosscher <steven@gcc.gnu.org>
Tue, 9 Oct 2012 20:37:11 +0000 (20:37 +0000)
* cfghooks.h (struct cfg_hooks) <account_profile_record>: 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.

From-SVN: r192271

gcc/ChangeLog
gcc/basic-block.h
gcc/cfghooks.c
gcc/cfghooks.h
gcc/cfgrtl.c
gcc/passes.c
gcc/tree-cfg.c

index 7eb7a090ed753be483908802ec211f91acedaad2..e14eb1a913aff30461467710a5e803b555b962e9 100644 (file)
@@ -1,3 +1,16 @@
+2012-10-09  Steven Bosscher  <steven@gcc.gnu.org>
+
+       * basic-block. (profile_record): New struct, moved from passes.c.
+       * cfghooks.h (struct cfg_hooks) <account_profile_record>: 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  <olegendo@gcc.gnu.org>
 
        PR target/54760
index a5491b030119546cedfc93be2dd30dc42e55f276..61351fb248de6a393d0176a74b2f7a501c7c6270 100644 (file)
@@ -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;
 
index acd1f7abebc1008a1cb0ee3672a1a82895a3495f..d54dd469cf4906695922f1b23d2daeade1024817 100644 (file)
@@ -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);
+   }
+}
index 951bdf6e17d78cce3128b0bcca70520e3611ca35..2806c4f27c50bba69364c57c1a883b91fc24cca8 100644 (file)
@@ -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);
 
index 7946a3fe9f4df9a6a1224e41b39ccda23e8637d5..1b578d7feeb31fbbe06b4d056e7b7ccdd5798619 100644 (file)
@@ -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"
index 27bdb829417efbe1ab4a5c3ea84dd9821c5f0585..7a3d204e0d337da85c71d74010e44098c21ba14a 100644 (file)
@@ -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.  */
index af277b79e099feda7ea295328f0c8155c1d10865..7fc5a534dc7cdf67726d3cbb73a2558d6214e508 100644 (file)
@@ -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,
 };