diff mbox series

Fix sreal::to_int and implement sreal::to_nearest_int

Message ID ZLqaIhXmspiXfoVl@kam.mff.cuni.cz
State New
Headers show
Series Fix sreal::to_int and implement sreal::to_nearest_int | expand

Commit Message

Jan Hubicka July 21, 2023, 2:45 p.m. UTC
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
Probably not big deal in practice as we do not do conversions on
negative values.

Fix is easy, we need to correctly shift in positive values.  This patch fixes
it and adds the to_nearest_int alternative.

Bootstrapped/regtested x86_64-linux, will commit it shortly.

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 mbox series

Patch

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 *);