From 7a096965f668c1d2129c70c92e2398227b97eee6 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 10 Aug 2018 11:31:51 +0200 Subject: [PATCH] Strip only selected predictors after early tree passes (PR tree-optimization/85799). 2018-08-10 Martin Liska PR tree-optimization/85799 * passes.def: Add argument for pass_strip_predict_hints. * predict.c (class pass_strip_predict_hints): Add new argument early_p. (strip_predictor_early): New function. (pass_strip_predict_hints::execute): Call the function to strip predictors. (strip_predict_hints): New function. * predict.def: Fix comment. 2018-08-10 Martin Liska PR tree-optimization/85799 * gcc.dg/pr85799.c: New test. From-SVN: r263465 --- gcc/ChangeLog | 12 ++++ gcc/passes.def | 6 +- gcc/predict.c | 100 +++++++++++++++++++++++---------- gcc/predict.def | 2 +- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.dg/pr85799.c | 19 +++++++ 6 files changed, 109 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr85799.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1cebb9c5bef..5edaf2414b6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2018-08-10 Martin Liska + + PR tree-optimization/85799 + * passes.def: Add argument for pass_strip_predict_hints. + * predict.c (class pass_strip_predict_hints): Add new argument + early_p. + (strip_predictor_early): New function. + (pass_strip_predict_hints::execute): Call the function to + strip predictors. + (strip_predict_hints): New function. + * predict.def: Fix comment. + 2018-08-10 Thomas Preud'homme * Makefile.in: Clarify which tm.texi to copy over to assert the diff --git a/gcc/passes.def b/gcc/passes.def index 2a8fbc2efbe..7f4b3479a35 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -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, true /* early_p */); POP_INSERT_PASSES () NEXT_PASS (pass_release_ssa_names); NEXT_PASS (pass_rebuild_cgraph_edges); @@ -183,7 +183,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_remove_cgraph_callee_edges); /* Initial scalar cleanups before alias computation. They ensure memory accesses are not indirect wherever possible. */ - NEXT_PASS (pass_strip_predict_hints); + NEXT_PASS (pass_strip_predict_hints, false /* early_p */); NEXT_PASS (pass_ccp, true /* nonzero_p */); NEXT_PASS (pass_post_ipa_warn); /* After CCP we rewrite no longer addressed locals into SSA @@ -348,7 +348,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_all_optimizations_g); PUSH_INSERT_PASSES_WITHIN (pass_all_optimizations_g) NEXT_PASS (pass_remove_cgraph_callee_edges); - NEXT_PASS (pass_strip_predict_hints); + NEXT_PASS (pass_strip_predict_hints, false /* early_p */); /* Lower remaining pieces of GIMPLE. */ NEXT_PASS (pass_lower_complex); NEXT_PASS (pass_lower_vector_ssa); diff --git a/gcc/predict.c b/gcc/predict.c index 96ae10f1319..abbafdae74a 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -3884,38 +3884,28 @@ make_pass_profile (gcc::context *ctxt) return new pass_profile (ctxt); } -namespace { +/* Return true when PRED predictor should be removed after early + tree passes. Most of the predictors are beneficial to survive + as early inlining can also distribute then into caller's bodies. */ -const pass_data pass_data_strip_predict_hints = +static bool +strip_predictor_early (enum br_predictor pred) { - 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 *); - -}; // 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 +3921,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 +3962,49 @@ pass_strip_predict_hints::execute (function *fun) return changed ? TODO_cleanup_cfg : 0; } +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); } + void set_pass_param (unsigned int n, bool param) + { + gcc_assert (n == 0); + early_p = param; + } + + virtual unsigned int execute (function *); + +private: + bool early_p; + +}; // class pass_strip_predict_hints + +unsigned int +pass_strip_predict_hints::execute (function *fun) +{ + return strip_predict_hints (fun, early_p); +} + } // anon namespace gimple_opt_pass * diff --git a/gcc/predict.def b/gcc/predict.def index 76e6590cc96..c0709aa6473 100644 --- a/gcc/predict.def +++ b/gcc/predict.def @@ -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. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1e915bc1a0a..8a2ed682f65 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2018-08-10 Martin Liska + + PR tree-optimization/85799 + * gcc.dg/pr85799.c: New test. + 2018-08-09 Jeff Law PR middle-end/86897 diff --git a/gcc/testsuite/gcc.dg/pr85799.c b/gcc/testsuite/gcc.dg/pr85799.c new file mode 100644 index 00000000000..0e937857e29 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr85799.c @@ -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"} } */