Hi,

I've updated the patch to invoke predict_extra_loop_exits in the right
place. Attached is the new patch.

Bootstrapped and passed gcc testsuite.

Thanks,
Dehao

Index: testsuite/g++.dg/predict-loop-exit-1.C
===================================================================
--- testsuite/g++.dg/predict-loop-exit-1.C      (revision 0)
+++ 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: testsuite/g++.dg/predict-loop-exit-3.C
===================================================================
--- testsuite/g++.dg/predict-loop-exit-3.C      (revision 0)
+++ 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: testsuite/g++.dg/predict-loop-exit-2.C
===================================================================
--- testsuite/g++.dg/predict-loop-exit-2.C      (revision 0)
+++ 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: predict.c
===================================================================
--- predict.c   (revision 187922)
+++ 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
@@ -1330,6 +1416,8 @@
          int probability;
          enum br_predictor predictor;

+         predict_extra_loop_exits (ex);
+
          if (number_of_iterations_exit (loop, ex, &niter_desc, false))
            niter = niter_desc.niter;
          if (!niter || TREE_CODE (niter_desc.niter) != INTEGER_CST)

Reply via email to