diff options
author | Jan Hubicka <jh@suse.cz> | 2023-07-21 16:44:01 +0200 |
---|---|---|
committer | Jan Hubicka <jh@suse.cz> | 2023-07-21 16:44:01 +0200 |
commit | e35d297fc9a625f11d861b6feacb228810e4e6bd (patch) | |
tree | cff62b168fc72eb4b5ff88c7b50b2362b02dd807 /gcc | |
parent | 65ff4a45b11b5ab13ef849bd5721ab28ff316202 (diff) | |
download | gcc-e35d297fc9a625f11d861b6feacb228810e4e6bd.zip gcc-e35d297fc9a625f11d861b6feacb228810e4e6bd.tar.gz gcc-e35d297fc9a625f11d861b6feacb228810e4e6bd.tar.bz2 |
Fix sreal::to_int and implement sreal::to_nearest_int
while exploring new loop estimate dumps, I noticed that loop iterating 1.8
times by profile is etimated as iterating once instead of 2 by nb_estimate.
While nb_estimate should really be a sreal and I will convert it incrementally,
I found problem is in previous patch doing:
+ *nit = (snit + 0.5).to_int ();
this does not work for sreal because it has only constructor from integer, so
first 0.5 is rounded to 0 and then added to snit.
Some code uses sreal(1, -1) which produces 0.5, but it reuqires unnecessary
addition, so I decided to add to_nearest_int. Testing it I noticed that to_int
is buggy:
(sreal(3)/2).to_int () == 1
while
(sreal(-3)/2).to_int () == -2
Fix is easy, we need to correctly shift in positive values. This patch fixes
it and adds the to_nearest_int alternative.
gcc/ChangeLog:
* sreal.cc (sreal::to_nearest_int): New.
(sreal_verify_basics): Verify also to_nearest_int.
(verify_aritmetics): Likewise.
(sreal_verify_conversions): New.
(sreal_cc_tests): Call sreal_verify_conversions.
* sreal.h: (sreal::to_nearest_int): Declare
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/sreal.cc | 55 | ||||
-rw-r--r-- | gcc/sreal.h | 1 |
2 files changed, 55 insertions, 1 deletions
diff --git a/gcc/sreal.cc b/gcc/sreal.cc index 8e99d87..606a571 100644 --- a/gcc/sreal.cc +++ b/gcc/sreal.cc @@ -116,7 +116,26 @@ sreal::to_int () const if (m_exp > 0) return sign * (SREAL_ABS ((int64_t)m_sig) << m_exp); if (m_exp < 0) - return m_sig >> -m_exp; + return sign * (SREAL_ABS ((int64_t)m_sig) >> -m_exp); + return m_sig; +} + +/* Return nearest integer value of *this. */ + +int64_t +sreal::to_nearest_int () const +{ + int64_t sign = SREAL_SIGN (m_sig); + + if (m_exp <= -SREAL_BITS) + return 0; + if (m_exp >= SREAL_PART_BITS) + return sign * INTTYPE_MAXIMUM (int64_t); + if (m_exp > 0) + return sign * (SREAL_ABS ((int64_t)m_sig) << m_exp); + if (m_exp < 0) + return sign * ((SREAL_ABS ((int64_t)m_sig) >> -m_exp) + + ((SREAL_ABS (m_sig) >> (-m_exp - 1)) & 1)); return m_sig; } @@ -286,6 +305,8 @@ sreal_verify_basics (void) ASSERT_EQ (INT_MIN/2, minimum.to_int ()); ASSERT_EQ (INT_MAX/2, maximum.to_int ()); + ASSERT_EQ (INT_MIN/2, minimum.to_nearest_int ()); + ASSERT_EQ (INT_MAX/2, maximum.to_nearest_int ()); ASSERT_FALSE (minus_two < minus_two); ASSERT_FALSE (seven < seven); @@ -315,6 +336,10 @@ verify_aritmetics (int64_t a, int64_t b) ASSERT_EQ (a - b, (sreal (a) - sreal (b)).to_int ()); ASSERT_EQ (b + a, (sreal (b) + sreal (a)).to_int ()); ASSERT_EQ (b - a, (sreal (b) - sreal (a)).to_int ()); + ASSERT_EQ (a + b, (sreal (a) + sreal (b)).to_nearest_int ()); + ASSERT_EQ (a - b, (sreal (a) - sreal (b)).to_nearest_int ()); + ASSERT_EQ (b + a, (sreal (b) + sreal (a)).to_nearest_int ()); + ASSERT_EQ (b - a, (sreal (b) - sreal (a)).to_nearest_int ()); } /* Verify arithmetics for interesting numbers. */ @@ -377,6 +402,33 @@ sreal_verify_negative_division (void) ASSERT_EQ (sreal (1234567) / sreal (-1234567), sreal (-1)); } +static void +sreal_verify_conversions (void) +{ + ASSERT_EQ ((sreal (11) / sreal (3)).to_int (), 3); + ASSERT_EQ ((sreal (11) / sreal (3)).to_nearest_int (), 4); + ASSERT_EQ ((sreal (10) / sreal (3)).to_int (), 3); + ASSERT_EQ ((sreal (10) / sreal (3)).to_nearest_int (), 3); + ASSERT_EQ ((sreal (9) / sreal (3)).to_int (), 3); + ASSERT_EQ ((sreal (9) / sreal (3)).to_nearest_int (), 3); + ASSERT_EQ ((sreal (-11) / sreal (3)).to_int (), -3); + ASSERT_EQ ((sreal (-11) / sreal (3)).to_nearest_int (), -4); + ASSERT_EQ ((sreal (-10) / sreal (3)).to_int (), -3); + ASSERT_EQ ((sreal (-10) / sreal (3)).to_nearest_int (), -3); + ASSERT_EQ ((sreal (-3)).to_int (), -3); + ASSERT_EQ ((sreal (-3)).to_nearest_int (), -3); + for (int i = -100000 ; i < 100000; i += 123) + for (int j = -10000 ; j < 100000; j += 71) + if (j != 0) + { + sreal sval = ((sreal)i) / (sreal)j; + double val = (double)i / (double)j; + ASSERT_EQ ((fabs (sval.to_double () - val) < 0.00001), true); + ASSERT_EQ (sval.to_int (), (int)val); + ASSERT_EQ (sval.to_nearest_int (), lround (val)); + } +} + /* Run all of the selftests within this file. */ void sreal_cc_tests () @@ -385,6 +437,7 @@ void sreal_cc_tests () sreal_verify_arithmetics (); sreal_verify_shifting (); sreal_verify_negative_division (); + sreal_verify_conversions (); } } // namespace selftest diff --git a/gcc/sreal.h b/gcc/sreal.h index 8700807..4dbb83c 100644 --- a/gcc/sreal.h +++ b/gcc/sreal.h @@ -51,6 +51,7 @@ public: void dump (FILE *) const; int64_t to_int () const; + int64_t to_nearest_int () const; double to_double () const; void stream_out (struct output_block *); static sreal stream_in (class lto_input_block *); |