+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
#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:
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 */
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.
|| 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);
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);
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);
{
edge e;
edge_iterator ei;
- gimple *last;
FOR_EACH_EDGE (e, ei, bb->succs)
{
}
}
- /* 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
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. */
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;
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;