@@ -98,7 +98,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);
+ NEXT_PASS (pass_strip_predict_hints_early);
POP_INSERT_PASSES ()
NEXT_PASS (pass_release_ssa_names);
NEXT_PASS (pass_rebuild_cgraph_edges);
@@ -3878,44 +3878,27 @@ pass_profile::execute (function *fun)
} // anon namespace
-gimple_opt_pass *
-make_pass_profile (gcc::context *ctxt)
-{
- return new pass_profile (ctxt);
-}
-
-namespace {
-
-const pass_data pass_data_strip_predict_hints =
-{
- GIMPLE_PASS, /* type */
- "*strip_predict_hints", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_BRANCH_PROB, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
+/* Return true when PRED predictor should be removed after early
+ tree passes. */
-class pass_strip_predict_hints : public gimple_opt_pass
+static bool
+strip_predictor_early (enum br_predictor pred)
{
-public:
- pass_strip_predict_hints (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_strip_predict_hints, ctxt)
- {}
-
- /* opt_pass methods: */
- opt_pass * clone () { return new pass_strip_predict_hints (m_ctxt); }
- virtual unsigned int execute (function *);
-
-}; // class pass_strip_predict_hints
+ switch (pred)
+ {
+ case PRED_TREE_EARLY_RETURN:
+ return true;
+ default:
+ return false;
+ }
+}
/* Get rid of all builtin_expect calls and GIMPLE_PREDICT statements
- we no longer need. */
+ we no longer need. EARLY is set to true when called from early
+ optimizations. */
+
unsigned int
-pass_strip_predict_hints::execute (function *fun)
+strip_predict_hints (function *fun, bool early)
{
basic_block bb;
gimple *ass_stmt;
@@ -3931,15 +3914,20 @@ pass_strip_predict_hints::execute (function *fun)
if (gimple_code (stmt) == GIMPLE_PREDICT)
{
- gsi_remove (&bi, true);
- changed = true;
- continue;
+ if (!early
+ || strip_predictor_early (gimple_predict_predictor (stmt)))
+ {
+ gsi_remove (&bi, true);
+ changed = true;
+ continue;
+ }
}
else if (is_gimple_call (stmt))
{
tree fndecl = gimple_call_fndecl (stmt);
- if ((fndecl
+ if ((!early
+ && fndecl
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
&& gimple_call_num_args (stmt) == 2)
@@ -3967,6 +3955,43 @@ pass_strip_predict_hints::execute (function *fun)
return changed ? TODO_cleanup_cfg : 0;
}
+gimple_opt_pass *
+make_pass_profile (gcc::context *ctxt)
+{
+ return new pass_profile (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_strip_predict_hints =
+{
+ GIMPLE_PASS, /* type */
+ "*strip_predict_hints", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_BRANCH_PROB, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_strip_predict_hints : public gimple_opt_pass
+{
+public:
+ pass_strip_predict_hints (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_strip_predict_hints, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ opt_pass * clone () { return new pass_strip_predict_hints (m_ctxt); }
+ virtual unsigned int execute (function *fun)
+ {
+ return strip_predict_hints (fun, false);
+ }
+
+}; // class pass_strip_predict_hints
+
} // anon namespace
gimple_opt_pass *
@@ -3975,6 +4000,45 @@ make_pass_strip_predict_hints (gcc::context *ctxt)
return new pass_strip_predict_hints (ctxt);
}
+namespace {
+
+const pass_data pass_data_strip_predict_hints_early =
+{
+ GIMPLE_PASS, /* type */
+ "*estrip_predict_hints", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_BRANCH_PROB, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_strip_predict_hints_early : public gimple_opt_pass
+{
+public:
+ pass_strip_predict_hints_early (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_strip_predict_hints, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ opt_pass * clone () { return new pass_strip_predict_hints_early (m_ctxt); }
+ virtual unsigned int execute (function *fun)
+ {
+ return strip_predict_hints (fun, true);
+ }
+
+}; // class pass_strip_predict_hints_early
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_strip_predict_hints_early (gcc::context *ctxt)
+{
+ return new pass_strip_predict_hints_early (ctxt);
+}
+
/* Rebuild function frequencies. Passes are in general expected to
maintain profile by hand, however in some cases this is not possible:
for example when inlining several functions with loops freuqencies might run
@@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see
DEF_PREDICTOR (ENUM, NAME, HITRATE)
This macro will be called once for each predictor. The ENUM will
- be of type `enum predictor', and will enumerate all supported
+ be of type `enum br_predictor', and will enumerate all supported
predictors. The order of DEF_PREDICTOR calls is important, as
in the first match combining heuristics, the predictor appearing
first in this file will win.
new file mode 100644
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-profile_estimate" } */
+
+void unlikely();
+void likely();
+
+inline int expect_false(int b) {
+ return __builtin_expect(b, 0);
+}
+
+void inline_func_hint(int b) {
+ if (expect_false(b)) {
+ unlikely();
+ } else {
+ likely();
+ }
+}
+
+/* { dg-final { scan-tree-dump "_builtin_expect heuristics of edge" "profile_estimate"} } */
@@ -405,6 +405,7 @@ extern gimple_opt_pass *make_pass_pre (gcc::context *ctxt);
extern unsigned int tail_merge_optimize (unsigned int);
extern gimple_opt_pass *make_pass_profile (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_strip_predict_hints (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_strip_predict_hints_early (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_complex_O0 (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_complex (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_switch (gcc::context *ctxt);