Ping.
Thanks,
Kyrill

> On 24 Jul 2026, at 14:27, Kyrylo Tkachov <[email protected]> wrote:
> 
> Ping.
> Thanks,
> Kyrill
> 
>> On 17 Jul 2026, at 15:25, Kyrylo Tkachov <[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-linux-gnu and x86_64-linux.
>> Ok for trunk?
>> 
>> Thanks,
>> Kyrill
>> 
>> gcc/ChangeLog:
>> 
>> * profile-count.h (profile_probability::apply): Scale an unsigned
>> magnitude with safe_scale_64bit.
>> * profile-count.cc (test_profile_probability_apply): New.
>> (profile_count_cc_tests): New.
>> * selftest.h (profile_count_cc_tests): Declare.
>> * selftest-run-tests.cc (selftest::run_tests): Run it.
>> 
>> Signed-off-by: Kyrylo Tkachov <[email protected]>
>> ---
>> gcc/profile-count.cc      | 47 +++++++++++++++++++++++++++++++++++++++
>> gcc/profile-count.h       | 26 +++++++++++++++++++++-
>> gcc/selftest-run-tests.cc |  1 +
>> gcc/selftest.h            |  1 +
>> 4 files changed, 74 insertions(+), 1 deletion(-)
>> 
>> diff --git a/gcc/profile-count.cc b/gcc/profile-count.cc
>> index 2cce9caa772..9be209efda2 100644
>> --- a/gcc/profile-count.cc
>> +++ b/gcc/profile-count.cc
>> @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
>> #include "wide-int.h"
>> #include "sreal.h"
>> #include "profile.h"
>> +#include "selftest.h"
>> 
>> /* Names from profile_quality enum values.  */
>> 
>> @@ -595,3 +596,49 @@ profile_count::force_nonzero () const
>>    }
>>  return ret;
>> }
>> +
>> +#if CHECKING_P
>> +
>> +namespace selftest {
>> +
>> +/* Verify profile_probability::apply.  */
>> +
>> +static void
>> +test_profile_probability_apply ()
>> +{
>> +  const gcov_type min = INTTYPE_MINIMUM (gcov_type);
>> +  const gcov_type max = INTTYPE_MAXIMUM (gcov_type);
>> +  profile_probability quarter = profile_probability::guessed_always () / 4;
>> +  profile_probability even = profile_probability::even ();
>> +
>> +  ASSERT_EQ (1, quarter.apply (3));
>> +  ASSERT_EQ (-1, quarter.apply (-3));
>> +  ASSERT_EQ (2, even.apply (3));
>> +  ASSERT_EQ (-2, even.apply (-3));
>> +  ASSERT_EQ (0, even.apply (0));
>> +
>> +  ASSERT_EQ (0, profile_probability::never ().apply (min));
>> +  ASSERT_EQ (min, profile_probability::always ().apply (min));
>> +  ASSERT_EQ (max, profile_probability::always ().apply (max));
>> +  ASSERT_EQ (min, profile_probability::guessed_always ().apply (min));
>> +  ASSERT_EQ (min / 2, even.apply (min));
>> +  ASSERT_EQ (max / 2 + 1, even.apply (max));
>> +
>> +  profile_probability uninitialized = profile_probability::uninitialized ();
>> +  ASSERT_EQ (1, uninitialized.apply (3));
>> +  ASSERT_EQ (-1, uninitialized.apply (-3));
>> +  ASSERT_EQ (min / 2, uninitialized.apply (min));
>> +  ASSERT_EQ (max / 2, uninitialized.apply (max));
>> +}
>> +
>> +/* Run all of the selftests within this file.  */
>> +
>> +void
>> +profile_count_cc_tests ()
>> +{
>> +  test_profile_probability_apply ();
>> +}
>> +
>> +} // namespace selftest
>> +
>> +#endif
>> diff --git a/gcc/profile-count.h b/gcc/profile-count.h
>> index b424ecba3ea..76325d0fdfa 100644
>> --- a/gcc/profile-count.h
>> +++ b/gcc/profile-count.h
>> @@ -513,11 +513,35 @@ public:
>>      return ret;
>>    }
>> 
>> +  /* Return VAL scaled by this probability.  Round initialized probabilities
>> +     to the nearest integer, with halfway values away from zero.  Treat an
>> +     uninitialized probability as one half and truncate toward zero.  */
>>  gcov_type apply (gcov_type val) const
>>    {
>>      if (*this == uninitialized ())
>> return val / 2;
>> -      return RDIV (val * m_val, max_probability);
>> +
>> +      /* A unit probability leaves VAL unchanged.  Return it directly 
>> because
>> + the magnitude of the minimum gcov_type value is one greater than the
>> + maximum gcov_type value.  */
>> +      if (m_val == max_probability)
>> + return val;
>> +
>> +      /* Convert to unsigned before negating so that the minimum gcov_type
>> + value has a representable magnitude.  Scale the magnitude with
>> + overflow-safe arithmetic, then restore the sign.  */
>> +      gcov_type_unsigned magnitude
>> + = val < 0 ? -(gcov_type_unsigned) val : (gcov_type_unsigned) val;
>> +      uint64_t scaled;
>> +      bool scaled_p
>> + = safe_scale_64bit (magnitude, m_val, max_probability, &scaled);
>> +      /* The scaled result fits in uint64_t.  With the unit case handled 
>> above,
>> + it also fits in the nonnegative range of gcov_type.  */
>> +      gcc_checking_assert (scaled_p);
>> +      gcc_checking_assert
>> + (scaled <= (gcov_type_unsigned) INTTYPE_MAXIMUM (gcov_type));
>> +
>> +      return val < 0 ? -(gcov_type) scaled : (gcov_type) scaled;
>>    }
>> 
>>  /* Return 1-*THIS.  */
>> diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc
>> index e39a94f8688..a281a239b10 100644
>> --- a/gcc/selftest-run-tests.cc
>> +++ b/gcc/selftest-run-tests.cc
>> @@ -72,6 +72,7 @@ selftest::run_tests ()
>>  wide_int_cc_tests ();
>>  ggc_tests_cc_tests ();
>>  sreal_cc_tests ();
>> +  profile_count_cc_tests ();
>>  fibonacci_heap_cc_tests ();
>>  typed_splay_tree_cc_tests ();
>>  opt_suggestions_cc_tests ();
>> diff --git a/gcc/selftest.h b/gcc/selftest.h
>> index 8891d0b7b6f..f9dacd69af7 100644
>> --- a/gcc/selftest.h
>> +++ b/gcc/selftest.h
>> @@ -248,6 +248,7 @@ extern void path_coverage_cc_tests ();
>> extern void predict_cc_tests ();
>> extern void pretty_print_cc_tests ();
>> extern void pretty_print_token_buffer_cc_tests ();
>> +extern void profile_count_cc_tests ();
>> extern void pub_sub_cc_tests ();
>> extern void range_op_tests ();
>> extern void range_tests ();
>> -- 
>> 2.50.1 (Apple Git-155)
>> 
> 

Reply via email to