public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-2710] Fix sreal::to_int and implement sreal::to_nearest_int
@ 2023-07-21 14:44 Jan Hubicka
  0 siblings, 0 replies; only message in thread
From: Jan Hubicka @ 2023-07-21 14:44 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:e35d297fc9a625f11d861b6feacb228810e4e6bd

commit r14-2710-ge35d297fc9a625f11d861b6feacb228810e4e6bd
Author: Jan Hubicka <jh@suse.cz>
Date:   Fri Jul 21 16:44:01 2023 +0200

    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

Diff:
---
 gcc/sreal.cc | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gcc/sreal.h  |  1 +
 2 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/gcc/sreal.cc b/gcc/sreal.cc
index 8e99d871420..606a571e339 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 8700807a131..4dbb83c3005 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 *);

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-07-21 14:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-21 14:44 [gcc r14-2710] Fix sreal::to_int and implement sreal::to_nearest_int Jan Hubicka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).