diff mbox series

Fix branch probability computation in do_compare_rtx_and_jump (PR tree-optimization/83081)

Message ID 20180119214556.GY2063@tucnak
State New
Headers show
Series Fix branch probability computation in do_compare_rtx_and_jump (PR tree-optimization/83081) | expand

Commit Message

Jakub Jelinek Jan. 19, 2018, 9:45 p.m. UTC
Hi!

This PR is about a certain test FAILing on arm, because it scans for
"Invalid sum ..." message in the *.ira dump, but recent GCC versions have
that message in there; not introduced by IRA though, but all the way from
expansion.  We are expanding:
  <bb 2> [local count: 1073741825]:
  _1 = *x_3(D);
  if (_1 u>= 0.0)
    goto <bb 4>; [99.95%]
  else
    goto <bb 3>; [0.05%]

  <bb 3> [local count: 536864]:
  sqrtf (_1);
and do_compare_rtx_and_jump decides to split the single _1 u>= 0.0
comparison into two.  The expectation is that the basic block counts stay
the same, so if bb 3's count is 0.05% times bb 2's count, the probabilities
need to be computed on both jumps so that this is preserved.
We want to expand essentially to:
  <bb 2> [local count: 1073741825]:
...
  if (cond1)
    goto <bb 4>; [first_prob]
  else
    goto <bb 5>; [first_prob.invert ()]

  <bb 5>:
  if (cond2)
    goto <bb 4>; [prob]
  else
    goto <bb 3>; [prob.invert ()]

  <bb 3> [local count: 536864]:
  sqrtf (_1);
and compute first_prob and prob from the original prob such that the bb
counts match.  The code used to hardcode first_prob to 1% or 99% depending
on condition, and leave the second probability the original one.

That IMHO can't work and the Invalid sum message verifies that.  If we want
the first jump to hit 99times more often than the second one or vice versa,
I believe first_prob should be .99 * prob or .01 * prob respectively, and
the second probability then should be (0.01 * prob) / (1 - 0.99 * prob)
or (0.99 * prob) / (1 - 0.01 * prob) respectively.

With this change the Invalid sum message disappears.
predict-8.c testcase was apparently trying to match the hardcoded 0.99
probability rather than .99 * 65% emitted now.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

If this patch is right, I think do_jump_by_parts* are buggy similarly too,
there we emit prob or prob.invert () for all the N jumps we emit instead of
the original single conditional jump with probability prob.  I think we'd
need to decide what relative probabilities we want to use for the different
jumps, e.g. all have even relative likelyhood and then adjust the
probability of each branch and from what we compute the following
probabiliries similarly to this patch.

2018-01-19  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/83081
	* dojump.c (do_compare_rtx_and_jump): Fix adjustment of probabilities
	when splitting a single conditional jump into 2.

	* gcc.dg/predict-8.c: Adjust expected probability.


	Jakub

Comments

Christophe Lyon Jan. 22, 2018, 12:11 p.m. UTC | #1
On 19 January 2018 at 22:45, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> This PR is about a certain test FAILing on arm, because it scans for
> "Invalid sum ..." message in the *.ira dump, but recent GCC versions have
> that message in there; not introduced by IRA though, but all the way from
> expansion.  We are expanding:
>   <bb 2> [local count: 1073741825]:
>   _1 = *x_3(D);
>   if (_1 u>= 0.0)
>     goto <bb 4>; [99.95%]
>   else
>     goto <bb 3>; [0.05%]
>
>   <bb 3> [local count: 536864]:
>   sqrtf (_1);
> and do_compare_rtx_and_jump decides to split the single _1 u>= 0.0
> comparison into two.  The expectation is that the basic block counts stay
> the same, so if bb 3's count is 0.05% times bb 2's count, the probabilities
> need to be computed on both jumps so that this is preserved.
> We want to expand essentially to:
>   <bb 2> [local count: 1073741825]:
> ...
>   if (cond1)
>     goto <bb 4>; [first_prob]
>   else
>     goto <bb 5>; [first_prob.invert ()]
>
>   <bb 5>:
>   if (cond2)
>     goto <bb 4>; [prob]
>   else
>     goto <bb 3>; [prob.invert ()]
>
>   <bb 3> [local count: 536864]:
>   sqrtf (_1);
> and compute first_prob and prob from the original prob such that the bb
> counts match.  The code used to hardcode first_prob to 1% or 99% depending
> on condition, and leave the second probability the original one.
>
> That IMHO can't work and the Invalid sum message verifies that.  If we want
> the first jump to hit 99times more often than the second one or vice versa,
> I believe first_prob should be .99 * prob or .01 * prob respectively, and
> the second probability then should be (0.01 * prob) / (1 - 0.99 * prob)
> or (0.99 * prob) / (1 - 0.01 * prob) respectively.
>
> With this change the Invalid sum message disappears.
> predict-8.c testcase was apparently trying to match the hardcoded 0.99
> probability rather than .99 * 65% emitted now.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
Hi,

Did you notice any performance impact?

Thanks,

Christophe

> If this patch is right, I think do_jump_by_parts* are buggy similarly too,
> there we emit prob or prob.invert () for all the N jumps we emit instead of
> the original single conditional jump with probability prob.  I think we'd
> need to decide what relative probabilities we want to use for the different
> jumps, e.g. all have even relative likelyhood and then adjust the
> probability of each branch and from what we compute the following
> probabiliries similarly to this patch.
>
> 2018-01-19  Jakub Jelinek  <jakub@redhat.com>
>
>         PR tree-optimization/83081
>         * dojump.c (do_compare_rtx_and_jump): Fix adjustment of probabilities
>         when splitting a single conditional jump into 2.
>
>         * gcc.dg/predict-8.c: Adjust expected probability.
>
> --- gcc/dojump.c.jj     2018-01-03 10:19:55.000000000 +0100
> +++ gcc/dojump.c        2018-01-19 17:07:25.238927314 +0100
> @@ -1122,11 +1122,30 @@ do_compare_rtx_and_jump (rtx op0, rtx op
>             {
>               profile_probability first_prob = prob;
>               if (first_code == UNORDERED)
> -               first_prob = profile_probability::guessed_always ().apply_scale
> -                                (1, 100);
> +               {
> +                 /* We want to split:
> +                    if (x) goto t; // prob;
> +                    into
> +                    if (a) goto t; // first_prob;
> +                    if (b) goto t; // prob;
> +                    such that the overall probability of jumping to t
> +                    remains the same, but the first jump jumps
> +                    much less often than the second jump.  */
> +                 first_prob = prob.guessed ().apply_scale (1, 100);
> +                 prob = (prob.guessed () - first_prob) / first_prob.invert ();
> +               }
>               else if (first_code == ORDERED)
> -               first_prob = profile_probability::guessed_always ().apply_scale
> -                                (99, 100);
> +               {
> +                 /* See above, except the first jump should jump much more
> +                    often than the second one.  */
> +                 first_prob = prob.guessed ().apply_scale (99, 100);
> +                 prob = (prob.guessed () - first_prob) / first_prob.invert ();
> +               }
> +             else
> +               {
> +                 first_prob = prob.guessed ().apply_scale (50, 100);
> +                 prob = first_prob;
> +               }
>               if (and_them)
>                 {
>                   rtx_code_label *dest_label;
> --- gcc/testsuite/gcc.dg/predict-8.c.jj 2017-11-21 23:17:43.149093787 +0100
> +++ gcc/testsuite/gcc.dg/predict-8.c    2018-01-19 22:24:09.949249810 +0100
> @@ -8,4 +8,4 @@ int foo(float a, float b) {
>      return 2;
>  }
>
> -/* { dg-final { scan-rtl-dump-times "99.0. .guessed" 2 "expand"} } */
> +/* { dg-final { scan-rtl-dump-times "64.[34]. .guessed" 2 "expand"} } */
>
>         Jakub
Jakub Jelinek Jan. 22, 2018, 12:14 p.m. UTC | #2
On Mon, Jan 22, 2018 at 01:11:34PM +0100, Christophe Lyon wrote:
> On 19 January 2018 at 22:45, Jakub Jelinek <jakub@redhat.com> wrote:
> > That IMHO can't work and the Invalid sum message verifies that.  If we want
> > the first jump to hit 99times more often than the second one or vice versa,
> > I believe first_prob should be .99 * prob or .01 * prob respectively, and
> > the second probability then should be (0.01 * prob) / (1 - 0.99 * prob)
> > or (0.99 * prob) / (1 - 0.01 * prob) respectively.
> >
> > With this change the Invalid sum message disappears.
> > predict-8.c testcase was apparently trying to match the hardcoded 0.99
> > probability rather than .99 * 65% emitted now.
> >
> > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> >
> Hi,
> 
> Did you notice any performance impact?

Haven't been looking for that, this is a bugfix, the current code is broken.
It changes (fixes) probabilities of some edges, sure, so it could
affect something both ways.

	Jakub
Jan Hubicka Jan. 22, 2018, 12:52 p.m. UTC | #3
Dne 2018-01-19 22:45, Jakub Jelinek napsal:
> Hi!
> 
> This PR is about a certain test FAILing on arm, because it scans for
> "Invalid sum ..." message in the *.ira dump, but recent GCC versions 
> have
> that message in there; not introduced by IRA though, but all the way 
> from
> expansion.  We are expanding:
>   <bb 2> [local count: 1073741825]:
>   _1 = *x_3(D);
>   if (_1 u>= 0.0)
>     goto <bb 4>; [99.95%]
>   else
>     goto <bb 3>; [0.05%]
> 
>   <bb 3> [local count: 536864]:
>   sqrtf (_1);
> and do_compare_rtx_and_jump decides to split the single _1 u>= 0.0
> comparison into two.  The expectation is that the basic block counts 
> stay
> the same, so if bb 3's count is 0.05% times bb 2's count, the 
> probabilities
> need to be computed on both jumps so that this is preserved.
> We want to expand essentially to:
>   <bb 2> [local count: 1073741825]:
> ...
>   if (cond1)
>     goto <bb 4>; [first_prob]
>   else
>     goto <bb 5>; [first_prob.invert ()]
> 
>   <bb 5>:
>   if (cond2)
>     goto <bb 4>; [prob]
>   else
>     goto <bb 3>; [prob.invert ()]
> 
>   <bb 3> [local count: 536864]:
>   sqrtf (_1);
> and compute first_prob and prob from the original prob such that the bb
> counts match.  The code used to hardcode first_prob to 1% or 99% 
> depending
> on condition, and leave the second probability the original one.

OK, so if we end u with first_prob 1% we increase probability to 
dispatch to bb 4 by little
bit that is acceptale noise, but when first_prob is 99% then we 
obviously get it wrong.
> 
> That IMHO can't work and the Invalid sum message verifies that.  If we 
> want
> the first jump to hit 99times more often than the second one or vice 
> versa,
> I believe first_prob should be .99 * prob or .01 * prob respectively, 
> and
> the second probability then should be (0.01 * prob) / (1 - 0.99 * prob)
> or (0.99 * prob) / (1 - 0.01 * prob) respectively.

In new code bb4 is reached by first_prob + (1-first_prob)*second_prob
which should be equal to prob.

Say your choosen constant is to obtain first_prob=c*prob is c=0.99 and 
you want to know c2 to obtain second_prob=c2*prob

You want the combined probability of branch 
(c*prob)+(1-c*prob)*(prob*c2) to be the same prob

This should give c2=(1-c)/(1-c*prob) so 
(c*prob)+(1-c*prob)*prob*(1-c)/(1-c*prob) cancels out to 
c*prob+(1-c)*prob

that is
                   profile_probability cprob = 
profile_probability::guessed_always ().apply_scale (1, 100);
		  first_prob = prob * cprob;
		  prob = cprob.inverse () / (first_prob).inverse ();

unless I missed something.  No need to do .guessed conversion on prob. 
It will be propagated
in as cprob which is already constructed as a guess.

I would say that there are multiple cases where we want to redistribute 
probabilities so perhaps factor it out into a helper. Perhaps something 
like

void profile_probability::split (profile_probability cprob, 
profile_probability *first_prob, profile_probability *second_prob)

I would bet we already have something like that but don't see it.

Other cases seems to choose c as 1/2 that  simplifies the formulate bit 
it is also easy to get misunderstand such as in:
             profile_probability false_prob = prob.invert ();
             profile_probability op0_false_prob = false_prob.apply_scale 
(1, 2);
             profile_probability op1_false_prob = false_prob.apply_scale 
(1, 2)
                                 / op0_false_prob.invert ();
So I would convert those into profile_probability::split

OK with this change.

Thanks for looking into this!
Honza
> 
> With this change the Invalid sum message disappears.
> predict-8.c testcase was apparently trying to match the hardcoded 0.99
> probability rather than .99 * 65% emitted now.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> If this patch is right, I think do_jump_by_parts* are buggy similarly 
> too,
> there we emit prob or prob.invert () for all the N jumps we emit 
> instead of
> the original single conditional jump with probability prob.  I think 
> we'd
> need to decide what relative probabilities we want to use for the 
> different
> jumps, e.g. all have even relative likelyhood and then adjust the
> probability of each branch and from what we compute the following
> probabiliries similarly to this patch.
> 
> 2018-01-19  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/83081
> 	* dojump.c (do_compare_rtx_and_jump): Fix adjustment of probabilities
> 	when splitting a single conditional jump into 2.
> 
> 	* gcc.dg/predict-8.c: Adjust expected probability.
> 
> --- gcc/dojump.c.jj	2018-01-03 10:19:55.000000000 +0100
> +++ gcc/dojump.c	2018-01-19 17:07:25.238927314 +0100
> @@ -1122,11 +1122,30 @@ do_compare_rtx_and_jump (rtx op0, rtx op
>  	    {
>  	      profile_probability first_prob = prob;
>  	      if (first_code == UNORDERED)
> -		first_prob = profile_probability::guessed_always ().apply_scale
> -				 (1, 100);
> +		{
> +		  /* We want to split:
> +		     if (x) goto t; // prob;
> +		     into
> +		     if (a) goto t; // first_prob;
> +		     if (b) goto t; // prob;
> +		     such that the overall probability of jumping to t
> +		     remains the same, but the first jump jumps
> +		     much less often than the second jump.  */
> +		  first_prob = prob.guessed ().apply_scale (1, 100);
> +		  prob = (prob.guessed () - first_prob) / first_prob.invert ();
> +		}
>  	      else if (first_code == ORDERED)
> -		first_prob = profile_probability::guessed_always ().apply_scale
> -				 (99, 100);
> +		{
> +		  /* See above, except the first jump should jump much more
> +		     often than the second one.  */
> +		  first_prob = prob.guessed ().apply_scale (99, 100);
> +		  prob = (prob.guessed () - first_prob) / first_prob.invert ();
> +		}
> +	      else
> +		{
> +		  first_prob = prob.guessed ().apply_scale (50, 100);
> +		  prob = first_prob;
> +		}
>  	      if (and_them)
>  		{
>  		  rtx_code_label *dest_label;
> --- gcc/testsuite/gcc.dg/predict-8.c.jj	2017-11-21 23:17:43.149093787 
> +0100
> +++ gcc/testsuite/gcc.dg/predict-8.c	2018-01-19 22:24:09.949249810 
> +0100
> @@ -8,4 +8,4 @@ int foo(float a, float b) {
>      return 2;
>  }
> 
> -/* { dg-final { scan-rtl-dump-times "99.0. .guessed" 2 "expand"} } */
> +/* { dg-final { scan-rtl-dump-times "64.[34]. .guessed" 2 "expand"} } 
> */
> 
> 	Jakub
Jakub Jelinek Jan. 22, 2018, 1:29 p.m. UTC | #4
On Mon, Jan 22, 2018 at 01:52:11PM +0100, Jan Hubicka wrote:
> In new code bb4 is reached by first_prob + (1-first_prob)*second_prob
> which should be equal to prob.
> 
> Say your choosen constant is to obtain first_prob=c*prob is c=0.99 and you
> want to know c2 to obtain second_prob=c2*prob
> 
> You want the combined probability of branch (c*prob)+(1-c*prob)*(prob*c2) to
> be the same prob
> 
> This should give c2=(1-c)/(1-c*prob) so
> (c*prob)+(1-c*prob)*prob*(1-c)/(1-c*prob) cancels out to c*prob+(1-c)*prob
> 
> that is
>                   profile_probability cprob =
> profile_probability::guessed_always ().apply_scale (1, 100);
> 		  first_prob = prob * cprob;

Yes, if we want it to be done with arbitrary cprob, we can do it the above
way and move the latter into the helper.

> 		  prob = cprob.inverse () / (first_prob).inverse ();

But this looks incorrect, because that computes only the above c2 in prob, not
second_prob.  It needs to be
  prob = cprob.invert () * prob / first_prob.invert ();
or
  prob *= cprob.invert () / first_prob.invert ();
or that
  prob = (prob - first_prob) / first_prob.invert ();
I had in the patch.  The last one looked to me like cheapest to compute.

> void profile_probability::split (profile_probability cprob,
> profile_probability *first_prob, profile_probability *second_prob)

This doesn't take prob as an argument, or should it be a method and take
prob as *this?  Couldn't it simply return first_prob and adjust itself, so
profile_probability split (profile_probability cprob)
{
  profile_probability ret = *this * cprob;
  *this = (*this - prob) / ret.invert ();
// or *this = *this * cprob.invert () / ret.invert ();
  return ret;
}
?
> 
> I would bet we already have something like that but don't see it.
> 
> Other cases seems to choose c as 1/2 that  simplifies the formulate bit it
> is also easy to get misunderstand such as in:
>             profile_probability false_prob = prob.invert ();
>             profile_probability op0_false_prob = false_prob.apply_scale (1,
> 2);
>             profile_probability op1_false_prob = false_prob.apply_scale (1,
> 2)
>                                 / op0_false_prob.invert ();

Or profile_probability op1_false_prob = op0_false_prob / op0_false_prob.invert ();

	Jakub
Jan Hubicka Jan. 22, 2018, 1:43 p.m. UTC | #5
Dne 2018-01-22 14:29, Jakub Jelinek napsal:
> On Mon, Jan 22, 2018 at 01:52:11PM +0100, Jan Hubicka wrote:
>> In new code bb4 is reached by first_prob + (1-first_prob)*second_prob
>> which should be equal to prob.
>> 
>> Say your choosen constant is to obtain first_prob=c*prob is c=0.99 and 
>> you
>> want to know c2 to obtain second_prob=c2*prob
>> 
>> You want the combined probability of branch 
>> (c*prob)+(1-c*prob)*(prob*c2) to
>> be the same prob
>> 
>> This should give c2=(1-c)/(1-c*prob) so
>> (c*prob)+(1-c*prob)*prob*(1-c)/(1-c*prob) cancels out to 
>> c*prob+(1-c)*prob
>> 
>> that is
>>                   profile_probability cprob =
>> profile_probability::guessed_always ().apply_scale (1, 100);
>> 		  first_prob = prob * cprob;
> 
> Yes, if we want it to be done with arbitrary cprob, we can do it the 
> above
> way and move the latter into the helper.
> 
>> 		  prob = cprob.inverse () / (first_prob).inverse ();
> 
> But this looks incorrect, because that computes only the above c2 in 
> prob, not
> second_prob.  It needs to be
>   prob = cprob.invert () * prob / first_prob.invert ();
> or
>   prob *= cprob.invert () / first_prob.invert ();
> or that
>   prob = (prob - first_prob) / first_prob.invert ();
> I had in the patch.  The last one looked to me like cheapest to 
> compute.

Aha, I see.  Ok that makes sense to me now :)
> 
>> void profile_probability::split (profile_probability cprob,
>> profile_probability *first_prob, profile_probability *second_prob)
> 
> This doesn't take prob as an argument, or should it be a method and 
> take
> prob as *this?  Couldn't it simply return first_prob and adjust itself, 
> so
> profile_probability split (profile_probability cprob)
> {
>   profile_probability ret = *this * cprob;
>   *this = (*this - prob) / ret.invert ();
> // or *this = *this * cprob.invert () / ret.invert ();
>   return ret;
> }
> ?

Yep, that is fine.
>> 
>> I would bet we already have something like that but don't see it.
>> 
>> Other cases seems to choose c as 1/2 that  simplifies the formulate 
>> bit it
>> is also easy to get misunderstand such as in:
>>             profile_probability false_prob = prob.invert ();
>>             profile_probability op0_false_prob = 
>> false_prob.apply_scale (1,
>> 2);
>>             profile_probability op1_false_prob = 
>> false_prob.apply_scale (1,
>> 2)
>>                                 / op0_false_prob.invert ();
> 
> Or profile_probability op1_false_prob = op0_false_prob /
> op0_false_prob.invert ();

I would use the splitting function here so once someone decides to 
change the weights the
code will not produce corrupt profile.

Thanks,
Honza
> 
> 	Jakub
Jakub Jelinek Jan. 22, 2018, 3:57 p.m. UTC | #6
On Mon, Jan 22, 2018 at 02:43:50PM +0100, Jan Hubicka wrote:
> > But this looks incorrect, because that computes only the above c2 in
> > prob, not
> > second_prob.  It needs to be
> >   prob = cprob.invert () * prob / first_prob.invert ();
> > or
> >   prob *= cprob.invert () / first_prob.invert ();
> > or that
> >   prob = (prob - first_prob) / first_prob.invert ();
> > I had in the patch.  The last one looked to me like cheapest to compute.
> 
> Aha, I see.  Ok that makes sense to me now :)
> > 
> > > void profile_probability::split (profile_probability cprob,
> > > profile_probability *first_prob, profile_probability *second_prob)
> > 
> > This doesn't take prob as an argument, or should it be a method and take
> > prob as *this?  Couldn't it simply return first_prob and adjust itself,
> > so
> > profile_probability split (profile_probability cprob)
> > {
> >   profile_probability ret = *this * cprob;
> >   *this = (*this - prob) / ret.invert ();
> > // or *this = *this * cprob.invert () / ret.invert ();
> >   return ret;
> > }
> > ?
> 
> Yep, that is fine.

So like this if it passes bootstrap/regtest on {x86_64,i686}-linux?

Besides adding the new helper method and using it in the spots I've changed
plus the two you've mentioned, I had to do another fix - looking
at how TRUTH_ANDIF_EXPR is handled in dojump_1 and seeing Invalid sum
messages in predict-8.c's *.expand jump, I've realized that it also works
as is only for the discussed, i.e.
  if (x)
    goto t; // prob
transformed into:
  if (a)
    goto t; // first_prob
  if (b)
    goto t; // prob
but not for the case where and_them is true, where we have:
  if (c)
    goto dummy; // first_prob.invert ()
  if (d)
    goto t; // prob
dummy:
which needs to be handled similarly to the TRUTH_ANDIF_EXPR case.
At least when trying in gdb on predict-8.c various values of cprob
(1%, 15%, 50%, 62%, 98%) none of them generate the Invalid sum messages.

2018-01-22  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/83081
	* profile-count.h (profile_probability::split): New method.
	* dojump.c (do_jump_1) <case TRUTH_ANDIF_EXPR, case TRUTH_ORIF_EXPR>:
	Use profile_probability::split.
	(do_compare_rtx_and_jump): Fix adjustment of probabilities
	when splitting a single conditional jump into 2.

	* gcc.dg/predict-8.c: Adjust expected probability.

--- gcc/profile-count.h.jj	2018-01-19 19:41:52.910549618 +0100
+++ gcc/profile-count.h	2018-01-22 16:20:27.073096515 +0100
@@ -410,6 +410,19 @@ public:
       return *this;
     }
 
+  /* Split *THIS (ORIG) probability into 2 probabilities, such that
+     the returned one (FIRST) is *THIS * CPROB and *THIS is
+     adjusted (SECOND) so that FIRST + FIRST.invert () * SECOND
+     == ORIG.  */
+  profile_probability split (const profile_probability &cprob)
+    {
+      profile_probability ret = *this * cprob;
+      /* The following is equivalent to:
+	 *this = cprob.invert () * *this / ret.invert ();  */
+      *this = (*this - ret) / ret.invert ();
+      return ret;
+    }
+
   gcov_type apply (gcov_type val) const
     {
       if (*this == profile_probability::uninitialized ())
--- gcc/dojump.c.jj	2018-01-19 19:41:49.978548984 +0100
+++ gcc/dojump.c	2018-01-22 16:31:43.867185428 +0100
@@ -347,13 +347,11 @@ do_jump_1 (enum tree_code code, tree op0
         profile_probability op1_prob = profile_probability::uninitialized ();
         if (prob.initialized_p ())
           {
-            profile_probability false_prob = prob.invert ();
-            profile_probability op0_false_prob = false_prob.apply_scale (1, 2);
-	    profile_probability op1_false_prob = false_prob.apply_scale (1, 2)
-				/ op0_false_prob.invert ();
+	    op1_prob = prob.invert ();
+	    op0_prob = op1_prob.split (profile_probability::even ());
             /* Get the probability that each jump below is true.  */
-            op0_prob = op0_false_prob.invert ();
-            op1_prob = op1_false_prob.invert ();
+	    op0_prob = op0_prob.invert ();
+	    op1_prob = op1_prob.invert ();
           }
 	if (if_false_label == NULL)
           {
@@ -380,8 +378,8 @@ do_jump_1 (enum tree_code code, tree op0
         profile_probability op1_prob = profile_probability::uninitialized ();
         if (prob.initialized_p ())
           {
-            op0_prob = prob.apply_scale (1, 2);
-            op1_prob = prob.apply_scale (1, 2) / op0_prob.invert ();
+	    op1_prob = prob;
+	    op0_prob = op1_prob.split (profile_probability::even ());
 	  }
 	if (if_true_label == NULL)
 	  {
@@ -1120,16 +1118,27 @@ do_compare_rtx_and_jump (rtx op0, rtx op
 
 	  else
 	    {
-	      profile_probability first_prob = prob;
+	      profile_probability cprob
+		= profile_probability::guessed_always ();
 	      if (first_code == UNORDERED)
-		first_prob = profile_probability::guessed_always ().apply_scale
-				 (1, 100);
+		cprob = cprob.apply_scale (1, 100);
 	      else if (first_code == ORDERED)
-		first_prob = profile_probability::guessed_always ().apply_scale
-				 (99, 100);
+		cprob = cprob.apply_scale (99, 100);
+	      else
+		cprob = profile_probability::even ();
+	      /* We want to split:
+		 if (x) goto t; // prob;
+		 into
+		 if (a) goto t; // first_prob;
+		 if (b) goto t; // prob;
+		 such that the overall probability of jumping to t
+		 remains the same and first_prob is prob * cprob.  */
 	      if (and_them)
 		{
 		  rtx_code_label *dest_label;
+		  prob = prob.invert ();
+		  profile_probability first_prob = prob.split (cprob).invert ();
+		  prob = prob.invert ();
 		  /* If we only jump if true, just bypass the second jump.  */
 		  if (! if_false_label)
 		    {
@@ -1143,8 +1152,11 @@ do_compare_rtx_and_jump (rtx op0, rtx op
 					   size, dest_label, NULL, first_prob);
 		}
               else
-                do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
-					 size, NULL, if_true_label, first_prob);
+		{
+		  profile_probability first_prob = prob.split (cprob);
+		  do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
+					   size, NULL, if_true_label, first_prob);
+		}
 	    }
 	}
 
--- gcc/testsuite/gcc.dg/predict-8.c.jj	2017-10-12 20:51:33.192974887 +0200
+++ gcc/testsuite/gcc.dg/predict-8.c	2018-01-22 16:18:09.528071106 +0100
@@ -8,4 +8,4 @@ int foo(float a, float b) {
     return 2;
 }
 
-/* { dg-final { scan-rtl-dump-times "99.0. .guessed" 2 "expand"} } */
+/* { dg-final { scan-rtl-dump-times "65.\[34]. .guessed" 2 "expand"} } */

	Jakub
Jan Hubicka Jan. 22, 2018, 5:44 p.m. UTC | #7
Dne 2018-01-22 16:57, Jakub Jelinek napsal:
> On Mon, Jan 22, 2018 at 02:43:50PM +0100, Jan Hubicka wrote:
>> > But this looks incorrect, because that computes only the above c2 in
>> > prob, not
>> > second_prob.  It needs to be
>> >   prob = cprob.invert () * prob / first_prob.invert ();
>> > or
>> >   prob *= cprob.invert () / first_prob.invert ();
>> > or that
>> >   prob = (prob - first_prob) / first_prob.invert ();
>> > I had in the patch.  The last one looked to me like cheapest to compute.
>> 
>> Aha, I see.  Ok that makes sense to me now :)
>> >
>> > > void profile_probability::split (profile_probability cprob,
>> > > profile_probability *first_prob, profile_probability *second_prob)
>> >
>> > This doesn't take prob as an argument, or should it be a method and take
>> > prob as *this?  Couldn't it simply return first_prob and adjust itself,
>> > so
>> > profile_probability split (profile_probability cprob)
>> > {
>> >   profile_probability ret = *this * cprob;
>> >   *this = (*this - prob) / ret.invert ();
>> > // or *this = *this * cprob.invert () / ret.invert ();
>> >   return ret;
>> > }
>> > ?
>> 
>> Yep, that is fine.
> 
> So like this if it passes bootstrap/regtest on {x86_64,i686}-linux?
> 
> Besides adding the new helper method and using it in the spots I've 
> changed
> plus the two you've mentioned, I had to do another fix - looking
> at how TRUTH_ANDIF_EXPR is handled in dojump_1 and seeing Invalid sum
> messages in predict-8.c's *.expand jump, I've realized that it also 
> works
> as is only for the discussed, i.e.
>   if (x)
>     goto t; // prob
> transformed into:
>   if (a)
>     goto t; // first_prob
>   if (b)
>     goto t; // prob
> but not for the case where and_them is true, where we have:
>   if (c)
>     goto dummy; // first_prob.invert ()
>   if (d)
>     goto t; // prob
> dummy:
> which needs to be handled similarly to the TRUTH_ANDIF_EXPR case.
> At least when trying in gdb on predict-8.c various values of cprob
> (1%, 15%, 50%, 62%, 98%) none of them generate the Invalid sum 
> messages.
> 
> 2018-01-22  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/83081
> 	* profile-count.h (profile_probability::split): New method.
> 	* dojump.c (do_jump_1) <case TRUTH_ANDIF_EXPR, case TRUTH_ORIF_EXPR>:
> 	Use profile_probability::split.
> 	(do_compare_rtx_and_jump): Fix adjustment of probabilities
> 	when splitting a single conditional jump into 2.
> 
> 	* gcc.dg/predict-8.c: Adjust expected probability.
> 
> --- gcc/profile-count.h.jj	2018-01-19 19:41:52.910549618 +0100
> +++ gcc/profile-count.h	2018-01-22 16:20:27.073096515 +0100
> @@ -410,6 +410,19 @@ public:
>        return *this;
>      }
> 
> +  /* Split *THIS (ORIG) probability into 2 probabilities, such that
> +     the returned one (FIRST) is *THIS * CPROB and *THIS is
> +     adjusted (SECOND) so that FIRST + FIRST.invert () * SECOND
> +     == ORIG.  */

To make documentation clear, i would include the pseudocode with 
conditionals and individual
probabilities.
It is bit non-obvious transformation and it would be nice to reduce 
level of apparent
magicness in profiling code :)

OK,
Honza

> +  profile_probability split (const profile_probability &cprob)
> +    {
> +      profile_probability ret = *this * cprob;
> +      /* The following is equivalent to:
> +	 *this = cprob.invert () * *this / ret.invert ();  */
> +      *this = (*this - ret) / ret.invert ();
> +      return ret;
> +    }
> +
>    gcov_type apply (gcov_type val) const
>      {
>        if (*this == profile_probability::uninitialized ())
> --- gcc/dojump.c.jj	2018-01-19 19:41:49.978548984 +0100
> +++ gcc/dojump.c	2018-01-22 16:31:43.867185428 +0100
> @@ -347,13 +347,11 @@ do_jump_1 (enum tree_code code, tree op0
>          profile_probability op1_prob = 
> profile_probability::uninitialized ();
>          if (prob.initialized_p ())
>            {
> -            profile_probability false_prob = prob.invert ();
> -            profile_probability op0_false_prob = 
> false_prob.apply_scale (1, 2);
> -	    profile_probability op1_false_prob = false_prob.apply_scale (1, 
> 2)
> -				/ op0_false_prob.invert ();
> +	    op1_prob = prob.invert ();
> +	    op0_prob = op1_prob.split (profile_probability::even ());
>              /* Get the probability that each jump below is true.  */
> -            op0_prob = op0_false_prob.invert ();
> -            op1_prob = op1_false_prob.invert ();
> +	    op0_prob = op0_prob.invert ();
> +	    op1_prob = op1_prob.invert ();
>            }
>  	if (if_false_label == NULL)
>            {
> @@ -380,8 +378,8 @@ do_jump_1 (enum tree_code code, tree op0
>          profile_probability op1_prob = 
> profile_probability::uninitialized ();
>          if (prob.initialized_p ())
>            {
> -            op0_prob = prob.apply_scale (1, 2);
> -            op1_prob = prob.apply_scale (1, 2) / op0_prob.invert ();
> +	    op1_prob = prob;
> +	    op0_prob = op1_prob.split (profile_probability::even ());
>  	  }
>  	if (if_true_label == NULL)
>  	  {
> @@ -1120,16 +1118,27 @@ do_compare_rtx_and_jump (rtx op0, rtx op
> 
>  	  else
>  	    {
> -	      profile_probability first_prob = prob;
> +	      profile_probability cprob
> +		= profile_probability::guessed_always ();
>  	      if (first_code == UNORDERED)
> -		first_prob = profile_probability::guessed_always ().apply_scale
> -				 (1, 100);
> +		cprob = cprob.apply_scale (1, 100);
>  	      else if (first_code == ORDERED)
> -		first_prob = profile_probability::guessed_always ().apply_scale
> -				 (99, 100);
> +		cprob = cprob.apply_scale (99, 100);
> +	      else
> +		cprob = profile_probability::even ();
> +	      /* We want to split:
> +		 if (x) goto t; // prob;
> +		 into
> +		 if (a) goto t; // first_prob;
> +		 if (b) goto t; // prob;
> +		 such that the overall probability of jumping to t
> +		 remains the same and first_prob is prob * cprob.  */
>  	      if (and_them)
>  		{
>  		  rtx_code_label *dest_label;
> +		  prob = prob.invert ();
> +		  profile_probability first_prob = prob.split (cprob).invert ();
> +		  prob = prob.invert ();
>  		  /* If we only jump if true, just bypass the second jump.  */
>  		  if (! if_false_label)
>  		    {
> @@ -1143,8 +1152,11 @@ do_compare_rtx_and_jump (rtx op0, rtx op
>  					   size, dest_label, NULL, first_prob);
>  		}
>                else
> -                do_compare_rtx_and_jump (op0, op1, first_code, 
> unsignedp, mode,
> -					 size, NULL, if_true_label, first_prob);
> +		{
> +		  profile_probability first_prob = prob.split (cprob);
> +		  do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
> +					   size, NULL, if_true_label, first_prob);
> +		}
>  	    }
>  	}
> 
> --- gcc/testsuite/gcc.dg/predict-8.c.jj	2017-10-12 20:51:33.192974887 
> +0200
> +++ gcc/testsuite/gcc.dg/predict-8.c	2018-01-22 16:18:09.528071106 
> +0100
> @@ -8,4 +8,4 @@ int foo(float a, float b) {
>      return 2;
>  }
> 
> -/* { dg-final { scan-rtl-dump-times "99.0. .guessed" 2 "expand"} } */
> +/* { dg-final { scan-rtl-dump-times "65.\[34]. .guessed" 2 "expand"} } 
> */
> 
> 	Jakub
Jakub Jelinek Jan. 22, 2018, 6:36 p.m. UTC | #8
On Mon, Jan 22, 2018 at 06:44:17PM +0100, Jan Hubicka wrote:
> > +  /* Split *THIS (ORIG) probability into 2 probabilities, such that
> > +     the returned one (FIRST) is *THIS * CPROB and *THIS is
> > +     adjusted (SECOND) so that FIRST + FIRST.invert () * SECOND
> > +     == ORIG.  */
> 
> To make documentation clear, i would include the pseudocode with
> conditionals and individual
> probabilities.
> It is bit non-obvious transformation and it would be nice to reduce level of
> apparent
> magicness in profiling code :)

So like this?

2018-01-22  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/83081
	* profile-count.h (profile_probability::split): New method.
	* dojump.c (do_jump_1) <case TRUTH_ANDIF_EXPR, case TRUTH_ORIF_EXPR>:
	Use profile_probability::split.
	(do_compare_rtx_and_jump): Fix adjustment of probabilities
	when splitting a single conditional jump into 2.

	* gcc.dg/predict-8.c: Adjust expected probability.

--- gcc/profile-count.h.jj	2018-01-19 19:41:52.910549618 +0100
+++ gcc/profile-count.h	2018-01-22 16:20:27.073096515 +0100
@@ -410,6 +410,30 @@ public:
       return *this;
     }
 
+  /* Split *THIS (ORIG) probability into 2 probabilities, such that
+     the returned one (FIRST) is *THIS * CPROB and *THIS is
+     adjusted (SECOND) so that FIRST + FIRST.invert () * SECOND
+     == ORIG.  This is useful e.g. when splitting a conditional
+     branch like:
+     if (cond)
+       goto lab; // ORIG probability
+     into
+     if (cond1)
+       goto lab; // FIRST = ORIG * CPROB probability
+     if (cond2)
+       goto lab; // SECOND probability
+     such that the overall probability of jumping to lab remains
+     the same.  CPROB gives the relative probability between the
+     branches.  */
+  profile_probability split (const profile_probability &cprob)
+    {
+      profile_probability ret = *this * cprob;
+      /* The following is equivalent to:
+         *this = cprob.invert () * *this / ret.invert ();  */
+      *this = (*this - ret) / ret.invert ();
+      return ret;
+    }
+
   gcov_type apply (gcov_type val) const
     {
       if (*this == profile_probability::uninitialized ())
--- gcc/dojump.c.jj	2018-01-19 19:41:49.978548984 +0100
+++ gcc/dojump.c	2018-01-22 16:31:43.867185428 +0100
@@ -347,13 +347,11 @@ do_jump_1 (enum tree_code code, tree op0
         profile_probability op1_prob = profile_probability::uninitialized ();
         if (prob.initialized_p ())
           {
-            profile_probability false_prob = prob.invert ();
-            profile_probability op0_false_prob = false_prob.apply_scale (1, 2);
-	    profile_probability op1_false_prob = false_prob.apply_scale (1, 2)
-				/ op0_false_prob.invert ();
+	    op1_prob = prob.invert ();
+	    op0_prob = op1_prob.split (profile_probability::even ());
             /* Get the probability that each jump below is true.  */
-            op0_prob = op0_false_prob.invert ();
-            op1_prob = op1_false_prob.invert ();
+	    op0_prob = op0_prob.invert ();
+	    op1_prob = op1_prob.invert ();
           }
 	if (if_false_label == NULL)
           {
@@ -380,8 +378,8 @@ do_jump_1 (enum tree_code code, tree op0
         profile_probability op1_prob = profile_probability::uninitialized ();
         if (prob.initialized_p ())
           {
-            op0_prob = prob.apply_scale (1, 2);
-            op1_prob = prob.apply_scale (1, 2) / op0_prob.invert ();
+	    op1_prob = prob;
+	    op0_prob = op1_prob.split (profile_probability::even ());
 	  }
 	if (if_true_label == NULL)
 	  {
@@ -1120,16 +1118,27 @@ do_compare_rtx_and_jump (rtx op0, rtx op
 
 	  else
 	    {
-	      profile_probability first_prob = prob;
+	      profile_probability cprob
+		= profile_probability::guessed_always ();
 	      if (first_code == UNORDERED)
-		first_prob = profile_probability::guessed_always ().apply_scale
-				 (1, 100);
+		cprob = cprob.apply_scale (1, 100);
 	      else if (first_code == ORDERED)
-		first_prob = profile_probability::guessed_always ().apply_scale
-				 (99, 100);
+		cprob = cprob.apply_scale (99, 100);
+	      else
+		cprob = profile_probability::even ();
+	      /* We want to split:
+		 if (x) goto t; // prob;
+		 into
+		 if (a) goto t; // first_prob;
+		 if (b) goto t; // prob;
+		 such that the overall probability of jumping to t
+		 remains the same and first_prob is prob * cprob.  */
 	      if (and_them)
 		{
 		  rtx_code_label *dest_label;
+		  prob = prob.invert ();
+		  profile_probability first_prob = prob.split (cprob).invert ();
+		  prob = prob.invert ();
 		  /* If we only jump if true, just bypass the second jump.  */
 		  if (! if_false_label)
 		    {
@@ -1143,8 +1152,11 @@ do_compare_rtx_and_jump (rtx op0, rtx op
 					   size, dest_label, NULL, first_prob);
 		}
               else
-                do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
-					 size, NULL, if_true_label, first_prob);
+		{
+		  profile_probability first_prob = prob.split (cprob);
+		  do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
+					   size, NULL, if_true_label, first_prob);
+		}
 	    }
 	}
 
--- gcc/testsuite/gcc.dg/predict-8.c.jj	2017-10-12 20:51:33.192974887 +0200
+++ gcc/testsuite/gcc.dg/predict-8.c	2018-01-22 16:18:09.528071106 +0100
@@ -8,4 +8,4 @@ int foo(float a, float b) {
     return 2;
 }
 
-/* { dg-final { scan-rtl-dump-times "99.0. .guessed" 2 "expand"} } */
+/* { dg-final { scan-rtl-dump-times "65.\[34]. .guessed" 2 "expand"} } */


	Jakub
Jan Hubicka Jan. 22, 2018, 7:58 p.m. UTC | #9
Dne 2018-01-22 19:36, Jakub Jelinek napsal:
> On Mon, Jan 22, 2018 at 06:44:17PM +0100, Jan Hubicka wrote:
>> > +  /* Split *THIS (ORIG) probability into 2 probabilities, such that
>> > +     the returned one (FIRST) is *THIS * CPROB and *THIS is
>> > +     adjusted (SECOND) so that FIRST + FIRST.invert () * SECOND
>> > +     == ORIG.  */
>> 
>> To make documentation clear, i would include the pseudocode with
>> conditionals and individual
>> probabilities.
>> It is bit non-obvious transformation and it would be nice to reduce 
>> level of
>> apparent
>> magicness in profiling code :)
> 
> So like this?
> 
> 2018-01-22  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/83081
> 	* profile-count.h (profile_probability::split): New method.
> 	* dojump.c (do_jump_1) <case TRUTH_ANDIF_EXPR, case TRUTH_ORIF_EXPR>:
> 	Use profile_probability::split.
> 	(do_compare_rtx_and_jump): Fix adjustment of probabilities
> 	when splitting a single conditional jump into 2.
> 
> 	* gcc.dg/predict-8.c: Adjust expected probability.

Looks great. Thanks a lot!
Honza
> 
> --- gcc/profile-count.h.jj	2018-01-19 19:41:52.910549618 +0100
> +++ gcc/profile-count.h	2018-01-22 16:20:27.073096515 +0100
> @@ -410,6 +410,30 @@ public:
>        return *this;
>      }
> 
> +  /* Split *THIS (ORIG) probability into 2 probabilities, such that
> +     the returned one (FIRST) is *THIS * CPROB and *THIS is
> +     adjusted (SECOND) so that FIRST + FIRST.invert () * SECOND
> +     == ORIG.  This is useful e.g. when splitting a conditional
> +     branch like:
> +     if (cond)
> +       goto lab; // ORIG probability
> +     into
> +     if (cond1)
> +       goto lab; // FIRST = ORIG * CPROB probability
> +     if (cond2)
> +       goto lab; // SECOND probability
> +     such that the overall probability of jumping to lab remains
> +     the same.  CPROB gives the relative probability between the
> +     branches.  */
> +  profile_probability split (const profile_probability &cprob)
> +    {
> +      profile_probability ret = *this * cprob;
> +      /* The following is equivalent to:
> +         *this = cprob.invert () * *this / ret.invert ();  */
> +      *this = (*this - ret) / ret.invert ();
> +      return ret;
> +    }
> +
>    gcov_type apply (gcov_type val) const
>      {
>        if (*this == profile_probability::uninitialized ())
> --- gcc/dojump.c.jj	2018-01-19 19:41:49.978548984 +0100
> +++ gcc/dojump.c	2018-01-22 16:31:43.867185428 +0100
> @@ -347,13 +347,11 @@ do_jump_1 (enum tree_code code, tree op0
>          profile_probability op1_prob = 
> profile_probability::uninitialized ();
>          if (prob.initialized_p ())
>            {
> -            profile_probability false_prob = prob.invert ();
> -            profile_probability op0_false_prob = 
> false_prob.apply_scale (1, 2);
> -	    profile_probability op1_false_prob = false_prob.apply_scale (1, 
> 2)
> -				/ op0_false_prob.invert ();
> +	    op1_prob = prob.invert ();
> +	    op0_prob = op1_prob.split (profile_probability::even ());
>              /* Get the probability that each jump below is true.  */
> -            op0_prob = op0_false_prob.invert ();
> -            op1_prob = op1_false_prob.invert ();
> +	    op0_prob = op0_prob.invert ();
> +	    op1_prob = op1_prob.invert ();
>            }
>  	if (if_false_label == NULL)
>            {
> @@ -380,8 +378,8 @@ do_jump_1 (enum tree_code code, tree op0
>          profile_probability op1_prob = 
> profile_probability::uninitialized ();
>          if (prob.initialized_p ())
>            {
> -            op0_prob = prob.apply_scale (1, 2);
> -            op1_prob = prob.apply_scale (1, 2) / op0_prob.invert ();
> +	    op1_prob = prob;
> +	    op0_prob = op1_prob.split (profile_probability::even ());
>  	  }
>  	if (if_true_label == NULL)
>  	  {
> @@ -1120,16 +1118,27 @@ do_compare_rtx_and_jump (rtx op0, rtx op
> 
>  	  else
>  	    {
> -	      profile_probability first_prob = prob;
> +	      profile_probability cprob
> +		= profile_probability::guessed_always ();
>  	      if (first_code == UNORDERED)
> -		first_prob = profile_probability::guessed_always ().apply_scale
> -				 (1, 100);
> +		cprob = cprob.apply_scale (1, 100);
>  	      else if (first_code == ORDERED)
> -		first_prob = profile_probability::guessed_always ().apply_scale
> -				 (99, 100);
> +		cprob = cprob.apply_scale (99, 100);
> +	      else
> +		cprob = profile_probability::even ();
> +	      /* We want to split:
> +		 if (x) goto t; // prob;
> +		 into
> +		 if (a) goto t; // first_prob;
> +		 if (b) goto t; // prob;
> +		 such that the overall probability of jumping to t
> +		 remains the same and first_prob is prob * cprob.  */
>  	      if (and_them)
>  		{
>  		  rtx_code_label *dest_label;
> +		  prob = prob.invert ();
> +		  profile_probability first_prob = prob.split (cprob).invert ();
> +		  prob = prob.invert ();
>  		  /* If we only jump if true, just bypass the second jump.  */
>  		  if (! if_false_label)
>  		    {
> @@ -1143,8 +1152,11 @@ do_compare_rtx_and_jump (rtx op0, rtx op
>  					   size, dest_label, NULL, first_prob);
>  		}
>                else
> -                do_compare_rtx_and_jump (op0, op1, first_code, 
> unsignedp, mode,
> -					 size, NULL, if_true_label, first_prob);
> +		{
> +		  profile_probability first_prob = prob.split (cprob);
> +		  do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
> +					   size, NULL, if_true_label, first_prob);
> +		}
>  	    }
>  	}
> 
> --- gcc/testsuite/gcc.dg/predict-8.c.jj	2017-10-12 20:51:33.192974887 
> +0200
> +++ gcc/testsuite/gcc.dg/predict-8.c	2018-01-22 16:18:09.528071106 
> +0100
> @@ -8,4 +8,4 @@ int foo(float a, float b) {
>      return 2;
>  }
> 
> -/* { dg-final { scan-rtl-dump-times "99.0. .guessed" 2 "expand"} } */
> +/* { dg-final { scan-rtl-dump-times "65.\[34]. .guessed" 2 "expand"} } 
> */
> 
> 
> 	Jakub
diff mbox series

Patch

--- gcc/dojump.c.jj	2018-01-03 10:19:55.000000000 +0100
+++ gcc/dojump.c	2018-01-19 17:07:25.238927314 +0100
@@ -1122,11 +1122,30 @@  do_compare_rtx_and_jump (rtx op0, rtx op
 	    {
 	      profile_probability first_prob = prob;
 	      if (first_code == UNORDERED)
-		first_prob = profile_probability::guessed_always ().apply_scale
-				 (1, 100);
+		{
+		  /* We want to split:
+		     if (x) goto t; // prob;
+		     into
+		     if (a) goto t; // first_prob;
+		     if (b) goto t; // prob;
+		     such that the overall probability of jumping to t
+		     remains the same, but the first jump jumps
+		     much less often than the second jump.  */
+		  first_prob = prob.guessed ().apply_scale (1, 100);
+		  prob = (prob.guessed () - first_prob) / first_prob.invert ();
+		}
 	      else if (first_code == ORDERED)
-		first_prob = profile_probability::guessed_always ().apply_scale
-				 (99, 100);
+		{
+		  /* See above, except the first jump should jump much more
+		     often than the second one.  */
+		  first_prob = prob.guessed ().apply_scale (99, 100);
+		  prob = (prob.guessed () - first_prob) / first_prob.invert ();
+		}
+	      else
+		{
+		  first_prob = prob.guessed ().apply_scale (50, 100);
+		  prob = first_prob;
+		}
 	      if (and_them)
 		{
 		  rtx_code_label *dest_label;
--- gcc/testsuite/gcc.dg/predict-8.c.jj	2017-11-21 23:17:43.149093787 +0100
+++ gcc/testsuite/gcc.dg/predict-8.c	2018-01-19 22:24:09.949249810 +0100
@@ -8,4 +8,4 @@  int foo(float a, float b) {
     return 2;
 }
 
-/* { dg-final { scan-rtl-dump-times "99.0. .guessed" 2 "expand"} } */
+/* { dg-final { scan-rtl-dump-times "64.[34]. .guessed" 2 "expand"} } */