Hi,

This patch adds an option. When the option is enabled, GCC will add a
record about it in an elf section called
".gnu.switches.text.branch.annotation" for every branch.

gcc/

2014-06-27 Yi Yang <ahyan...@google.com>

        * auto-profile.c: Main comparison and reporting logic.
        * cfg-flags.def: Add an extra flag representing an edge's
probability is predicted by annotations.
        * predict.c: Set up the extra flag on an edge when appropriate.
        * common.opt: Add an extra GCC option to turn on this report mechanism
diff --git a/gcc/auto-profile.c b/gcc/auto-profile.c
index 74d3d1d..f7698cd 100644
--- a/gcc/auto-profile.c
+++ b/gcc/auto-profile.c
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "opts.h"	      /* for in_fnames.	 */
 #include "tree-pass.h"	      /* for ipa pass.  */
 #include "cfgloop.h"	      /* for loop_optimizer_init.  */
+#include "md5.h"	      /* for hashing function names. */
 #include "gimple.h"
 #include "cgraph.h"
 #include "tree-flow.h"
@@ -1367,6 +1368,80 @@ afdo_propagate (void)
     }
 }
 
+struct locus_information_t {
+  char filename[1024];
+  unsigned lineno;
+  unsigned function_lineno;
+  char function_hash[33];
+};
+
+static bool
+get_locus_information (location_t locus, locus_information_t* li) {
+  if (locus == UNKNOWN_LOCATION || !LOCATION_FILE(locus))
+    return false;
+  snprintf(li->filename, 1024, "%s", LOCATION_FILE(locus));
+  li->lineno = LOCATION_LINE(locus);
+
+  tree block = LOCATION_BLOCK (locus);
+  tree function_decl = current_function_decl;
+  
+  if (block && TREE_CODE (block) == BLOCK)
+    {
+      for (block = BLOCK_SUPERCONTEXT (block);
+	   block && (TREE_CODE (block) == BLOCK);
+	   block = BLOCK_SUPERCONTEXT (block))
+	{
+	  location_t tmp_locus = BLOCK_SOURCE_LOCATION (block);
+	  if (LOCATION_LOCUS (tmp_locus) == UNKNOWN_LOCATION)
+	    continue;
+
+	  tree decl = get_function_decl_from_block (block);
+	  function_decl = decl;
+	  break;
+	}
+    }
+
+  if (!(function_decl && TREE_CODE (function_decl) == FUNCTION_DECL))
+    return false;
+  unsigned function_length = 0;
+  function *f = DECL_STRUCT_FUNCTION(function_decl);
+
+  li->function_lineno = LOCATION_LINE(DECL_SOURCE_LOCATION(function_decl));
+
+  if (f)
+    {
+      function_length = LOCATION_LINE(f->function_end_locus) -
+	li->function_lineno;
+    }
+
+  const char *fn_name = fndecl_name(function_decl);
+  unsigned char md5_result[16];
+
+  md5_ctx ctx;
+
+  md5_init_ctx(&ctx);
+  md5_process_bytes(fn_name, strlen(fn_name), &ctx);
+  md5_process_bytes(&function_length, sizeof(function_length), &ctx);
+  md5_finish_ctx(&ctx, md5_result);
+
+  for (int i = 0; i < 16; ++i)
+    {
+      sprintf(li->function_hash + i*2, "%02x", md5_result[i]);
+    }
+  
+  return true;
+}
+
+void
+fill_invalid_locus_information(locus_information_t* li) {
+  snprintf(li->filename, 1024, "<unknown>");
+  li->lineno = 0;
+  li->function_lineno = 0;
+  for (int i = 0; i < 32; ++i)
+    li->function_hash[i] = '0';
+  li->function_hash[32] = '\0';
+}
+
 /* Propagate counts on control flow graph and calculate branch
    probabilities.  */
 
@@ -1407,8 +1482,62 @@ afdo_calculate_branch_prob (void)
       if (num_unknown_succ == 0 && total_count > 0)
 	{
 	  FOR_EACH_EDGE (e, ei, bb->succs)
-	    e->probability =
-		(double) e->count * REG_BR_PROB_BASE / total_count;
+	    {
+	      double probability =
+		  (double) e->count * REG_BR_PROB_BASE / total_count;
+
+	      if (flag_check_branch_annotation &&
+		  bb->succs->length() == 2 &&
+		  maybe_hot_count_p (cfun, bb->count) &&
+		  bb->count >= 100)
+		{
+		  gimple_stmt_iterator gsi;
+		  gimple last = NULL;
+
+		  for (gsi = gsi_last_nondebug_bb (bb);
+		       !gsi_end_p (gsi);
+		       gsi_prev_nondebug (&gsi))
+		    {
+		      last = gsi_stmt (gsi);
+
+		      if (gimple_has_location (last))
+			break;
+		    }
+
+		  struct locus_information_t li;
+		  bool annotated;
+
+		  if (e->flags & EDGE_PREDICTED_BY_EXPECT)
+		    annotated = true;
+		  else
+		    annotated = false;
+
+		  if (get_locus_information(e->goto_locus, &li))
+		    ;
+		  else if (get_locus_information(gimple_location(last), &li))
+		    ;
+		  else
+		    fill_invalid_locus_information(&li);
+
+		  switch_to_section (get_section (
+		      ".gnu.switches.text.branch.annotation",
+		      SECTION_DEBUG | SECTION_MERGE |
+		      SECTION_STRINGS | (SECTION_ENTSIZE & 1),
+		      NULL));
+		  char buf[1024];
+		  snprintf (buf, 1024, "%s;%u;%d;"
+			    HOST_WIDEST_INT_PRINT_DEC";%.6lf;%.6lf;%s;%u",
+			    li.filename, li.lineno, bb->count, annotated?1:0,
+			    probability/REG_BR_PROB_BASE,
+			    e->probability/(double)REG_BR_PROB_BASE,
+			    li.function_hash, li.function_lineno);
+		  dw2_asm_output_nstring (buf, (size_t)-1, NULL);
+
+		  break;
+		}
+
+	      e->probability = probability;
+	    }
 	}
     }
   FOR_ALL_BB (bb)
@@ -1417,8 +1546,11 @@ afdo_calculate_branch_prob (void)
       edge_iterator ei;
 
       FOR_EACH_EDGE (e, ei, bb->succs)
-	e->count =
-		(double) bb->count * e->probability / REG_BR_PROB_BASE;
+	{
+	  e->count =
+		  (double) bb->count * e->probability / REG_BR_PROB_BASE;
+	  e->flags &= ~EDGE_PREDICTED_BY_EXPECT;
+	}
       bb->aux = NULL;
     }
 
@@ -1542,9 +1674,9 @@ afdo_annotate_cfg (const stmt_set &promoted_stmts)
   afdo_source_profile->mark_annotated (cfun->function_end_locus);
   if (max_count > 0)
     {
+      profile_status = PROFILE_READ;
       afdo_calculate_branch_prob ();
       counts_to_freqs ();
-      profile_status = PROFILE_READ;
     }
   if (flag_value_profile_transformations)
     gimple_value_profile_transformations ();
diff --git a/gcc/cfg-flags.def b/gcc/cfg-flags.def
index 42a0473..5904d8d 100644
--- a/gcc/cfg-flags.def
+++ b/gcc/cfg-flags.def
@@ -186,6 +186,9 @@ DEF_EDGE_FLAG(TM_ABORT, 16)
 /* Annotated during AutoFDO profile attribution.  */
 DEF_EDGE_FLAG(ANNOTATED, 17)
 
+/* Edge probability predicted by __builtin_expect. */
+DEF_EDGE_FLAG(PREDICTED_BY_EXPECT, 18)
+
 #endif
 
 /*
diff --git a/gcc/common.opt b/gcc/common.opt
index 4305c89..5ac159e 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -950,6 +950,10 @@ fauto-profile-record-coverage-in-elf
 Common Report Var(flag_auto_profile_record_coverage_in_elf) Optimization
 Whether to record annotation coverage info in elf.
 
+fcheck-branch-annotation
+Common Report Var(flag_check_branch_annotation)
+Record branch prediction information in elf.
+
 ; -fcheck-bounds causes gcc to generate array bounds checks.
 ; For C, C++ and ObjC: defaults off.
 ; For Java: defaults to on.
diff --git a/gcc/predict.c b/gcc/predict.c
index f27c58c..cecc801 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -1014,6 +1014,11 @@ combine_predictions_for_bb (basic_block bb)
     {
       first->probability = combined_probability;
       second->probability = REG_BR_PROB_BASE - combined_probability;
+      if (first_match && best_predictor == PRED_BUILTIN_EXPECT)
+	{
+	  first->flags |= EDGE_PREDICTED_BY_EXPECT;
+	  second->flags |= EDGE_PREDICTED_BY_EXPECT;
+	}
     }
 }

--

Reply via email to