[1/6] Additions to gdb_mpz

Message ID 20230328-expr-128-bit-v1-1-f9eeb0143318@adacore.com
State New
Headers
Series Add 128-bit integers to Ada and Rust parsers |

Commit Message

Tom Tromey March 28, 2023, 3:49 p.m. UTC
  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 | 10 ++++++----
 gdb/gmp-utils.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 52 insertions(+), 6 deletions(-)
  

Patch

diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index 0afa344781b..13fa61d61e3 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -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
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index f294ab622ee..d05c11ecbe4 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -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