diff mbox

Predict for loop exits in short-circuit conditions

Message ID CAO2gOZW0HCj1agfmESWPVS2rxGs9WPTxveJGNAmxYnoFrPwfqg@mail.gmail.com
State New
Headers show

Commit Message

Dehao Chen May 28, 2012, 3:06 a.m. UTC
Hi,

This patch implements static branch prediction for loop exit
conditions that cannot be identified by original heuristic (edge->dst
is outside of the loop). It can find extra loop exits for short
circuit conditions.

Bootstrapped and passed gcc testsuite.

Is it ok for trunk?

Thanks,
Dehao

gcc/ChangeLog
2012-05-28  Dehao Chen  <dehao@google.com>

	* predict.c (predict_extra_loop_exit): New function to predict for
	extra loop exits resulted from short-circuit conditions.

gcc/testsuite/ChangeLog
2012-05-28  Dehao Chen  <dehao@google.com>
	* g++.dg/predict-loop-exit-1.C: New test.
	* g++.dg/predict-loop-exit-2.C: New test.
	* g++.dg/predict-loop-exit-3.C: New test.
diff mbox

Patch

Index: gcc/testsuite/g++.dg/predict-loop-exit-1.C
===================================================================
--- gcc/testsuite/g++.dg/predict-loop-exit-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/predict-loop-exit-1.C	(revision 0)
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-profile_estimate" } */
+
+int g;
+int foo();
+void test() {
+  while (foo() && g < 10)
+    g++;
+  return;
+}
+
+/* { dg-final { scan-tree-dump-times "loop exit heuristics:" 3
"profile_estimate"} } */
+/* { dg-final { cleanup-tree-dump "profile_estimate" } } */
Index: gcc/testsuite/g++.dg/predict-loop-exit-3.C
===================================================================
--- gcc/testsuite/g++.dg/predict-loop-exit-3.C	(revision 0)
+++ gcc/testsuite/g++.dg/predict-loop-exit-3.C	(revision 0)
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-profile_estimate" } */
+
+int g;
+int foo();
+void test() {
+  while (foo() && (g < 10 || g > 20))
+    g++;
+  return;
+}
+
+/* { dg-final { scan-tree-dump-times "loop exit heuristics:" 3
"profile_estimate"} } */
+/* { dg-final { cleanup-tree-dump "profile_estimate" } } */
Index: gcc/testsuite/g++.dg/predict-loop-exit-2.C
===================================================================
--- gcc/testsuite/g++.dg/predict-loop-exit-2.C	(revision 0)
+++ gcc/testsuite/g++.dg/predict-loop-exit-2.C	(revision 0)
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-profile_estimate" } */
+
+int g;
+int foo();
+void test() {
+  while (foo() || g < 10)
+    g++;
+  return;
+}
+
+/* { dg-final { scan-tree-dump-times "loop exit heuristics:" 2
"profile_estimate"} } */
+/* { dg-final { cleanup-tree-dump "profile_estimate" } } */
Index: gcc/predict.c
===================================================================
--- gcc/predict.c	(revision 187922)
+++ gcc/predict.c	(working copy)
@@ -1294,7 +1294,93 @@ 
 	predict_edge_def (then_edge, PRED_LOOP_IV_COMPARE_GUESS, NOT_TAKEN);
     }
 }
-
+
+/* Predict for extra loop exits that will lead to EXIT_EDGE. The extra loop
+   exits are resulted from short-circuit conditions that will generate an
+   if_tmp. E.g.:
+
+   if (foo() || global > 10)
+     break;
+
+   This will be translated into:
+
+   BB3:
+     loop header...
+   BB4:
+     if foo() goto BB6 else goto BB5
+   BB5:
+     if global > 10 goto BB6 else goto BB7
+   BB6:
+     goto BB7
+   BB7:
+     iftmp = (PHI 0(BB5), 1(BB6))
+     if iftmp == 1 goto BB8 else goto BB3
+   BB8:
+     outside of the loop...
+
+   The edge BB7->BB8 is loop exit because BB8 is outside of the loop.
+   From the dataflow, we can infer that BB4->BB6 and BB5->BB6 are also loop
+   exits. This function takes BB7->BB8 as input, and finds out the extra loop
+   exits to predict them using PRED_LOOP_EXIT.  */
+
+static void
+predict_extra_loop_exits (edge exit_edge)
+{
+  unsigned i;
+  bool check_value_one;
+  gimple phi_stmt;
+  tree cmp_rhs, cmp_lhs;
+  gimple cmp_stmt = last_stmt (exit_edge->src);
+
+  if (!cmp_stmt || gimple_code (cmp_stmt) != GIMPLE_COND)
+    return;
+  cmp_rhs = gimple_cond_rhs (cmp_stmt);
+  cmp_lhs = gimple_cond_lhs (cmp_stmt);
+  if (!TREE_CONSTANT (cmp_rhs)
+      || !(integer_zerop (cmp_rhs) || integer_onep (cmp_rhs)))
+    return;
+  if (TREE_CODE (cmp_lhs) != SSA_NAME)
+    return;
+
+  /* If check_value_one is true, only the phi_args with value '1' will lead
+     to loop exit. Otherwise, only the phi_args with value '0' will lead to
+     loop exit.  */
+  check_value_one = (((integer_onep (cmp_rhs))
+		    ^ (gimple_cond_code (cmp_stmt) == EQ_EXPR))
+		    ^ ((exit_edge->flags & EDGE_TRUE_VALUE) != 0));
+
+  phi_stmt = SSA_NAME_DEF_STMT (cmp_lhs);
+  if (!phi_stmt || gimple_code (phi_stmt) != GIMPLE_PHI)
+    return;
+
+  for (i = 0; i < gimple_phi_num_args (phi_stmt); i++)
+    {
+      edge e1;
+      edge_iterator ei;
+      tree val = gimple_phi_arg_def (phi_stmt, i);
+      edge e = gimple_phi_arg_edge (phi_stmt, i);
+
+      if (!TREE_CONSTANT (val) || !(integer_zerop (val) || integer_onep (val)))
+	continue;
+      if (check_value_one ^ integer_onep (val))
+	continue;
+      if (VEC_length (edge, e->src->succs) != 1)
+	{
+	  if (!predicted_by_p (exit_edge->src, PRED_LOOP_ITERATIONS_GUESSED)
+	      && !predicted_by_p (exit_edge->src, PRED_LOOP_ITERATIONS)
+	      && !predicted_by_p (exit_edge->src, PRED_LOOP_EXIT))
+	    predict_edge_def (e, PRED_LOOP_EXIT, NOT_TAKEN);
+	  continue;
+	}
+
+      FOR_EACH_EDGE (e1, ei, e->src->preds)
+	if (!predicted_by_p (exit_edge->src, PRED_LOOP_ITERATIONS_GUESSED)
+	    && !predicted_by_p (exit_edge->src, PRED_LOOP_ITERATIONS)
+	    && !predicted_by_p (exit_edge->src, PRED_LOOP_EXIT))
+	  predict_edge_def (e1, PRED_LOOP_EXIT, NOT_TAKEN);
+    }
+}
+
 /* Predict edge probabilities by exploiting loop structure.  */

 static void
@@ -1362,6 +1448,7 @@ 

 	  probability = ((REG_BR_PROB_BASE + nitercst / 2) / nitercst);
 	  predict_edge (ex, predictor, probability);
+	  predict_extra_loop_exits (ex);
 	}
       VEC_free (edge, heap, exits);