Additions to gdb_mpz
authorTom Tromey <tromey@adacore.com>
Mon, 27 Mar 2023 20:35:17 +0000 (14:35 -0600)
committerTom Tromey <tromey@adacore.com>
Mon, 17 Apr 2023 16:43:06 +0000 (10:43 -0600)
In preparation for adding more 128-bit support to gdb, a few additions
to gdb_mpz are needed.

First, this adds a new 'as_integer_truncate' method.  This method
works like 'as_integer' but does not require the value to fit in the
target type -- it just truncates.

Second, gdb_mpz::export_bits is changed to handle the somewhat unusual
situation of zero-length types.  This can happen for a Rust '()' type;
but I think other languages have zero-bit integer types as well.

Finally, this adds some operator== overloads.

gdb/gmp-utils.c
gdb/gmp-utils.h

index 0afa344781b703b2e3ced03fd245c0c9d6a984e1..13fa61d61e30aa5b156ce96243de129e079e7d92 100644 (file)
@@ -69,19 +69,21 @@ void
 gdb_mpz::export_bits (gdb::array_view<gdb_byte> buf, int endian, bool unsigned_p,
                      bool safe) const
 {
-  gdb_assert (buf.size () > 0);
-
   int sign = mpz_sgn (m_val);
   if (sign == 0)
     {
       /* Our value is zero, so no need to call mpz_export to do the work,
         especially since mpz_export's documentation explicitly says
         that the function is a noop in this case.  Just write zero to
-        BUF ourselves.  */
-      memset (buf.data (), 0, buf.size ());
+        BUF ourselves, if it is non-empty.  In some languages, a
+        zero-bit type can exist and this is also fine.  */
+      if (buf.size () > 0)
+       memset (buf.data (), 0, buf.size ());
       return;
     }
 
+  gdb_assert (buf.size () > 0);
+
   if (safe)
     {
       /* Determine the maximum range of values that our buffer can
index f294ab622eed1decf193d8585fa7fd2272b4f6dd..d05c11ecbe4ba3304e5f5b88e40e8d3d9063c0c1 100644 (file)
@@ -119,11 +119,17 @@ struct gdb_mpz
     return result;
   }
 
-  /* Convert VAL to an integer of the given type.
+  /* Convert this value to an integer of the given type.
 
      The return type can signed or unsigned, with no size restriction.  */
   template<typename T> T as_integer () const;
 
+  /* Convert this value to an integer of the given type.  If this
+     value is too large, it is truncated.
+
+     The return type can signed or unsigned, with no size restriction.  */
+  template<typename T> T as_integer_truncate () const;
+
   /* Set VAL by importing the number stored in the byte array (BUF),
      using the given BYTE_ORDER.  The size of the data to read is
      the byte array's size.
@@ -312,7 +318,7 @@ struct gdb_mpz
     return mpz_cmp (m_val, other.m_val) <= 0;
   }
 
-  bool operator< (int other) const
+  bool operator< (long other) const
   {
     return mpz_cmp_si (m_val, other) < 0;
   }
@@ -322,6 +328,28 @@ struct gdb_mpz
     return mpz_cmp_si (m_val, other) == 0;
   }
 
+  bool operator== (long other) const
+  {
+    return mpz_cmp_si (m_val, other) == 0;
+  }
+
+  bool operator== (unsigned long other) const
+  {
+    return mpz_cmp_ui (m_val, other) == 0;
+  }
+
+  template<typename T,
+          typename = gdb::Requires<
+            gdb::And<std::is_integral<T>,
+                     std::integral_constant<bool,
+                                            (sizeof (T) > sizeof (long))>>
+            >
+          >
+  bool operator== (T src)
+  {
+    return *this == gdb_mpz (src);
+  }
+
   bool operator== (const gdb_mpz &other) const
   {
     return mpz_cmp (m_val, other.m_val) == 0;
@@ -612,4 +640,20 @@ gdb_mpz::as_integer () const
   return result;
 }
 
+/* See declaration above.  */
+
+template<typename T>
+T
+gdb_mpz::as_integer_truncate () const
+{
+  T result;
+
+  this->export_bits ({(gdb_byte *) &result, sizeof (result)},
+                    0 /* endian (0 = native) */,
+                    !std::is_signed<T>::value /* unsigned_p */,
+                    false /* safe */);
+
+  return result;
+}
+
 #endif