This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Introduce __builtin_expect_with_probability (PR target/83610).


On 07/31/2018 11:24 AM, Jan Hubicka wrote:
>> Hi.
>>
>> This is implementation of new built-in that can be used for more fine
>> tweaking of probability. Micro benchmark is attached as part of the PR.
>>
>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>>
>> Ready to be installed?
> 
> It reasonale to me to add the fature. Years ago I made similar patch and at
> that time it did not go in based on argumentation that programers are not good
> on guessing probabilities and this is too much of fine control while it should
> be done by profile feedback. 
> 
> However I guess it is better to have way to specify probability than tweak with
> --param that controls the builtin_expect outcome globally.

Agree with that, that's why I implemented that.

> 
> What I think would be useful is to tie this to the code giving loop trip
> estimate.  If you know that the loop iterates 100 times at the average, you
> can specify probability 1%.   For this it seems to me more sensible to have
> the percentage parameter to be double rather than long so one can specify larger
> trip counts this way.

Makes fully sense, please take a look at attached updated patch.

Martin

> 
> Honza
> 
> 
>> Martin
>>
>> gcc/ChangeLog:
>>
>> 2018-07-24  Martin Liska  <mliska@suse.cz>
>>
>>         PR target/83610
>> 	* builtin-types.def (BT_FN_LONG_LONG_LONG_LONG): New type.
>> 	* builtins.c (expand_builtin_expect_with_probability):
>>         New function.
>> 	(expand_builtin): Handle also BUILT_IN_EXPECT_WITH_PROBABILITY.
>> 	(build_builtin_expect_predicate): Likewise.
>> 	(fold_builtin_expect): Likewise.
>> 	(fold_builtin_2): Likewise.
>> 	(fold_builtin_3): Likewise.
>> 	* builtins.def (BUILT_IN_EXPECT_WITH_PROBABILITY): Define new
>>         builtin.
>> 	* builtins.h (fold_builtin_expect): Add new argument
>>         (probability).
>> 	* doc/extend.texi: Document the new builtin.
>> 	* 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 (expr_expected_value): Add new out argument which
>>         is probability.
>> 	(expr_expected_value_1): Likewise.
>> 	(tree_predict_by_opcode): Predict edge based on
>>         provided probability.
>> 	(pass_strip_predict_hints::execute): Use newly added
>>         DECL_BUILT_IN_P macro.
>> 	* predict.def (PRED_BUILTIN_EXPECT_WITH_PROBABILITY):
>>         Define new predictor.
>> 	* tree.h (DECL_BUILT_IN_P): Define.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 2018-07-24  Martin Liska  <mliska@suse.cz>
>>
>> 	* gcc.dg/predict-16.c: New test.
>> ---
>>  gcc/builtin-types.def             |  2 +
>>  gcc/builtins.c                    | 65 ++++++++++++++++++++++++-------
>>  gcc/builtins.def                  |  1 +
>>  gcc/builtins.h                    |  2 +-
>>  gcc/doc/extend.texi               |  8 ++++
>>  gcc/doc/invoke.texi               |  3 ++
>>  gcc/gimple-fold.c                 |  3 +-
>>  gcc/ipa-fnsummary.c               |  1 +
>>  gcc/predict.c                     | 61 ++++++++++++++++++++++-------
>>  gcc/predict.def                   |  5 +++
>>  gcc/testsuite/gcc.dg/predict-16.c | 13 +++++++
>>  gcc/tree.h                        |  6 +++
>>  12 files changed, 140 insertions(+), 30 deletions(-)
>>  create mode 100644 gcc/testsuite/gcc.dg/predict-16.c
>>
>>
> 
>> diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
>> index b01095c420f..6e87bcbbf1d 100644
>> --- a/gcc/builtin-types.def
>> +++ b/gcc/builtin-types.def
>> @@ -531,6 +531,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_ULONG_ULONG_ULONG_ULONG,
>>  		     BT_ULONG, BT_ULONG, BT_ULONG, BT_ULONG)
>>  DEF_FUNCTION_TYPE_3 (BT_FN_LONG_LONG_UINT_UINT,
>>  		     BT_LONG, BT_LONG, BT_UINT, BT_UINT)
>> +DEF_FUNCTION_TYPE_3 (BT_FN_LONG_LONG_LONG_LONG,
>> +		     BT_LONG, BT_LONG, BT_LONG, BT_LONG)
>>  DEF_FUNCTION_TYPE_3 (BT_FN_ULONG_ULONG_UINT_UINT,
>>  		     BT_ULONG, BT_ULONG, BT_UINT, BT_UINT)
>>  DEF_FUNCTION_TYPE_3 (BT_FN_STRING_CONST_STRING_CONST_STRING_INT,
>> diff --git a/gcc/builtins.c b/gcc/builtins.c
>> index 539a6d17688..29d77d3d83b 100644
>> --- a/gcc/builtins.c
>> +++ b/gcc/builtins.c
>> @@ -148,6 +148,7 @@ static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
>>  static rtx expand_builtin_frame_address (tree, tree);
>>  static tree stabilize_va_list_loc (location_t, tree, int);
>>  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_classify_type (tree);
>>  static tree fold_builtin_strlen (location_t, tree, tree);
>> @@ -5237,6 +5238,27 @@ expand_builtin_expect (tree exp, rtx 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
>>     argument as the builtin_assume_aligned semantic should've been already
>>     executed by CCP.  */
>> @@ -7494,6 +7516,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
>>        return expand_builtin_va_copy (exp);
>>      case BUILT_IN_EXPECT:
>>        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:
>>        return expand_builtin_assume_aligned (exp, target);
>>      case BUILT_IN_PREFETCH:
>> @@ -8134,16 +8158,20 @@ fold_builtin_constant_p (tree arg)
>>    return NULL_TREE;
>>  }
>>  
>> -/* Create builtin_expect with PRED and EXPECTED as its arguments and
>> -   return it as a truthvalue.  */
>> +/* Create builtin_expect or builtin_expect_with_probability
>> +   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
>>  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;
>>  
>> -  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));
>>    ret_type = TREE_TYPE (TREE_TYPE (fn));
>>    pred_type = TREE_VALUE (arg_types);
>> @@ -8151,18 +8179,23 @@ build_builtin_expect_predicate (location_t loc, tree pred, tree expected,
>>  
>>    pred = fold_convert_loc (loc, pred_type, pred);
>>    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,
>>  		 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.  */
>>  
>>  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;
>>    enum tree_code code;
>> @@ -8186,8 +8219,9 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
>>  
>>    if (TREE_CODE (inner) == CALL_EXPR
>>        && (fndecl = get_callee_fndecl (inner))
>> -      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
>> -      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT)
>> +      && (DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL, BUILT_IN_EXPECT)
>> +	  || DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL,
>> +			      BUILT_IN_EXPECT_WITH_PROBABILITY)))
>>      return arg0;
>>  
>>    inner = inner_arg0;
>> @@ -8198,8 +8232,8 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
>>        tree op1 = TREE_OPERAND (inner, 1);
>>        arg1 = save_expr (arg1);
>>  
>> -      op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2);
>> -      op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2);
>> +      op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2, arg3);
>> +      op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2, arg3);
>>        inner = build2 (code, TREE_TYPE (inner), op0, op1);
>>  
>>        return fold_convert_loc (loc, TREE_TYPE (arg0), inner);
>> @@ -9295,7 +9329,7 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
>>        return fold_builtin_strpbrk (loc, arg0, arg1, type);
>>  
>>      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:
>>        return fold_builtin_unordered_cmp (loc, fndecl,
>> @@ -9373,7 +9407,10 @@ fold_builtin_3 (location_t loc, tree fndecl,
>>        return fold_builtin_memcmp (loc, arg0, arg1, arg2);
>>  
>>      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_SUB_OVERFLOW:
>> diff --git a/gcc/builtins.def b/gcc/builtins.def
>> index aacbd513a16..683a07e18fa 100644
>> --- a/gcc/builtins.def
>> +++ b/gcc/builtins.def
>> @@ -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_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_WITH_PROBABILITY, "expect_with_probability", BT_FN_LONG_LONG_LONG_LONG, 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_EXTRACT_RETURN_ADDR, "extract_return_addr", BT_FN_PTR_PTR, ATTR_LEAF_LIST)
>> diff --git a/gcc/builtins.h b/gcc/builtins.h
>> index c9229049e21..3662ebcd98f 100644
>> --- a/gcc/builtins.h
>> +++ b/gcc/builtins.h
>> @@ -76,7 +76,7 @@ extern void expand_ifn_atomic_compare_exchange (gcall *);
>>  extern rtx expand_builtin (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 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 tree fold_call_expr (location_t, tree, bool);
>>  extern tree fold_builtin_call_array (location_t, tree, tree, int, tree *);
>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
>> index 7b471ec40f7..8567b24f873 100644
>> --- a/gcc/doc/extend.texi
>> +++ b/gcc/doc/extend.texi
>> @@ -11852,6 +11852,14 @@ if (__builtin_expect (ptr != NULL, 1))
>>  when testing pointer or floating-point values.
>>  @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}.
>> +Valid values of @var{probability} argument are in inclusive range 0 and 100.
>> +@end deftypefn
>> +
>>  @deftypefn {Built-in Function} void __builtin_trap (void)
>>  This function causes the program to exit abnormally.  GCC implements
>>  this function by using a target-dependent mechanism (such as
>> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> index 1dcdfb51c47..edc46a3be95 100644
>> --- a/gcc/doc/invoke.texi
>> +++ b/gcc/doc/invoke.texi
>> @@ -9209,6 +9209,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
>>  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
>>  @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}.
>>  
>> diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
>> index 027ca4da97c..ea441797214 100644
>> --- a/gcc/gimple-fold.c
>> +++ b/gcc/gimple-fold.c
>> @@ -4166,7 +4166,8 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
>>  	  result = fold_builtin_expect (gimple_location (stmt),
>>  					gimple_call_arg (stmt, 0),
>>  					gimple_call_arg (stmt, 1),
>> -					gimple_call_arg (stmt, 2));
>> +					gimple_call_arg (stmt, 2),
>> +					NULL_TREE);
>>  	  break;
>>  	case IFN_UBSAN_OBJECT_SIZE:
>>  	  {
>> diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
>> index c99718a265f..a8fc2c2df9a 100644
>> --- a/gcc/ipa-fnsummary.c
>> +++ b/gcc/ipa-fnsummary.c
>> @@ -1851,6 +1851,7 @@ find_foldable_builtin_expect (basic_block bb)
>>      {
>>        gimple *stmt = gsi_stmt (bsi);
>>        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))
>>          {
>>            tree var = gimple_call_lhs (stmt);
>> diff --git a/gcc/predict.c b/gcc/predict.c
>> index 65e088fb8df..73e2a0fd2ed 100644
>> --- a/gcc/predict.c
>> +++ b/gcc/predict.c
>> @@ -2262,13 +2262,15 @@ guess_outgoing_edge_probabilities (basic_block 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,
>> +				 tree *probability);
>>  
>>  /* Helper function for expr_expected_value.  */
>>  
>>  static tree
>>  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,
>> +		       tree *probability)
>>  {
>>    gimple *def;
>>  
>> @@ -2329,7 +2331,8 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
>>  	      if (arg == PHI_RESULT (def))
>>  		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
>>  		 that later predictor is weaker and take its prediction.  */
>> @@ -2353,7 +2356,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
>>  					gimple_assign_rhs1 (def),
>>  					gimple_assign_rhs_code (def),
>>  					gimple_assign_rhs2 (def),
>> -					visited, predictor);
>> +					visited, predictor, NULL);
>>  	}
>>  
>>        if (is_gimple_call (def))
>> @@ -2395,6 +2398,21 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
>>  		    *predictor = PRED_BUILTIN_EXPECT;
>>  		  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;
>> +		  if (predictor)
>> +		    {
>> +		      *predictor = PRED_BUILTIN_EXPECT_WITH_PROBABILITY;
>> +		      *probability = gimple_call_arg (def, 2);
>> +		    }
>> +		  return gimple_call_arg (def, 1);
>> +		}
>>  
>>  	      case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N:
>>  	      case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
>> @@ -2426,10 +2444,10 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
>>      {
>>        tree res;
>>        enum br_predictor predictor2;
>> -      op0 = expr_expected_value (op0, visited, predictor);
>> +      op0 = expr_expected_value (op0, visited, predictor, probability);
>>        if (!op0)
>>  	return NULL;
>> -      op1 = expr_expected_value (op1, visited, &predictor2);
>> +      op1 = expr_expected_value (op1, visited, &predictor2, probability);
>>        if (predictor && *predictor < predictor2)
>>  	*predictor = predictor2;
>>        if (!op1)
>> @@ -2442,7 +2460,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
>>    if (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS)
>>      {
>>        tree res;
>> -      op0 = expr_expected_value (op0, visited, predictor);
>> +      op0 = expr_expected_value (op0, visited, predictor, probability);
>>        if (!op0)
>>  	return NULL;
>>        res = fold_build1 (code, type, op0);
>> @@ -2463,7 +2481,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
>>  
>>  static tree
>>  expr_expected_value (tree expr, bitmap visited,
>> -		     enum br_predictor *predictor)
>> +		     enum br_predictor *predictor, tree *probability)
>>  {
>>    enum tree_code code;
>>    tree op0, op1;
>> @@ -2477,7 +2495,8 @@ expr_expected_value (tree expr, bitmap visited,
>>  
>>    extract_ops_from_tree (expr, &code, &op0, &op1);
>>    return expr_expected_value_1 (TREE_TYPE (expr),
>> -				op0, code, op1, visited, predictor);
>> +				op0, code, op1, visited, predictor,
>> +				probability);
>>  }
>>  
>>  /* Predict using opcode of the last statement in basic block.  */
>> @@ -2488,7 +2507,7 @@ tree_predict_by_opcode (basic_block bb)
>>    edge then_edge;
>>    tree op0, op1;
>>    tree type;
>> -  tree val;
>> +  tree val, probability;
>>    enum tree_code cmp;
>>    edge_iterator ei;
>>    enum br_predictor predictor;
>> @@ -2503,7 +2522,7 @@ tree_predict_by_opcode (basic_block bb)
>>    cmp = gimple_cond_code (stmt);
>>    type = TREE_TYPE (op0);
>>    val = expr_expected_value_1 (boolean_type_node, op0, cmp, op1, auto_bitmap (),
>> -			       &predictor);
>> +			       &predictor, &probability);
>>    if (val && TREE_CODE (val) == INTEGER_CST)
>>      {
>>        if (predictor == PRED_BUILTIN_EXPECT)
>> @@ -2515,6 +2534,19 @@ tree_predict_by_opcode (basic_block bb)
>>  	    percent = 100 - percent;
>>  	  predict_edge (then_edge, PRED_BUILTIN_EXPECT, HITRATE (percent));
>>  	}
>> +      else if (predictor == PRED_BUILTIN_EXPECT_WITH_PROBABILITY)
>> +	{
>> +	  if (!tree_fits_uhwi_p (probability))
>> +	    return;
>> +
>> +	  unsigned percent = tree_to_uhwi (probability);
>> +	  if (integer_zerop (val))
>> +	    percent = 100 - percent;
>> +	  if (percent > 100)
>> +	    return;
>> +	  predict_edge (then_edge, PRED_BUILTIN_EXPECT_WITH_PROBABILITY,
>> +			HITRATE (percent));
>> +	}
>>        else
>>  	predict_edge_def (then_edge, predictor,
>>  			  integer_zerop (val) ? NOT_TAKEN : TAKEN);
>> @@ -3927,10 +3959,11 @@ pass_strip_predict_hints::execute (function *fun)
>>  	    {
>>  	      tree fndecl = gimple_call_fndecl (stmt);
>>  
>> -	      if ((fndecl
>> -		   && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
>> -		   && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
>> +	      if ((DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL, BUILT_IN_EXPECT)
>>  		   && gimple_call_num_args (stmt) == 2)
>> +		  || (DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL,
>> +				       BUILT_IN_EXPECT_WITH_PROBABILITY)
>> +		      && gimple_call_num_args (stmt) == 3)
>>  		  || (gimple_call_internal_p (stmt)
>>  		      && gimple_call_internal_fn (stmt) == IFN_BUILTIN_EXPECT))
>>  		{
>> diff --git a/gcc/predict.def b/gcc/predict.def
>> index 4ed97ed165c..b929d4c37db 100644
>> --- a/gcc/predict.def
>> +++ b/gcc/predict.def
>> @@ -69,6 +69,11 @@ DEF_PREDICTOR (PRED_COMPARE_AND_SWAP, "compare and swap", PROB_VERY_LIKELY,
>>  DEF_PREDICTOR (PRED_BUILTIN_EXPECT, "__builtin_expect", PROB_VERY_LIKELY,
>>  	       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.  */
>>  DEF_PREDICTOR (PRED_LOOP_ITERATIONS_GUESSED, "guessed loop iterations",
>>  	       PROB_UNINITIALIZED, PRED_FLAG_FIRST_MATCH)
>> diff --git a/gcc/testsuite/gcc.dg/predict-16.c b/gcc/testsuite/gcc.dg/predict-16.c
>> new file mode 100644
>> index 00000000000..043f154f19f
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/predict-16.c
>> @@ -0,0 +1,13 @@
>> +/* { 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, 99))
>> +    global++;
>> +}
>> +
>> +/* { dg-final { scan-tree-dump "first match heuristics: 99.0%" "profile_estimate"} } */
>> +/* { dg-final { scan-tree-dump "__builtin_expect_with_probability heuristics of edge .*->.*: 99.0%" "profile_estimate"} } */
>> diff --git a/gcc/tree.h b/gcc/tree.h
>> index 70ac78130c0..ae00e6e4035 100644
>> --- a/gcc/tree.h
>> +++ b/gcc/tree.h
>> @@ -3008,6 +3008,12 @@ extern vec<tree, va_gc> **decl_debug_args_insert (tree);
>>  #define DECL_BUILT_IN_CLASS(NODE) \
>>     (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.  */
>>  #define DECL_ARGUMENTS(NODE) \
>>     (FUNCTION_DECL_CHECK (NODE)->function_decl.arguments)
>>
> 

>From 6e59bf3acfa83dbde1af80678aa69a917cdbcecd Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Mon, 23 Jul 2018 16:03:19 +0200
Subject: [PATCH] Introduce __builtin_expect_with_probability (PR
 target/83610).

gcc/ChangeLog:

2018-07-24  Martin Liska  <mliska@suse.cz>

        PR target/83610
	* builtin-types.def (BT_FN_LONG_LONG_LONG_DOUBLE): New type.
	* builtins.c (expand_builtin_expect_with_probability):
        New function.
	(expand_builtin): Handle also BUILT_IN_EXPECT_WITH_PROBABILITY.
	(build_builtin_expect_predicate): Likewise.
	(fold_builtin_expect): Likewise.
	(fold_builtin_2): Likewise.
	(fold_builtin_3): Likewise.
	* builtins.def (BUILT_IN_EXPECT_WITH_PROBABILITY): Define new
        builtin.
	* builtins.h (fold_builtin_expect): Add new argument
        (probability).
	* doc/extend.texi: Document the new builtin.
	* 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 (expr_expected_value): Add new out argument which
        is probability.
	(expr_expected_value_1): Likewise.
	(tree_predict_by_opcode): Predict edge based on
        provided probability.
	(pass_strip_predict_hints::execute): Use newly added
        DECL_BUILT_IN_P macro.
	* predict.def (PRED_BUILTIN_EXPECT_WITH_PROBABILITY):
        Define new predictor.
	* tree.h (DECL_BUILT_IN_P): Define.

gcc/testsuite/ChangeLog:

2018-07-24  Martin Liska  <mliska@suse.cz>

	* gcc.dg/predict-16.c: New test.
	* gcc.dg/predict-17.c: New test.
---
 gcc/builtin-types.def             |  2 +
 gcc/builtins.c                    | 65 ++++++++++++++++++++++-------
 gcc/builtins.def                  |  1 +
 gcc/builtins.h                    |  2 +-
 gcc/doc/extend.texi               |  9 ++++
 gcc/doc/invoke.texi               |  3 ++
 gcc/gimple-fold.c                 |  3 +-
 gcc/ipa-fnsummary.c               |  1 +
 gcc/predict.c                     | 68 ++++++++++++++++++++++++-------
 gcc/predict.def                   |  5 +++
 gcc/testsuite/gcc.dg/predict-16.c | 13 ++++++
 gcc/testsuite/gcc.dg/predict-17.c | 13 ++++++
 gcc/tree.h                        |  6 +++
 13 files changed, 160 insertions(+), 31 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/predict-16.c
 create mode 100644 gcc/testsuite/gcc.dg/predict-17.c

diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index 70fae35ce72..f13da6a188c 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -531,6 +531,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_ULONG_ULONG_ULONG_ULONG,
 		     BT_ULONG, BT_ULONG, BT_ULONG, BT_ULONG)
 DEF_FUNCTION_TYPE_3 (BT_FN_LONG_LONG_UINT_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,
 		     BT_ULONG, BT_ULONG, BT_UINT, BT_UINT)
 DEF_FUNCTION_TYPE_3 (BT_FN_STRING_CONST_STRING_CONST_STRING_INT,
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 39611de7021..867d153d798 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -148,6 +148,7 @@ static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
 static rtx expand_builtin_frame_address (tree, tree);
 static tree stabilize_va_list_loc (location_t, tree, int);
 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_classify_type (tree);
 static tree fold_builtin_strlen (location_t, tree, tree);
@@ -5251,6 +5252,27 @@ expand_builtin_expect (tree exp, rtx 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
    argument as the builtin_assume_aligned semantic should've been already
    executed by CCP.  */
@@ -7562,6 +7584,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
       return expand_builtin_va_copy (exp);
     case BUILT_IN_EXPECT:
       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:
       return expand_builtin_assume_aligned (exp, target);
     case BUILT_IN_PREFETCH:
@@ -8213,16 +8237,20 @@ fold_builtin_constant_p (tree arg)
   return NULL_TREE;
 }
 
-/* Create builtin_expect with PRED and EXPECTED as its arguments and
-   return it as a truthvalue.  */
+/* Create builtin_expect or builtin_expect_with_probability
+   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
 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;
 
-  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));
   ret_type = TREE_TYPE (TREE_TYPE (fn));
   pred_type = TREE_VALUE (arg_types);
@@ -8230,18 +8258,23 @@ build_builtin_expect_predicate (location_t loc, tree pred, tree expected,
 
   pred = fold_convert_loc (loc, pred_type, pred);
   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,
 		 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.  */
 
 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;
   enum tree_code code;
@@ -8265,8 +8298,9 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
 
   if (TREE_CODE (inner) == CALL_EXPR
       && (fndecl = get_callee_fndecl (inner))
-      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT)
+      && (DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL, BUILT_IN_EXPECT)
+	  || DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL,
+			      BUILT_IN_EXPECT_WITH_PROBABILITY)))
     return arg0;
 
   inner = inner_arg0;
@@ -8277,8 +8311,8 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
       tree op1 = TREE_OPERAND (inner, 1);
       arg1 = save_expr (arg1);
 
-      op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2);
-      op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2);
+      op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2, arg3);
+      op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2, arg3);
       inner = build2 (code, TREE_TYPE (inner), op0, op1);
 
       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)
       return fold_builtin_strpbrk (loc, arg0, arg1, type);
 
     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:
       return fold_builtin_unordered_cmp (loc, fndecl,
@@ -9452,7 +9486,10 @@ fold_builtin_3 (location_t loc, tree fndecl,
       return fold_builtin_memcmp (loc, arg0, arg1, arg2);
 
     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_SUB_OVERFLOW:
diff --git a/gcc/builtins.def b/gcc/builtins.def
index ad90d4458a1..ef89729fd0c 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -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_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_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_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)
diff --git a/gcc/builtins.h b/gcc/builtins.h
index 2e0a2f95379..1113bd37f1b 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -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_with_bounds (tree, rtx, rtx, machine_mode, int);
 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 tree fold_call_expr (location_t, tree, bool);
 extern tree fold_builtin_call_array (location_t, tree, tree, int, tree *);
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index bf465d7b93c..392cf0d5634 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -11954,6 +11954,15 @@ if (__builtin_expect (ptr != NULL, 1))
 when testing pointer or floating-point values.
 @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 flaot type and valid values
+are in inclusive range 0.0f and 1.0f.
+@end deftypefn
+
 @deftypefn {Built-in Function} void __builtin_trap (void)
 This function causes the program to exit abnormally.  GCC implements
 this function by using a target-dependent mechanism (such as
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 6047d82065a..bbc024ec1ea 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -9210,6 +9210,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
 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
 @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}.
 
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index c3fa57064c2..0bdb559eadc 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -4156,7 +4156,8 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
 	  result = fold_builtin_expect (gimple_location (stmt),
 					gimple_call_arg (stmt, 0),
 					gimple_call_arg (stmt, 1),
-					gimple_call_arg (stmt, 2));
+					gimple_call_arg (stmt, 2),
+					NULL_TREE);
 	  break;
 	case IFN_UBSAN_OBJECT_SIZE:
 	  {
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index c99718a265f..a8fc2c2df9a 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -1851,6 +1851,7 @@ find_foldable_builtin_expect (basic_block bb)
     {
       gimple *stmt = gsi_stmt (bsi);
       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))
         {
           tree var = gimple_call_lhs (stmt);
diff --git a/gcc/predict.c b/gcc/predict.c
index 65e088fb8df..779f656238f 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -2262,13 +2262,15 @@ guess_outgoing_edge_probabilities (basic_block 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,
+				 tree *probability);
 
 /* Helper function for expr_expected_value.  */
 
 static tree
 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,
+		       tree *probability)
 {
   gimple *def;
 
@@ -2329,7 +2331,8 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
 	      if (arg == PHI_RESULT (def))
 		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
 		 that later predictor is weaker and take its prediction.  */
@@ -2353,7 +2356,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
 					gimple_assign_rhs1 (def),
 					gimple_assign_rhs_code (def),
 					gimple_assign_rhs2 (def),
-					visited, predictor);
+					visited, predictor, NULL);
 	}
 
       if (is_gimple_call (def))
@@ -2395,6 +2398,21 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
 		    *predictor = PRED_BUILTIN_EXPECT;
 		  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;
+		  if (predictor)
+		    {
+		      *predictor = PRED_BUILTIN_EXPECT_WITH_PROBABILITY;
+		      *probability = gimple_call_arg (def, 2);
+		    }
+		  return gimple_call_arg (def, 1);
+		}
 
 	      case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N:
 	      case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
@@ -2426,10 +2444,10 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
     {
       tree res;
       enum br_predictor predictor2;
-      op0 = expr_expected_value (op0, visited, predictor);
+      op0 = expr_expected_value (op0, visited, predictor, probability);
       if (!op0)
 	return NULL;
-      op1 = expr_expected_value (op1, visited, &predictor2);
+      op1 = expr_expected_value (op1, visited, &predictor2, probability);
       if (predictor && *predictor < predictor2)
 	*predictor = predictor2;
       if (!op1)
@@ -2442,7 +2460,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
   if (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS)
     {
       tree res;
-      op0 = expr_expected_value (op0, visited, predictor);
+      op0 = expr_expected_value (op0, visited, predictor, probability);
       if (!op0)
 	return NULL;
       res = fold_build1 (code, type, op0);
@@ -2463,7 +2481,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
 
 static tree
 expr_expected_value (tree expr, bitmap visited,
-		     enum br_predictor *predictor)
+		     enum br_predictor *predictor, tree *probability)
 {
   enum tree_code code;
   tree op0, op1;
@@ -2477,7 +2495,8 @@ expr_expected_value (tree expr, bitmap visited,
 
   extract_ops_from_tree (expr, &code, &op0, &op1);
   return expr_expected_value_1 (TREE_TYPE (expr),
-				op0, code, op1, visited, predictor);
+				op0, code, op1, visited, predictor,
+				probability);
 }
 
 /* Predict using opcode of the last statement in basic block.  */
@@ -2488,7 +2507,7 @@ tree_predict_by_opcode (basic_block bb)
   edge then_edge;
   tree op0, op1;
   tree type;
-  tree val;
+  tree val, probability;
   enum tree_code cmp;
   edge_iterator ei;
   enum br_predictor predictor;
@@ -2503,8 +2522,8 @@ tree_predict_by_opcode (basic_block bb)
   cmp = gimple_cond_code (stmt);
   type = TREE_TYPE (op0);
   val = expr_expected_value_1 (boolean_type_node, op0, cmp, op1, auto_bitmap (),
-			       &predictor);
-  if (val && TREE_CODE (val) == INTEGER_CST)
+			       &predictor, &probability);
+  if (val && (TREE_CODE (val) == INTEGER_CST || TREE_CODE (val) == REAL_CST))
     {
       if (predictor == PRED_BUILTIN_EXPECT)
 	{
@@ -2515,6 +2534,24 @@ tree_predict_by_opcode (basic_block bb)
 	    percent = 100 - percent;
 	  predict_edge (then_edge, PRED_BUILTIN_EXPECT, HITRATE (percent));
 	}
+      else if (predictor == PRED_BUILTIN_EXPECT_WITH_PROBABILITY)
+	{
+	  if (TREE_CODE (probability) != REAL_CST)
+	    return;
+
+	  /* Compute final probability as probability * REG_BR_PROB_BASE.  */
+	  tree t = TREE_TYPE (probability);
+	  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, probability, base);
+	  HOST_WIDE_INT prob = real_to_integer (TREE_REAL_CST_PTR (r));
+
+	  if (integer_zerop (val))
+	    prob = REG_BR_PROB_BASE - prob;
+	  if (prob > REG_BR_PROB_BASE || prob < 0)
+	    return;
+	  predict_edge (then_edge, PRED_BUILTIN_EXPECT_WITH_PROBABILITY, prob);
+	}
       else
 	predict_edge_def (then_edge, predictor,
 			  integer_zerop (val) ? NOT_TAKEN : TAKEN);
@@ -3927,10 +3964,11 @@ pass_strip_predict_hints::execute (function *fun)
 	    {
 	      tree fndecl = gimple_call_fndecl (stmt);
 
-	      if ((fndecl
-		   && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-		   && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
+	      if ((DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL, BUILT_IN_EXPECT)
 		   && gimple_call_num_args (stmt) == 2)
+		  || (DECL_BUILT_IN_P (fndecl, BUILT_IN_NORMAL,
+				       BUILT_IN_EXPECT_WITH_PROBABILITY)
+		      && gimple_call_num_args (stmt) == 3)
 		  || (gimple_call_internal_p (stmt)
 		      && gimple_call_internal_fn (stmt) == IFN_BUILTIN_EXPECT))
 		{
diff --git a/gcc/predict.def b/gcc/predict.def
index 4ed97ed165c..b929d4c37db 100644
--- a/gcc/predict.def
+++ b/gcc/predict.def
@@ -69,6 +69,11 @@ DEF_PREDICTOR (PRED_COMPARE_AND_SWAP, "compare and swap", PROB_VERY_LIKELY,
 DEF_PREDICTOR (PRED_BUILTIN_EXPECT, "__builtin_expect", PROB_VERY_LIKELY,
 	       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.  */
 DEF_PREDICTOR (PRED_LOOP_ITERATIONS_GUESSED, "guessed loop iterations",
 	       PROB_UNINITIALIZED, PRED_FLAG_FIRST_MATCH)
diff --git a/gcc/testsuite/gcc.dg/predict-16.c b/gcc/testsuite/gcc.dg/predict-16.c
new file mode 100644
index 00000000000..2682dba18d9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/predict-16.c
@@ -0,0 +1,13 @@
+/* { 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.1%" "profile_estimate"} } */
+/* { dg-final { scan-tree-dump "__builtin_expect_with_probability heuristics of edge .*->.*: 0.1%" "profile_estimate"} } */
diff --git a/gcc/testsuite/gcc.dg/predict-17.c b/gcc/testsuite/gcc.dg/predict-17.c
new file mode 100644
index 00000000000..78a868367d4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/predict-17.c
@@ -0,0 +1,13 @@
+/* { 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.0%" "profile_estimate"} } */
+/* { dg-final { scan-tree-dump "__builtin_expect_with_probability heuristics of edge .*->.*: 5.0%" "profile_estimate"} } */
diff --git a/gcc/tree.h b/gcc/tree.h
index 7bed03553b2..648e9e2a3c4 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3008,6 +3008,12 @@ extern vec<tree, va_gc> **decl_debug_args_insert (tree);
 #define DECL_BUILT_IN_CLASS(NODE) \
    (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.  */
 #define DECL_ARGUMENTS(NODE) \
    (FUNCTION_DECL_CHECK (NODE)->function_decl.arguments)
-- 
2.18.0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]