Fix runtime error: left shift of negative value (PR
authorMartin Liska <mliska@suse.cz>
Fri, 2 Dec 2016 08:36:01 +0000 (09:36 +0100)
committerMartin Liska <marxin@gcc.gnu.org>
Fri, 2 Dec 2016 08:36:01 +0000 (08:36 +0000)
PR ipa/78555
* sreal.c (sreal::to_int): Make absolute value before shifting.
(sreal::operator/): Likewise.
(sreal_verify_negative_division): New test.
(void sreal_c_tests): Call the new test.
* sreal.h (sreal::normalize_up): Use new SREAL_ABS and
SREAL_SIGN macros.
(sreal::normalize_down): Likewise.

From-SVN: r243163

gcc/ChangeLog
gcc/sreal.c
gcc/sreal.h

index a3fcd8b6d0b0c7b1cff9994063ab0ef72a7e6120..445384226cc4fe5286403a39431e1cb17fd1b99d 100644 (file)
@@ -1,3 +1,14 @@
+2016-12-02  Martin Liska  <mliska@suse.cz>
+
+       PR ipa/78555
+       * sreal.c (sreal::to_int): Make absolute value before shifting.
+       (sreal::operator/): Likewise.
+       (sreal_verify_negative_division): New test.
+       (void sreal_c_tests): Call the new test.
+       * sreal.h (sreal::normalize_up): Use new SREAL_ABS and
+       SREAL_SIGN macros.
+       (sreal::normalize_down): Likewise.
+
 2016-12-02  Dominik Vogt  <vogt@linux.vnet.ibm.com>
 
        * combine.c (combine_simplify_rtx):  Suppress replacement of
index 9c43b4eed21e20bd66a86d09b0e477ae90e22c1a..52e530d623f1462d97a4ae642d024866f3e0cd78 100644 (file)
@@ -102,14 +102,14 @@ sreal::shift_right (int s)
 int64_t
 sreal::to_int () const
 {
-  int64_t sign = m_sig < 0 ? -1 : 1;
+  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 m_sig << m_exp;
+    return sign * (SREAL_ABS (m_sig) << m_exp);
   if (m_exp < 0)
     return m_sig >> -m_exp;
   return m_sig;
@@ -229,7 +229,8 @@ sreal::operator/ (const sreal &other) const
 {
   gcc_checking_assert (other.m_sig != 0);
   sreal r;
-  r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
+  r.m_sig
+    = SREAL_SIGN (m_sig) * (SREAL_ABS (m_sig) << SREAL_PART_BITS) / other.m_sig;
   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
   r.normalize ();
   return r;
@@ -334,6 +335,18 @@ sreal_verify_shifting (void)
     verify_shifting (values[i]);
 }
 
+/* Verify division by (of) a negative value.  */
+
+static void
+sreal_verify_negative_division (void)
+{
+  ASSERT_EQ (sreal (1) / sreal (1), sreal (1));
+  ASSERT_EQ (sreal (-1) / sreal (-1), sreal (1));
+  ASSERT_EQ (sreal (-1234567) / sreal (-1234567), sreal (1));
+  ASSERT_EQ (sreal (-1234567) / sreal (1234567), sreal (-1));
+  ASSERT_EQ (sreal (1234567) / sreal (-1234567), sreal (-1));
+}
+
 /* Run all of the selftests within this file.  */
 
 void sreal_c_tests ()
@@ -341,6 +354,7 @@ void sreal_c_tests ()
   sreal_verify_basics ();
   sreal_verify_arithmetics ();
   sreal_verify_shifting ();
+  sreal_verify_negative_division ();
 }
 
 } // namespace selftest
index ce9cdbbfded8e938106c72f5d5c548356641cd99..21f14b0182120081ed5a84c8495da486774fdd00 100644 (file)
@@ -31,6 +31,9 @@ along with GCC; see the file COPYING3.  If not see
 
 #define SREAL_BITS SREAL_PART_BITS
 
+#define SREAL_SIGN(v) (v < 0 ? -1: 1)
+#define SREAL_ABS(v) (v < 0 ? -v: v)
+
 /* Structure for holding a simple real number.  */
 class sreal
 {
@@ -193,7 +196,6 @@ inline sreal operator>> (const sreal &a, int exp)
 inline void
 sreal::normalize_up ()
 {
-  int64_t s = m_sig < 0 ? -1 : 1;
   unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);
   int shift = SREAL_PART_BITS - 2 - floor_log2 (sig);
 
@@ -208,7 +210,7 @@ sreal::normalize_up ()
       m_exp = -SREAL_MAX_EXP;
       sig = 0;
     }
-  if (s == -1)
+  if (SREAL_SIGN (m_sig) == -1)
     m_sig = -sig;
   else
     m_sig = sig;
@@ -221,7 +223,6 @@ sreal::normalize_up ()
 inline void
 sreal::normalize_down ()
 {
-  int64_t s = m_sig < 0 ? -1 : 1;
   int last_bit;
   unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);
   int shift = floor_log2 (sig) - SREAL_PART_BITS + 2;
@@ -246,7 +247,7 @@ sreal::normalize_down ()
       m_exp = SREAL_MAX_EXP;
       sig = SREAL_MAX_SIG;
     }
-  if (s == -1)
+  if (SREAL_SIGN (m_sig) == -1)
     m_sig = -sig;
   else
     m_sig = sig;