Re: [PATCH 1/3] profile-count: Handle signed values in profile_probability::apply

Jeffrey Law <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>

On 8/11/2026 2:38 AM, Kyrylo Tkachov wrote:
>
>> On 11 Aug 2026, at 08:31, Richard Biener <[email protected]> wrote:
>>
>> On Mon, Aug 10, 2026 at 4:28 PM <[email protected]> wrote:
>>> From: Kyrylo Tkachov <[email protected]>
>>>
>>> profile_probability::apply uses RDIV, which adds half the denominator
>>> before division.  This does not round negative values correctly.
>>> Multiplying the signed input by the fixed-point probability can also
>>> overflow for large inputs.
>>>
>>> Scale the unsigned magnitude with safe_scale_64bit, then restore the sign.
>>> Return the input directly for a unit probability so that the minimum
>>> gcov_type value remains representable.  Preserve the existing truncation
>>> for uninitialized probabilities.
>>>
>>> Add selftests for signed rounding, zero and unit probabilities,
>>> uninitialized probabilities, and the minimum and maximum gcov_type values.
>>>
>>> Bootstrapped and tested on aarch64-none-linux and x86_64-linux.
>>> Ok for trunk?
>> So the reason I have not yet acked this is that I wonder why we'd have
>> negative probabilities at all?  To me that doesn't make sense.
> There are no negative probabilities here.
> profile_probability remains in the range from zero to one. The signed quantity is the gcov_type val argument to profile_probability::apply.
> Before patch 2, ifcvt calls it with an arm-cost delta:
> e->probability.apply ((signed) (then_cost - else_cost))
>
> The intended value is negative when then_cost is less than else_cost. For example, applying a probability of one half to -3 gives -1 with the old RDIV expression, instead of -2 with symmetric nearest rounding. The signed multiplication can also overflow for large value arguments.
>
> This patch keeps the probability unsigned and in range. It scales the unsigned magnitude of val and then restores the sign. Patch 2 changes average_cost to pass a nonnegative delta. That is a separate change which makes the rounded cost independent of CFG arm order.
I think a bit more context may help here.  If we look at average_cost:

/* Compute average of two given costs weighted by relative probabilities
    of respective basic blocks in an IF-THEN-ELSE.  E is the IF-THEN edge.
    With P as the probability to take the IF-THEN branch, return
    P * THEN_COST + (1 - P) * ELSE_COST.  */
static unsigned
average_cost (unsigned then_cost, unsigned else_cost, edge e)
{
   return else_cost + e->probability.apply ((signed) (then_cost - 
else_cost));
}

Of course this gets rewritten in patch #2.  So it's less of an issue.  
Though this does show a mostly reasonable way to use the APIs that can 
result in a negative value being passed in and adjusts the code to 
handle it more correctly.

Jeff
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.