Commit 1e9168b2 by Martin Liska Committed by Martin Liska

Introduce __builtin_expect_with_probability (PR target/83610).

2018-08-10  Martin Liska  <mliska@suse.cz>

        PR target/83610
	* builtin-types.def (BT_FN_LONG_LONG_LONG_DOUBLE): Add new
        function type.
	* builtins.c (expand_builtin_expect_with_probability):
        New function.
	(expand_builtin_expect_with_probability): New function.
	(build_builtin_expect_predicate): Add new argumnet probability
        for BUILT_IN_EXPECT_WITH_PROBABILITY.
	(fold_builtin_expect):
	(fold_builtin_2):
	(fold_builtin_3):
	* builtins.def (BUILT_IN_EXPECT_WITH_PROBABILITY):
	* builtins.h (fold_builtin_expect): Set new argument.
	* doc/extend.texi: Document __builtin_expect_with_probability.
	* doc/invoke.texi: Likewise.
	* gimple-fold.c (gimple_fold_call): Pass new argument.
	* ipa-fnsummary.c (find_foldable_builtin_expect): Handle
        also BUILT_IN_EXPECT_WITH_PROBABILITY.
	* predict.c (get_predictor_value): New function.
	(expr_expected_value): Add new argument probability. Assume
        that predictor and probability are always non-null.
	(expr_expected_value_1): Likewise.  For __builtin_expect and
        __builtin_expect_with_probability set probability.  Handle
        combination in binary expressions.
	(tree_predict_by_opcode): Simplify code by simply calling
        get_predictor_value.
	(pass_strip_predict_hints::execute): Add handling of
        BUILT_IN_EXPECT_WITH_PROBABILITY.
	* predict.def (PRED_BUILTIN_EXPECT_WITH_PROBABILITY): Add
        new predictor.
	* tree.h (DECL_BUILT_IN_P): New function.
2018-08-10  Martin Liska  <mliska@suse.cz>

        PR target/83610
	* gcc.dg/predict-17.c: New test.
	* gcc.dg/predict-18.c: New test.
	* gcc.dg/predict-19.c: New test.

From-SVN: r263466
parent 7a096965
2018-08-10 Martin Liska <mliska@suse.cz> 2018-08-10 Martin Liska <mliska@suse.cz>
PR target/83610
* builtin-types.def (BT_FN_LONG_LONG_LONG_DOUBLE): Add new
function type.
* builtins.c (expand_builtin_expect_with_probability):
New function.
(expand_builtin_expect_with_probability): New function.
(build_builtin_expect_predicate): Add new argumnet probability
for BUILT_IN_EXPECT_WITH_PROBABILITY.
(fold_builtin_expect):
(fold_builtin_2):
(fold_builtin_3):
* builtins.def (BUILT_IN_EXPECT_WITH_PROBABILITY):
* builtins.h (fold_builtin_expect): Set new argument.
* doc/extend.texi: Document __builtin_expect_with_probability.
* doc/invoke.texi: Likewise.
* gimple-fold.c (gimple_fold_call): Pass new argument.
* ipa-fnsummary.c (find_foldable_builtin_expect): Handle
also BUILT_IN_EXPECT_WITH_PROBABILITY.
* predict.c (get_predictor_value): New function.
(expr_expected_value): Add new argument probability. Assume
that predictor and probability are always non-null.
(expr_expected_value_1): Likewise. For __builtin_expect and
__builtin_expect_with_probability set probability. Handle
combination in binary expressions.
(tree_predict_by_opcode): Simplify code by simply calling
get_predictor_value.
(pass_strip_predict_hints::execute): Add handling of
BUILT_IN_EXPECT_WITH_PROBABILITY.
* predict.def (PRED_BUILTIN_EXPECT_WITH_PROBABILITY): Add
new predictor.
* tree.h (DECL_BUILT_IN_P): New function.
2018-08-10 Martin Liska <mliska@suse.cz>
PR tree-optimization/85799 PR tree-optimization/85799
* passes.def: Add argument for pass_strip_predict_hints. * passes.def: Add argument for pass_strip_predict_hints.
* predict.c (class pass_strip_predict_hints): Add new argument * predict.c (class pass_strip_predict_hints): Add new argument
......
...@@ -531,6 +531,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_ULONG_ULONG_ULONG_ULONG, ...@@ -531,6 +531,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_ULONG_ULONG_ULONG_ULONG,
BT_ULONG, BT_ULONG, BT_ULONG, BT_ULONG) BT_ULONG, BT_ULONG, BT_ULONG, BT_ULONG)
DEF_FUNCTION_TYPE_3 (BT_FN_LONG_LONG_UINT_UINT, DEF_FUNCTION_TYPE_3 (BT_FN_LONG_LONG_UINT_UINT,
BT_LONG, BT_LONG, BT_UINT, BT_UINT) BT_LONG, BT_LONG, BT_UINT, BT_UINT)
DEF_FUNCTION_TYPE_3 (BT_FN_LONG_LONG_LONG_DOUBLE,
BT_LONG, BT_LONG, BT_LONG, BT_DOUBLE)
DEF_FUNCTION_TYPE_3 (BT_FN_ULONG_ULONG_UINT_UINT, DEF_FUNCTION_TYPE_3 (BT_FN_ULONG_ULONG_UINT_UINT,
BT_ULONG, BT_ULONG, BT_UINT, BT_UINT) BT_ULONG, BT_ULONG, BT_UINT, BT_UINT)
DEF_FUNCTION_TYPE_3 (BT_FN_STRING_CONST_STRING_CONST_STRING_INT, DEF_FUNCTION_TYPE_3 (BT_FN_STRING_CONST_STRING_CONST_STRING_INT,
......
...@@ -148,6 +148,7 @@ static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab); ...@@ -148,6 +148,7 @@ static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
static rtx expand_builtin_frame_address (tree, tree); static rtx expand_builtin_frame_address (tree, tree);
static tree stabilize_va_list_loc (location_t, tree, int); static tree stabilize_va_list_loc (location_t, tree, int);
static rtx expand_builtin_expect (tree, rtx); static rtx expand_builtin_expect (tree, rtx);
static rtx expand_builtin_expect_with_probability (tree, rtx);
static tree fold_builtin_constant_p (tree); static tree fold_builtin_constant_p (tree);
static tree fold_builtin_classify_type (tree); static tree fold_builtin_classify_type (tree);
static tree fold_builtin_strlen (location_t, tree, tree); static tree fold_builtin_strlen (location_t, tree, tree);
...@@ -5251,6 +5252,27 @@ expand_builtin_expect (tree exp, rtx target) ...@@ -5251,6 +5252,27 @@ expand_builtin_expect (tree exp, rtx target)
return target; return target;
} }
/* Expand a call to __builtin_expect_with_probability. We just return our
argument as the builtin_expect semantic should've been already executed by
tree branch prediction pass. */
static rtx
expand_builtin_expect_with_probability (tree exp, rtx target)
{
tree arg;
if (call_expr_nargs (exp) < 3)
return const0_rtx;
arg = CALL_EXPR_ARG (exp, 0);
target = expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
/* When guessing was done, the hints should be already stripped away. */
gcc_assert (!flag_guess_branch_prob
|| optimize == 0 || seen_error ());
return target;
}
/* Expand a call to __builtin_assume_aligned. We just return our first /* Expand a call to __builtin_assume_aligned. We just return our first
argument as the builtin_assume_aligned semantic should've been already argument as the builtin_assume_aligned semantic should've been already
executed by CCP. */ executed by CCP. */
...@@ -7562,6 +7584,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, ...@@ -7562,6 +7584,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
return expand_builtin_va_copy (exp); return expand_builtin_va_copy (exp);
case BUILT_IN_EXPECT: case BUILT_IN_EXPECT:
return expand_builtin_expect (exp, target); return expand_builtin_expect (exp, target);
case BUILT_IN_EXPECT_WITH_PROBABILITY:
return expand_builtin_expect_with_probability (exp, target);
case BUILT_IN_ASSUME_ALIGNED: case BUILT_IN_ASSUME_ALIGNED:
return expand_builtin_assume_aligned (exp, target); return expand_builtin_assume_aligned (exp, target);
case BUILT_IN_PREFETCH: case BUILT_IN_PREFETCH:
...@@ -8213,16 +8237,20 @@ fold_builtin_constant_p (tree arg) ...@@ -8213,16 +8237,20 @@ fold_builtin_constant_p (tree arg)
return NULL_TREE; return NULL_TREE;
} }
/* Create builtin_expect with PRED and EXPECTED as its arguments and /* Create builtin_expect or builtin_expect_with_probability
return it as a truthvalue. */ with PRED and EXPECTED as its arguments and return it as a truthvalue.
Fortran FE can also produce builtin_expect with PREDICTOR as third argument.
builtin_expect_with_probability instead uses third argument as PROBABILITY
value. */
static tree static tree
build_builtin_expect_predicate (location_t loc, tree pred, tree expected, build_builtin_expect_predicate (location_t loc, tree pred, tree expected,
tree predictor) tree predictor, tree probability)
{ {
tree fn, arg_types, pred_type, expected_type, call_expr, ret_type; tree fn, arg_types, pred_type, expected_type, call_expr, ret_type;
fn = builtin_decl_explicit (BUILT_IN_EXPECT); fn = builtin_decl_explicit (probability == NULL_TREE ? BUILT_IN_EXPECT
: BUILT_IN_EXPECT_WITH_PROBABILITY);
arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
ret_type = TREE_TYPE (TREE_TYPE (fn)); ret_type = TREE_TYPE (TREE_TYPE (fn));
pred_type = TREE_VALUE (arg_types); pred_type = TREE_VALUE (arg_types);
...@@ -8230,18 +8258,23 @@ build_builtin_expect_predicate (location_t loc, tree pred, tree expected, ...@@ -8230,18 +8258,23 @@ build_builtin_expect_predicate (location_t loc, tree pred, tree expected,
pred = fold_convert_loc (loc, pred_type, pred); pred = fold_convert_loc (loc, pred_type, pred);
expected = fold_convert_loc (loc, expected_type, expected); expected = fold_convert_loc (loc, expected_type, expected);
call_expr = build_call_expr_loc (loc, fn, predictor ? 3 : 2, pred, expected,
predictor); if (probability)
call_expr = build_call_expr_loc (loc, fn, 3, pred, expected, probability);
else
call_expr = build_call_expr_loc (loc, fn, predictor ? 3 : 2, pred, expected,
predictor);
return build2 (NE_EXPR, TREE_TYPE (pred), call_expr, return build2 (NE_EXPR, TREE_TYPE (pred), call_expr,
build_int_cst (ret_type, 0)); build_int_cst (ret_type, 0));
} }
/* Fold a call to builtin_expect with arguments ARG0 and ARG1. Return /* Fold a call to builtin_expect with arguments ARG0, ARG1, ARG2, ARG3. Return
NULL_TREE if no simplification is possible. */ NULL_TREE if no simplification is possible. */
tree tree
fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2) fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2,
tree arg3)
{ {
tree inner, fndecl, inner_arg0; tree inner, fndecl, inner_arg0;
enum tree_code code; enum tree_code code;
...@@ -8265,8 +8298,9 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2) ...@@ -8265,8 +8298,9 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
if (TREE_CODE (inner) == CALL_EXPR if (TREE_CODE (inner) == CALL_EXPR
&& (fndecl = get_callee_fndecl (inner)) && (fndecl = get_callee_fndecl (inner))
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL && (DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL, BUILT_IN_EXPECT)
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT) || DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL,
BUILT_IN_EXPECT_WITH_PROBABILITY)))
return arg0; return arg0;
inner = inner_arg0; inner = inner_arg0;
...@@ -8277,8 +8311,8 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2) ...@@ -8277,8 +8311,8 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
tree op1 = TREE_OPERAND (inner, 1); tree op1 = TREE_OPERAND (inner, 1);
arg1 = save_expr (arg1); arg1 = save_expr (arg1);
op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2); op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2, arg3);
op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2); op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2, arg3);
inner = build2 (code, TREE_TYPE (inner), op0, op1); inner = build2 (code, TREE_TYPE (inner), op0, op1);
return fold_convert_loc (loc, TREE_TYPE (arg0), inner); return fold_convert_loc (loc, TREE_TYPE (arg0), inner);
...@@ -9374,7 +9408,7 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1) ...@@ -9374,7 +9408,7 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
return fold_builtin_strpbrk (loc, arg0, arg1, type); return fold_builtin_strpbrk (loc, arg0, arg1, type);
case BUILT_IN_EXPECT: case BUILT_IN_EXPECT:
return fold_builtin_expect (loc, arg0, arg1, NULL_TREE); return fold_builtin_expect (loc, arg0, arg1, NULL_TREE, NULL_TREE);
case BUILT_IN_ISGREATER: case BUILT_IN_ISGREATER:
return fold_builtin_unordered_cmp (loc, fndecl, return fold_builtin_unordered_cmp (loc, fndecl,
...@@ -9452,7 +9486,10 @@ fold_builtin_3 (location_t loc, tree fndecl, ...@@ -9452,7 +9486,10 @@ fold_builtin_3 (location_t loc, tree fndecl,
return fold_builtin_memcmp (loc, arg0, arg1, arg2); return fold_builtin_memcmp (loc, arg0, arg1, arg2);
case BUILT_IN_EXPECT: case BUILT_IN_EXPECT:
return fold_builtin_expect (loc, arg0, arg1, arg2); return fold_builtin_expect (loc, arg0, arg1, arg2, NULL_TREE);
case BUILT_IN_EXPECT_WITH_PROBABILITY:
return fold_builtin_expect (loc, arg0, arg1, NULL_TREE, arg2);
case BUILT_IN_ADD_OVERFLOW: case BUILT_IN_ADD_OVERFLOW:
case BUILT_IN_SUB_OVERFLOW: case BUILT_IN_SUB_OVERFLOW:
......
...@@ -848,6 +848,7 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECVP, "execvp", BT_FN_INT_CONST_STRING_PT ...@@ -848,6 +848,7 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECVP, "execvp", BT_FN_INT_CONST_STRING_PT
DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECVE, "execve", BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECVE, "execve", BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST)
DEF_LIB_BUILTIN (BUILT_IN_EXIT, "exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LIST) DEF_LIB_BUILTIN (BUILT_IN_EXIT, "exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_EXPECT, "expect", BT_FN_LONG_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GCC_BUILTIN (BUILT_IN_EXPECT, "expect", BT_FN_LONG_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_EXPECT_WITH_PROBABILITY, "expect_with_probability", BT_FN_LONG_LONG_LONG_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_ASSUME_ALIGNED, "assume_aligned", BT_FN_PTR_CONST_PTR_SIZE_VAR, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GCC_BUILTIN (BUILT_IN_ASSUME_ALIGNED, "assume_aligned", BT_FN_PTR_CONST_PTR_SIZE_VAR, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_EXTEND_POINTER, "extend_pointer", BT_FN_UNWINDWORD_PTR, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GCC_BUILTIN (BUILT_IN_EXTEND_POINTER, "extend_pointer", BT_FN_UNWINDWORD_PTR, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_EXTRACT_RETURN_ADDR, "extract_return_addr", BT_FN_PTR_PTR, ATTR_LEAF_LIST) DEF_GCC_BUILTIN (BUILT_IN_EXTRACT_RETURN_ADDR, "extract_return_addr", BT_FN_PTR_PTR, ATTR_LEAF_LIST)
......
...@@ -77,7 +77,7 @@ extern void expand_ifn_atomic_compare_exchange (gcall *); ...@@ -77,7 +77,7 @@ extern void expand_ifn_atomic_compare_exchange (gcall *);
extern rtx expand_builtin (tree, rtx, rtx, machine_mode, int); extern rtx expand_builtin (tree, rtx, rtx, machine_mode, int);
extern rtx expand_builtin_with_bounds (tree, rtx, rtx, machine_mode, int); extern rtx expand_builtin_with_bounds (tree, rtx, rtx, machine_mode, int);
extern enum built_in_function builtin_mathfn_code (const_tree); extern enum built_in_function builtin_mathfn_code (const_tree);
extern tree fold_builtin_expect (location_t, tree, tree, tree); extern tree fold_builtin_expect (location_t, tree, tree, tree, tree);
extern bool avoid_folding_inline_builtin (tree); extern bool avoid_folding_inline_builtin (tree);
extern tree fold_call_expr (location_t, tree, bool); extern tree fold_call_expr (location_t, tree, bool);
extern tree fold_builtin_call_array (location_t, tree, tree, int, tree *); extern tree fold_builtin_call_array (location_t, tree, tree, int, tree *);
......
...@@ -11956,6 +11956,15 @@ if (__builtin_expect (ptr != NULL, 1)) ...@@ -11956,6 +11956,15 @@ if (__builtin_expect (ptr != NULL, 1))
when testing pointer or floating-point values. when testing pointer or floating-point values.
@end deftypefn @end deftypefn
@deftypefn {Built-in Function} long __builtin_expect_with_probability
(long @var{exp}, long @var{c}, long @var{probability})
The built-in has same semantics as @code{__builtin_expect_with_probability},
but user can provide expected probability (in percent) for value of @var{exp}.
Last argument @var{probability} is of float type and valid values
are in inclusive range 0.0f and 1.0f.
@end deftypefn
@deftypefn {Built-in Function} void __builtin_trap (void) @deftypefn {Built-in Function} void __builtin_trap (void)
This function causes the program to exit abnormally. GCC implements This function causes the program to exit abnormally. GCC implements
this function by using a target-dependent mechanism (such as this function by using a target-dependent mechanism (such as
......
...@@ -9218,6 +9218,9 @@ between the heuristics and @code{__builtin_expect} can be complex, and in ...@@ -9218,6 +9218,9 @@ between the heuristics and @code{__builtin_expect} can be complex, and in
some cases, it may be useful to disable the heuristics so that the effects some cases, it may be useful to disable the heuristics so that the effects
of @code{__builtin_expect} are easier to understand. of @code{__builtin_expect} are easier to understand.
It is also possible to specify expected probability of the expression
with @code{__builtin_expect_with_probability} built-in function.
The default is @option{-fguess-branch-probability} at levels The default is @option{-fguess-branch-probability} at levels
@option{-O}, @option{-O2}, @option{-O3}, @option{-Os}. @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}.
...@@ -4155,7 +4155,8 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) ...@@ -4155,7 +4155,8 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
result = fold_builtin_expect (gimple_location (stmt), result = fold_builtin_expect (gimple_location (stmt),
gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 0),
gimple_call_arg (stmt, 1), gimple_call_arg (stmt, 1),
gimple_call_arg (stmt, 2)); gimple_call_arg (stmt, 2),
NULL_TREE);
break; break;
case IFN_UBSAN_OBJECT_SIZE: case IFN_UBSAN_OBJECT_SIZE:
{ {
......
...@@ -1851,6 +1851,7 @@ find_foldable_builtin_expect (basic_block bb) ...@@ -1851,6 +1851,7 @@ find_foldable_builtin_expect (basic_block bb)
{ {
gimple *stmt = gsi_stmt (bsi); gimple *stmt = gsi_stmt (bsi);
if (gimple_call_builtin_p (stmt, BUILT_IN_EXPECT) if (gimple_call_builtin_p (stmt, BUILT_IN_EXPECT)
|| gimple_call_builtin_p (stmt, BUILT_IN_EXPECT_WITH_PROBABILITY)
|| gimple_call_internal_p (stmt, IFN_BUILTIN_EXPECT)) || gimple_call_internal_p (stmt, IFN_BUILTIN_EXPECT))
{ {
tree var = gimple_call_lhs (stmt); tree var = gimple_call_lhs (stmt);
......
...@@ -92,6 +92,7 @@ static void predict_paths_leading_to_edge (edge, enum br_predictor, ...@@ -92,6 +92,7 @@ static void predict_paths_leading_to_edge (edge, enum br_predictor,
enum prediction, enum prediction,
struct loop *in_loop = NULL); struct loop *in_loop = NULL);
static bool can_predict_insn_p (const rtx_insn *); static bool can_predict_insn_p (const rtx_insn *);
static HOST_WIDE_INT get_predictor_value (br_predictor, HOST_WIDE_INT);
/* Information we hold about each branch predictor. /* Information we hold about each branch predictor.
Filled using information from predict.def. */ Filled using information from predict.def. */
...@@ -2262,18 +2263,21 @@ guess_outgoing_edge_probabilities (basic_block bb) ...@@ -2262,18 +2263,21 @@ guess_outgoing_edge_probabilities (basic_block bb)
combine_predictions_for_insn (BB_END (bb), bb); combine_predictions_for_insn (BB_END (bb), bb);
} }
static tree expr_expected_value (tree, bitmap, enum br_predictor *predictor); static tree expr_expected_value (tree, bitmap, enum br_predictor *predictor,
HOST_WIDE_INT *probability);
/* Helper function for expr_expected_value. */ /* Helper function for expr_expected_value. */
static tree static tree
expr_expected_value_1 (tree type, tree op0, enum tree_code code, expr_expected_value_1 (tree type, tree op0, enum tree_code code,
tree op1, bitmap visited, enum br_predictor *predictor) tree op1, bitmap visited, enum br_predictor *predictor,
HOST_WIDE_INT *probability)
{ {
gimple *def; gimple *def;
if (predictor) /* Reset returned probability value. */
*predictor = PRED_UNCONDITIONAL; *probability = -1;
*predictor = PRED_UNCONDITIONAL;
if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS) if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS)
{ {
...@@ -2292,8 +2296,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, ...@@ -2292,8 +2296,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
{ {
/* Assume that any given atomic operation has low contention, /* Assume that any given atomic operation has low contention,
and thus the compare-and-swap operation succeeds. */ and thus the compare-and-swap operation succeeds. */
if (predictor) *predictor = PRED_COMPARE_AND_SWAP;
*predictor = PRED_COMPARE_AND_SWAP;
return build_one_cst (TREE_TYPE (op0)); return build_one_cst (TREE_TYPE (op0));
} }
} }
...@@ -2329,11 +2332,12 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, ...@@ -2329,11 +2332,12 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
if (arg == PHI_RESULT (def)) if (arg == PHI_RESULT (def))
continue; continue;
new_val = expr_expected_value (arg, visited, &predictor2); new_val = expr_expected_value (arg, visited, &predictor2,
probability);
/* It is difficult to combine value predictors. Simply assume /* It is difficult to combine value predictors. Simply assume
that later predictor is weaker and take its prediction. */ that later predictor is weaker and take its prediction. */
if (predictor && *predictor < predictor2) if (*predictor < predictor2)
*predictor = predictor2; *predictor = predictor2;
if (!new_val) if (!new_val)
return NULL; return NULL;
...@@ -2353,7 +2357,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, ...@@ -2353,7 +2357,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
gimple_assign_rhs1 (def), gimple_assign_rhs1 (def),
gimple_assign_rhs_code (def), gimple_assign_rhs_code (def),
gimple_assign_rhs2 (def), gimple_assign_rhs2 (def),
visited, predictor); visited, predictor, probability);
} }
if (is_gimple_call (def)) if (is_gimple_call (def))
...@@ -2368,14 +2372,14 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, ...@@ -2368,14 +2372,14 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
tree val = gimple_call_arg (def, 0); tree val = gimple_call_arg (def, 0);
if (TREE_CONSTANT (val)) if (TREE_CONSTANT (val))
return val; return val;
if (predictor) tree val2 = gimple_call_arg (def, 2);
{ gcc_assert (TREE_CODE (val2) == INTEGER_CST
tree val2 = gimple_call_arg (def, 2); && tree_fits_uhwi_p (val2)
gcc_assert (TREE_CODE (val2) == INTEGER_CST && tree_to_uhwi (val2) < END_PREDICTORS);
&& tree_fits_uhwi_p (val2) *predictor = (enum br_predictor) tree_to_uhwi (val2);
&& tree_to_uhwi (val2) < END_PREDICTORS); if (*predictor == PRED_BUILTIN_EXPECT)
*predictor = (enum br_predictor) tree_to_uhwi (val2); *probability
} = HITRATE (PARAM_VALUE (BUILTIN_EXPECT_PROBABILITY));
return gimple_call_arg (def, 1); return gimple_call_arg (def, 1);
} }
return NULL; return NULL;
...@@ -2399,8 +2403,34 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, ...@@ -2399,8 +2403,34 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
val = gimple_call_arg (def, 0); val = gimple_call_arg (def, 0);
if (TREE_CONSTANT (val)) if (TREE_CONSTANT (val))
return val; return val;
if (predictor) *predictor = PRED_BUILTIN_EXPECT;
*predictor = PRED_BUILTIN_EXPECT; *probability
= HITRATE (PARAM_VALUE (BUILTIN_EXPECT_PROBABILITY));
return gimple_call_arg (def, 1);
}
case BUILT_IN_EXPECT_WITH_PROBABILITY:
{
tree val;
if (gimple_call_num_args (def) != 3)
return NULL;
val = gimple_call_arg (def, 0);
if (TREE_CONSTANT (val))
return val;
/* Compute final probability as:
probability * REG_BR_PROB_BASE. */
tree prob = gimple_call_arg (def, 2);
tree t = TREE_TYPE (prob);
tree base = build_int_cst (integer_type_node,
REG_BR_PROB_BASE);
base = build_real_from_int_cst (t, base);
tree r = fold_build2 (MULT_EXPR, t, prob, base);
HOST_WIDE_INT probi
= real_to_integer (TREE_REAL_CST_PTR (r));
if (probi >= 0 && probi <= REG_BR_PROB_BASE)
{
*predictor = PRED_BUILTIN_EXPECT_WITH_PROBABILITY;
*probability = probi;
}
return gimple_call_arg (def, 1); return gimple_call_arg (def, 1);
} }
...@@ -2419,8 +2449,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, ...@@ -2419,8 +2449,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16: case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
/* Assume that any given atomic operation has low contention, /* Assume that any given atomic operation has low contention,
and thus the compare-and-swap operation succeeds. */ and thus the compare-and-swap operation succeeds. */
if (predictor) *predictor = PRED_COMPARE_AND_SWAP;
*predictor = PRED_COMPARE_AND_SWAP;
return boolean_true_node; return boolean_true_node;
case BUILT_IN_REALLOC: case BUILT_IN_REALLOC:
if (predictor) if (predictor)
...@@ -2438,23 +2467,37 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, ...@@ -2438,23 +2467,37 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
{ {
tree res; tree res;
enum br_predictor predictor2; enum br_predictor predictor2;
op0 = expr_expected_value (op0, visited, predictor); HOST_WIDE_INT probability2;
op0 = expr_expected_value (op0, visited, predictor, probability);
if (!op0) if (!op0)
return NULL; return NULL;
op1 = expr_expected_value (op1, visited, &predictor2); op1 = expr_expected_value (op1, visited, &predictor2, &probability2);
if (predictor && *predictor < predictor2)
*predictor = predictor2;
if (!op1) if (!op1)
return NULL; return NULL;
res = fold_build2 (code, type, op0, op1); res = fold_build2 (code, type, op0, op1);
if (TREE_CONSTANT (res)) if (TREE_CODE (res) == INTEGER_CST
return res; && TREE_CODE (op0) == INTEGER_CST
&& TREE_CODE (op1) == INTEGER_CST)
{
/* Combine binary predictions. */
if (*probability != -1 || probability2 != -1)
{
HOST_WIDE_INT p1 = get_predictor_value (*predictor, *probability);
HOST_WIDE_INT p2 = get_predictor_value (predictor2, probability2);
*probability = RDIV (p1 * p2, REG_BR_PROB_BASE);
}
if (*predictor < predictor2)
*predictor = predictor2;
return res;
}
return NULL; return NULL;
} }
if (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS) if (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS)
{ {
tree res; tree res;
op0 = expr_expected_value (op0, visited, predictor); op0 = expr_expected_value (op0, visited, predictor, probability);
if (!op0) if (!op0)
return NULL; return NULL;
res = fold_build1 (code, type, op0); res = fold_build1 (code, type, op0);
...@@ -2475,23 +2518,44 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, ...@@ -2475,23 +2518,44 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
static tree static tree
expr_expected_value (tree expr, bitmap visited, expr_expected_value (tree expr, bitmap visited,
enum br_predictor *predictor) enum br_predictor *predictor,
HOST_WIDE_INT *probability)
{ {
enum tree_code code; enum tree_code code;
tree op0, op1; tree op0, op1;
if (TREE_CONSTANT (expr)) if (TREE_CONSTANT (expr))
{ {
if (predictor) *predictor = PRED_UNCONDITIONAL;
*predictor = PRED_UNCONDITIONAL; *probability = -1;
return expr; return expr;
} }
extract_ops_from_tree (expr, &code, &op0, &op1); extract_ops_from_tree (expr, &code, &op0, &op1);
return expr_expected_value_1 (TREE_TYPE (expr), return expr_expected_value_1 (TREE_TYPE (expr),
op0, code, op1, visited, predictor); op0, code, op1, visited, predictor,
probability);
} }
/* Return probability of a PREDICTOR. If the predictor has variable
probability return passed PROBABILITY. */
static HOST_WIDE_INT
get_predictor_value (br_predictor predictor, HOST_WIDE_INT probability)
{
switch (predictor)
{
case PRED_BUILTIN_EXPECT:
case PRED_BUILTIN_EXPECT_WITH_PROBABILITY:
gcc_assert (probability != -1);
return probability;
default:
gcc_assert (probability == -1);
return predictor_info[(int) predictor].hitrate;
}
}
/* Predict using opcode of the last statement in basic block. */ /* Predict using opcode of the last statement in basic block. */
static void static void
tree_predict_by_opcode (basic_block bb) tree_predict_by_opcode (basic_block bb)
...@@ -2504,6 +2568,7 @@ tree_predict_by_opcode (basic_block bb) ...@@ -2504,6 +2568,7 @@ tree_predict_by_opcode (basic_block bb)
enum tree_code cmp; enum tree_code cmp;
edge_iterator ei; edge_iterator ei;
enum br_predictor predictor; enum br_predictor predictor;
HOST_WIDE_INT probability;
if (!stmt || gimple_code (stmt) != GIMPLE_COND) if (!stmt || gimple_code (stmt) != GIMPLE_COND)
return; return;
...@@ -2515,21 +2580,13 @@ tree_predict_by_opcode (basic_block bb) ...@@ -2515,21 +2580,13 @@ tree_predict_by_opcode (basic_block bb)
cmp = gimple_cond_code (stmt); cmp = gimple_cond_code (stmt);
type = TREE_TYPE (op0); type = TREE_TYPE (op0);
val = expr_expected_value_1 (boolean_type_node, op0, cmp, op1, auto_bitmap (), val = expr_expected_value_1 (boolean_type_node, op0, cmp, op1, auto_bitmap (),
&predictor); &predictor, &probability);
if (val && TREE_CODE (val) == INTEGER_CST) if (val && TREE_CODE (val) == INTEGER_CST)
{ {
if (predictor == PRED_BUILTIN_EXPECT) HOST_WIDE_INT prob = get_predictor_value (predictor, probability);
{ if (integer_zerop (val))
int percent = PARAM_VALUE (BUILTIN_EXPECT_PROBABILITY); prob = REG_BR_PROB_BASE - prob;
predict_edge (then_edge, predictor, prob);
gcc_assert (percent >= 0 && percent <= 100);
if (integer_zerop (val))
percent = 100 - percent;
predict_edge (then_edge, PRED_BUILTIN_EXPECT, HITRATE (percent));
}
else
predict_edge_def (then_edge, predictor,
integer_zerop (val) ? NOT_TAKEN : TAKEN);
} }
/* Try "pointer heuristic." /* Try "pointer heuristic."
A comparison ptr == 0 is predicted as false. A comparison ptr == 0 is predicted as false.
...@@ -3933,13 +3990,14 @@ strip_predict_hints (function *fun, bool early) ...@@ -3933,13 +3990,14 @@ strip_predict_hints (function *fun, bool early)
{ {
tree fndecl = gimple_call_fndecl (stmt); tree fndecl = gimple_call_fndecl (stmt);
if ((!early if (!early
&& fndecl && ((DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL, BUILT_IN_EXPECT)
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL && gimple_call_num_args (stmt) == 2)
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT || (DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL,
&& gimple_call_num_args (stmt) == 2) BUILT_IN_EXPECT_WITH_PROBABILITY)
|| (gimple_call_internal_p (stmt) && gimple_call_num_args (stmt) == 3)
&& gimple_call_internal_fn (stmt) == IFN_BUILTIN_EXPECT)) || (gimple_call_internal_p (stmt)
&& gimple_call_internal_fn (stmt) == IFN_BUILTIN_EXPECT)))
{ {
var = gimple_call_lhs (stmt); var = gimple_call_lhs (stmt);
changed = true; changed = true;
......
...@@ -73,6 +73,11 @@ DEF_PREDICTOR (PRED_COMPARE_AND_SWAP, "compare and swap", PROB_VERY_LIKELY, ...@@ -73,6 +73,11 @@ DEF_PREDICTOR (PRED_COMPARE_AND_SWAP, "compare and swap", PROB_VERY_LIKELY,
DEF_PREDICTOR (PRED_BUILTIN_EXPECT, "__builtin_expect", PROB_VERY_LIKELY, DEF_PREDICTOR (PRED_BUILTIN_EXPECT, "__builtin_expect", PROB_VERY_LIKELY,
PRED_FLAG_FIRST_MATCH) PRED_FLAG_FIRST_MATCH)
/* Hints provided by user via __builtin_expect_with_probability. */
DEF_PREDICTOR (PRED_BUILTIN_EXPECT_WITH_PROBABILITY,
"__builtin_expect_with_probability", PROB_UNINITIALIZED,
PRED_FLAG_FIRST_MATCH)
/* Use number of loop iterations guessed by the contents of the loop. */ /* Use number of loop iterations guessed by the contents of the loop. */
DEF_PREDICTOR (PRED_LOOP_ITERATIONS_GUESSED, "guessed loop iterations", DEF_PREDICTOR (PRED_LOOP_ITERATIONS_GUESSED, "guessed loop iterations",
PROB_UNINITIALIZED, PRED_FLAG_FIRST_MATCH) PROB_UNINITIALIZED, PRED_FLAG_FIRST_MATCH)
......
2018-08-10 Martin Liska <mliska@suse.cz> 2018-08-10 Martin Liska <mliska@suse.cz>
PR target/83610
* gcc.dg/predict-17.c: New test.
* gcc.dg/predict-18.c: New test.
* gcc.dg/predict-19.c: New test.
2018-08-10 Martin Liska <mliska@suse.cz>
PR tree-optimization/85799 PR tree-optimization/85799
* gcc.dg/pr85799.c: New test. * gcc.dg/pr85799.c: New test.
......
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-profile_estimate" } */
extern int global;
void foo (int base)
{
for (int i = 0; __builtin_expect_with_probability (i < base, 1, 0.05f); i++)
global++;
}
/* { dg-final { scan-tree-dump "first match heuristics: 5.00%" "profile_estimate"} } */
/* { dg-final { scan-tree-dump "__builtin_expect_with_probability heuristics of edge .*->.*: 5.00%" "profile_estimate"} } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-profile_estimate" } */
extern int global;
int x;
short v = 0;
short expected = 0;
short max = ~0;
#define STRONG 0
void foo (int a, int b)
{
if (__builtin_expect_with_probability (a < b, 1, 0.6f) > __builtin_expect (b, 0))
global++;
if (__builtin_expect_with_probability (a < b, 1, 0.777f) > 0)
global++;
if (__builtin_expect_with_probability (a < b, 1, 0.99) == __atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED))
global++;
if (__builtin_expect_with_probability (a < 10, 1, 0.9f) > __builtin_expect_with_probability (b, 0, 0.8f))
global++;
}
/* { dg-final { scan-tree-dump "__builtin_expect_with_probability heuristics of edge .*->.*: 54.00%" "profile_estimate"} } */
/* { dg-final { scan-tree-dump "__builtin_expect_with_probability heuristics of edge .*->.*: 77.70%" "profile_estimate"} } */
/* { dg-final { scan-tree-dump "__builtin_expect_with_probability heuristics of edge .*->.*: 98.96%" "profile_estimate"} } */
/* { dg-final { scan-tree-dump "__builtin_expect_with_probability heuristics of edge .*->.*: 71.99%" "profile_estimate"} } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-profile_estimate" } */
extern int global;
void foo (int base)
{
if (__builtin_expect_with_probability (base == 100, 1, 0.001f))
global++;
}
/* { dg-final { scan-tree-dump "first match heuristics: 0.10%" "profile_estimate"} } */
/* { dg-final { scan-tree-dump "__builtin_expect_with_probability heuristics of edge .*->.*: 0.10%" "profile_estimate"} } */
...@@ -3008,6 +3008,12 @@ extern vec<tree, va_gc> **decl_debug_args_insert (tree); ...@@ -3008,6 +3008,12 @@ extern vec<tree, va_gc> **decl_debug_args_insert (tree);
#define DECL_BUILT_IN_CLASS(NODE) \ #define DECL_BUILT_IN_CLASS(NODE) \
(FUNCTION_DECL_CHECK (NODE)->function_decl.built_in_class) (FUNCTION_DECL_CHECK (NODE)->function_decl.built_in_class)
/* For a function declaration, return true if NODE is non-null and it is
a builtin of a CLASS with requested NAME. */
#define DECL_BUILT_IN_P(NODE, CLASS, NAME) \
(NODE != NULL_TREE && DECL_BUILT_IN_CLASS (NODE) == CLASS \
&& DECL_FUNCTION_CODE (NODE) == NAME)
/* In FUNCTION_DECL, a chain of ..._DECL nodes. */ /* In FUNCTION_DECL, a chain of ..._DECL nodes. */
#define DECL_ARGUMENTS(NODE) \ #define DECL_ARGUMENTS(NODE) \
(FUNCTION_DECL_CHECK (NODE)->function_decl.arguments) (FUNCTION_DECL_CHECK (NODE)->function_decl.arguments)
......
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