Make early return predictor more precise.
authorMartin Liska <mliska@suse.cz>
Wed, 21 Jun 2017 12:51:46 +0000 (14:51 +0200)
committerMartin Liska <marxin@gcc.gnu.org>
Wed, 21 Jun 2017 12:51:46 +0000 (12:51 +0000)
2017-06-21  Martin Liska  <mliska@suse.cz>

PR tree-optimization/79489
* gimplify.c (maybe_add_early_return_predict_stmt): New
function.
(gimplify_return_expr): Call the function.
* predict.c (tree_estimate_probability_bb): Remove handling
of early return.
* predict.def: Update comment about early return predictor.
* gimple-predict.h (is_gimple_predict): New function.
* predict.def: Change default value of early return to 66.
* tree-tailcall.c (find_tail_calls): Skip GIMPLE_PREDICT
statements.
* passes.def: Put pass_strip_predict_hints to the beginning of
IPA passes.

From-SVN: r249450

gcc/ChangeLog
gcc/gimple-low.c
gcc/gimple-predict.h
gcc/gimplify.c
gcc/passes.def
gcc/predict.c
gcc/predict.def
gcc/tree-tailcall.c

index 0926a49..12d0ee8 100644 (file)
@@ -1,3 +1,19 @@
+2017-06-21  Martin Liska  <mliska@suse.cz>
+
+       PR tree-optimization/79489
+       * gimplify.c (maybe_add_early_return_predict_stmt): New
+       function.
+       (gimplify_return_expr): Call the function.
+       * predict.c (tree_estimate_probability_bb): Remove handling
+       of early return.
+       * predict.def: Update comment about early return predictor.
+       * gimple-predict.h (is_gimple_predict): New function.
+       * predict.def: Change default value of early return to 66.
+       * tree-tailcall.c (find_tail_calls): Skip GIMPLE_PREDICT
+       statements.
+       * passes.def: Put pass_strip_predict_hints to the beginning of
+       IPA passes.
+
 2017-06-21  Pierre-Marie de Rodat  <derodat@adacore.com>
 
        * dwarf2out.c (gen_decl_die): Remove the guard to skip file-scope
index 619b9d7..4ea6c35 100644 (file)
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "calls.h"
 #include "gimple-iterator.h"
 #include "gimple-low.h"
+#include "predict.h"
+#include "gimple-predict.h"
 
 /* The differences between High GIMPLE and Low GIMPLE are the
    following:
index ba58e12..0e6c2e1 100644 (file)
@@ -80,4 +80,12 @@ gimple_build_predict (enum br_predictor predictor, enum prediction outcome)
   return p;
 }
 
+/* Return true if GS is a GIMPLE_PREDICT statement.  */
+
+static inline bool
+is_gimple_predict (const gimple *gs)
+{
+  return gimple_code (gs) == GIMPLE_PREDICT;
+}
+
 #endif  /* GCC_GIMPLE_PREDICT_H */
index 13760c0..c645bce 100644 (file)
@@ -1428,6 +1428,20 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
   return GS_ALL_DONE;
 }
 
+/* Maybe add early return predict statement to PRE_P sequence.  */
+
+static void
+maybe_add_early_return_predict_stmt (gimple_seq *pre_p)
+{
+  /* If we are not in a conditional context, add PREDICT statement.  */
+  if (gimple_conditional_context ())
+    {
+      gimple *predict = gimple_build_predict (PRED_TREE_EARLY_RETURN,
+                                             NOT_TAKEN);
+      gimplify_seq_add_stmt (pre_p, predict);
+    }
+}
+
 /* Gimplify a RETURN_EXPR.  If the expression to be returned is not a
    GIMPLE value, it is assigned to a new temporary and the statement is
    re-written to return the temporary.
@@ -1458,6 +1472,7 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p)
       || TREE_CODE (ret_expr) == RESULT_DECL
       || ret_expr == error_mark_node)
     {
+      maybe_add_early_return_predict_stmt (pre_p);
       greturn *ret = gimple_build_return (ret_expr);
       gimple_set_no_warning (ret, TREE_NO_WARNING (stmt));
       gimplify_seq_add_stmt (pre_p, ret);
@@ -1525,6 +1540,7 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p)
 
   gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p);
 
+  maybe_add_early_return_predict_stmt (pre_p);
   ret = gimple_build_return (result);
   gimple_set_no_warning (ret, TREE_NO_WARNING (stmt));
   gimplify_seq_add_stmt (pre_p, ret);
index c14f6b9..316e19d 100644 (file)
@@ -107,6 +107,7 @@ along with GCC; see the file COPYING3.  If not see
             early optimizations again.  It is thus good idea to do this
              late.  */
          NEXT_PASS (pass_split_functions);
+         NEXT_PASS (pass_strip_predict_hints);
       POP_INSERT_PASSES ()
       NEXT_PASS (pass_release_ssa_names);
       NEXT_PASS (pass_rebuild_cgraph_edges);
index 60d1a09..790be9f 100644 (file)
@@ -2739,7 +2739,6 @@ tree_estimate_probability_bb (basic_block bb, bool local_only)
 {
   edge e;
   edge_iterator ei;
-  gimple *last;
 
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
@@ -2766,46 +2765,6 @@ tree_estimate_probability_bb (basic_block bb, bool local_only)
            }
        }
 
-      /* Predict early returns to be probable, as we've already taken
-        care for error returns and other cases are often used for
-        fast paths through function.
-
-        Since we've already removed the return statements, we are
-        looking for CFG like:
-
-        if (conditional)
-        {
-        ..
-        goto return_block
-        }
-        some other blocks
-        return_block:
-        return_stmt.  */
-      if (e->dest != bb->next_bb
-         && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
-         && single_succ_p (e->dest)
-         && single_succ_edge (e->dest)->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)
-         && (last = last_stmt (e->dest)) != NULL
-         && gimple_code (last) == GIMPLE_RETURN)
-       {
-         edge e1;
-         edge_iterator ei1;
-
-         if (single_succ_p (bb))
-           {
-             FOR_EACH_EDGE (e1, ei1, bb->preds)
-               if (!predicted_by_p (e1->src, PRED_NULL_RETURN)
-                   && !predicted_by_p (e1->src, PRED_CONST_RETURN)
-                   && !predicted_by_p (e1->src, PRED_NEGATIVE_RETURN))
-                 predict_edge_def (e1, PRED_TREE_EARLY_RETURN, NOT_TAKEN);
-           }
-         else
-           if (!predicted_by_p (e->src, PRED_NULL_RETURN)
-               && !predicted_by_p (e->src, PRED_CONST_RETURN)
-               && !predicted_by_p (e->src, PRED_NEGATIVE_RETURN))
-             predict_edge_def (e, PRED_TREE_EARLY_RETURN, NOT_TAKEN);
-       }
-
       /* Look for block we are guarding (ie we dominate it,
         but it doesn't postdominate us).  */
       if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun) && e->dest != bb
index fcda6c4..f7b2bf7 100644 (file)
@@ -128,18 +128,9 @@ DEF_PREDICTOR (PRED_POLYMORPHIC_CALL, "polymorphic call", HITRATE (59), 0)
    indefinitely.  */
 DEF_PREDICTOR (PRED_RECURSIVE_CALL, "recursive call", HITRATE (75), 0)
 
-/* Branch causing function to terminate is probably not taken. 
-   FIXME: early return currently predicts code:
-   int foo (int a)
-   {
-      if (a)
-       bar();
-      else
-       bar2();
-   }
-   even though there is no return statement involved.  We probably want to track
-   this from FE or retire the predictor.  */
-DEF_PREDICTOR (PRED_TREE_EARLY_RETURN, "early return (on trees)", HITRATE (54), 0)
+/* Branch causing function to terminate is probably not taken.  */
+DEF_PREDICTOR (PRED_TREE_EARLY_RETURN, "early return (on trees)", HITRATE (66),
+              0)
 
 /* Branch containing goto is probably not taken.
    FIXME: Currently not used.  */
index b705338..6aa9a56 100644 (file)
@@ -421,6 +421,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
       if (gimple_code (stmt) == GIMPLE_LABEL
          || gimple_code (stmt) == GIMPLE_RETURN
          || gimple_code (stmt) == GIMPLE_NOP
+         || gimple_code (stmt) == GIMPLE_PREDICT
          || gimple_clobber_p (stmt)
          || is_gimple_debug (stmt))
        continue;
@@ -555,6 +556,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
 
       if (gimple_code (stmt) == GIMPLE_LABEL
          || gimple_code (stmt) == GIMPLE_NOP
+         || gimple_code (stmt) == GIMPLE_PREDICT
          || gimple_clobber_p (stmt)
          || is_gimple_debug (stmt))
        continue;