Commit e59a1c22 by Martin Liska Committed by Martin Liska

Make early return predictor more precise.

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
parent ff9baa5f
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> 2017-06-21 Pierre-Marie de Rodat <derodat@adacore.com>
* dwarf2out.c (gen_decl_die): Remove the guard to skip file-scope * dwarf2out.c (gen_decl_die): Remove the guard to skip file-scope
......
...@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see ...@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see
#include "calls.h" #include "calls.h"
#include "gimple-iterator.h" #include "gimple-iterator.h"
#include "gimple-low.h" #include "gimple-low.h"
#include "predict.h"
#include "gimple-predict.h"
/* The differences between High GIMPLE and Low GIMPLE are the /* The differences between High GIMPLE and Low GIMPLE are the
following: following:
......
...@@ -80,4 +80,12 @@ gimple_build_predict (enum br_predictor predictor, enum prediction outcome) ...@@ -80,4 +80,12 @@ gimple_build_predict (enum br_predictor predictor, enum prediction outcome)
return p; 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 */ #endif /* GCC_GIMPLE_PREDICT_H */
...@@ -1428,6 +1428,20 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) ...@@ -1428,6 +1428,20 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
return GS_ALL_DONE; 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 /* 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 GIMPLE value, it is assigned to a new temporary and the statement is
re-written to return the temporary. re-written to return the temporary.
...@@ -1458,6 +1472,7 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p) ...@@ -1458,6 +1472,7 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p)
|| TREE_CODE (ret_expr) == RESULT_DECL || TREE_CODE (ret_expr) == RESULT_DECL
|| ret_expr == error_mark_node) || ret_expr == error_mark_node)
{ {
maybe_add_early_return_predict_stmt (pre_p);
greturn *ret = gimple_build_return (ret_expr); greturn *ret = gimple_build_return (ret_expr);
gimple_set_no_warning (ret, TREE_NO_WARNING (stmt)); gimple_set_no_warning (ret, TREE_NO_WARNING (stmt));
gimplify_seq_add_stmt (pre_p, ret); gimplify_seq_add_stmt (pre_p, ret);
...@@ -1525,6 +1540,7 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p) ...@@ -1525,6 +1540,7 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p)
gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p); gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p);
maybe_add_early_return_predict_stmt (pre_p);
ret = gimple_build_return (result); ret = gimple_build_return (result);
gimple_set_no_warning (ret, TREE_NO_WARNING (stmt)); gimple_set_no_warning (ret, TREE_NO_WARNING (stmt));
gimplify_seq_add_stmt (pre_p, ret); gimplify_seq_add_stmt (pre_p, ret);
......
...@@ -107,6 +107,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -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 early optimizations again. It is thus good idea to do this
late. */ late. */
NEXT_PASS (pass_split_functions); NEXT_PASS (pass_split_functions);
NEXT_PASS (pass_strip_predict_hints);
POP_INSERT_PASSES () POP_INSERT_PASSES ()
NEXT_PASS (pass_release_ssa_names); NEXT_PASS (pass_release_ssa_names);
NEXT_PASS (pass_rebuild_cgraph_edges); NEXT_PASS (pass_rebuild_cgraph_edges);
......
...@@ -2739,7 +2739,6 @@ tree_estimate_probability_bb (basic_block bb, bool local_only) ...@@ -2739,7 +2739,6 @@ tree_estimate_probability_bb (basic_block bb, bool local_only)
{ {
edge e; edge e;
edge_iterator ei; edge_iterator ei;
gimple *last;
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
{ {
...@@ -2766,46 +2765,6 @@ tree_estimate_probability_bb (basic_block bb, bool local_only) ...@@ -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, /* Look for block we are guarding (ie we dominate it,
but it doesn't postdominate us). */ but it doesn't postdominate us). */
if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun) && e->dest != bb if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun) && e->dest != bb
......
...@@ -128,18 +128,9 @@ DEF_PREDICTOR (PRED_POLYMORPHIC_CALL, "polymorphic call", HITRATE (59), 0) ...@@ -128,18 +128,9 @@ DEF_PREDICTOR (PRED_POLYMORPHIC_CALL, "polymorphic call", HITRATE (59), 0)
indefinitely. */ indefinitely. */
DEF_PREDICTOR (PRED_RECURSIVE_CALL, "recursive call", HITRATE (75), 0) DEF_PREDICTOR (PRED_RECURSIVE_CALL, "recursive call", HITRATE (75), 0)
/* Branch causing function to terminate is probably not taken. /* Branch causing function to terminate is probably not taken. */
FIXME: early return currently predicts code: DEF_PREDICTOR (PRED_TREE_EARLY_RETURN, "early return (on trees)", HITRATE (66),
int foo (int a) 0)
{
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 containing goto is probably not taken. /* Branch containing goto is probably not taken.
FIXME: Currently not used. */ FIXME: Currently not used. */
......
...@@ -421,6 +421,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret) ...@@ -421,6 +421,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
if (gimple_code (stmt) == GIMPLE_LABEL if (gimple_code (stmt) == GIMPLE_LABEL
|| gimple_code (stmt) == GIMPLE_RETURN || gimple_code (stmt) == GIMPLE_RETURN
|| gimple_code (stmt) == GIMPLE_NOP || gimple_code (stmt) == GIMPLE_NOP
|| gimple_code (stmt) == GIMPLE_PREDICT
|| gimple_clobber_p (stmt) || gimple_clobber_p (stmt)
|| is_gimple_debug (stmt)) || is_gimple_debug (stmt))
continue; continue;
...@@ -555,6 +556,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret) ...@@ -555,6 +556,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
if (gimple_code (stmt) == GIMPLE_LABEL if (gimple_code (stmt) == GIMPLE_LABEL
|| gimple_code (stmt) == GIMPLE_NOP || gimple_code (stmt) == GIMPLE_NOP
|| gimple_code (stmt) == GIMPLE_PREDICT
|| gimple_clobber_p (stmt) || gimple_clobber_p (stmt)
|| is_gimple_debug (stmt)) || is_gimple_debug (stmt))
continue; continue;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment