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

Kyrylo Tkachov <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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)
>> 
>
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.