public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/8] Arithmetic for 128-bit types
@ 2023-03-03 21:11 Tom Tromey
  2023-03-03 21:12 ` [PATCH 1/8] Add many operators to gdb_mpz Tom Tromey
                   ` (9 more replies)
  0 siblings, 10 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-03 21:11 UTC (permalink / raw)
  To: gdb-patches

This series adss basic arithmetic for 128-bit integer types to gdb.

This is done using GMP, which gdb already requires.  While this
involves extra allocation, my view is that this hardly matters in most
expression contexts.  However, if it does turn out to matter, we can
try to switch to GCC's wide-integer code.

While this series, or something like it, is necessary for supporting
128-bit types, it is not sufficient.  In particular, none of the
lexers or parsers are touched, and integers that are part of types
(e.g., range bounds) are not handled.

This series is based on my earlier series to clean up the GMP classes.

Regression tested on x86-64 Fedora 36.

Tom



^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/8] Add many operators to gdb_mpz
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
@ 2023-03-03 21:12 ` Tom Tromey
  2023-03-07 13:38   ` Alexandra Petlanova Hajkova
  2023-03-03 21:12 ` [PATCH 2/8] Avoid a copy in gdb_mpz::safe_export Tom Tromey
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Tom Tromey @ 2023-03-03 21:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds many operator overloads and other useful methods to gdb_mpz.
This is preparation for using this class for scalar arithmetic in gdb
expression evaluation.
---
 gdb/gmp-utils.h | 138 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 138 insertions(+)

diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 274c28c0ce8..d4e5015e345 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -90,6 +90,12 @@ struct gdb_mpz
     return *this;
   }
 
+  gdb_mpz &operator= (bool src)
+  {
+    mpz_set_ui (m_val, (unsigned long) src);
+    return *this;
+  }
+
   /* Initialize this value from a string and a base.  Returns true if
      the string was parsed successfully, false otherwise.  */
   bool set (const char *str, int base)
@@ -105,6 +111,14 @@ struct gdb_mpz
     return result;
   }
 
+  /* Return a new value that is this value raised to EXP.  */
+  gdb_mpz pow (unsigned long exp) const
+  {
+    gdb_mpz result;
+    mpz_pow_ui (result.m_val, m_val, exp);
+    return result;
+  }
+
   /* Convert VAL to an integer of the given type.
 
      The return type can signed or unsigned, with no size restriction.  */
@@ -137,35 +151,154 @@ struct gdb_mpz
     mpz_neg (m_val, m_val);
   }
 
+  /* Take the one's complement in place.  */
+  void complement ()
+  { mpz_com (m_val, m_val); }
+
+  /* Mask this value to N bits, in place.  */
+  void mask (unsigned n)
+  { mpz_tdiv_r_2exp (m_val, m_val, n); }
+
+  /* Return the sign of this value.  This returns -1 for a negative
+     value, 0 if the value is 0, and 1 for a positive value.  */
+  int sgn () const
+  { return mpz_sgn (m_val); }
+
+  explicit operator bool () const
+  { return sgn () != 0; }
+
   gdb_mpz &operator*= (long other)
   {
     mpz_mul_si (m_val, m_val, other);
     return *this;
   }
 
+  gdb_mpz operator* (const gdb_mpz &other) const
+  {
+    gdb_mpz result;
+    mpz_mul (result.m_val, m_val, other.m_val);
+    return result;
+  }
+
+  gdb_mpz operator/ (const gdb_mpz &other) const
+  {
+    gdb_mpz result;
+    mpz_tdiv_q (result.m_val, m_val, other.m_val);
+    return result;
+  }
+
+  gdb_mpz operator% (const gdb_mpz &other) const
+  {
+    gdb_mpz result;
+    mpz_tdiv_r (result.m_val, m_val, other.m_val);
+    return result;
+  }
+
   gdb_mpz &operator+= (unsigned long other)
   {
     mpz_add_ui (m_val, m_val, other);
     return *this;
   }
 
+  gdb_mpz &operator+= (const gdb_mpz &other)
+  {
+    mpz_add (m_val, m_val, other.m_val);
+    return *this;
+  }
+
+  gdb_mpz operator+ (const gdb_mpz &other) const
+  {
+    gdb_mpz result;
+    mpz_add (result.m_val, m_val, other.m_val);
+    return result;
+  }
+
   gdb_mpz &operator-= (unsigned long other)
   {
     mpz_sub_ui (m_val, m_val, other);
     return *this;
   }
 
+  gdb_mpz &operator-= (const gdb_mpz &other)
+  {
+    mpz_sub (m_val, m_val, other.m_val);
+    return *this;
+  }
+
+  gdb_mpz operator- (const gdb_mpz &other) const
+  {
+    gdb_mpz result;
+    mpz_sub (result.m_val, m_val, other.m_val);
+    return result;
+  }
+
   gdb_mpz &operator<<= (unsigned long nbits)
   {
     mpz_mul_2exp (m_val, m_val, nbits);
     return *this;
   }
 
+  gdb_mpz operator<< (unsigned long nbits) const
+  {
+    gdb_mpz result;
+    mpz_mul_2exp (result.m_val, m_val, nbits);
+    return result;
+  }
+
+  gdb_mpz operator>> (unsigned long nbits) const
+  {
+    gdb_mpz result;
+    mpz_tdiv_q_2exp (result.m_val, m_val, nbits);
+    return result;
+  }
+
+  gdb_mpz &operator>>= (unsigned long nbits)
+  {
+    mpz_tdiv_q_2exp (m_val, m_val, nbits);
+    return *this;
+  }
+
+  gdb_mpz operator& (const gdb_mpz &other) const
+  {
+    gdb_mpz result;
+    mpz_and (result.m_val, m_val, other.m_val);
+    return result;
+  }
+
+  gdb_mpz operator| (const gdb_mpz &other) const
+  {
+    gdb_mpz result;
+    mpz_ior (result.m_val, m_val, other.m_val);
+    return result;
+  }
+
+  gdb_mpz operator^ (const gdb_mpz &other) const
+  {
+    gdb_mpz result;
+    mpz_xor (result.m_val, m_val, other.m_val);
+    return result;
+  }
+
   bool operator> (const gdb_mpz &other) const
   {
     return mpz_cmp (m_val, other.m_val) > 0;
   }
 
+  bool operator>= (const gdb_mpz &other) const
+  {
+    return mpz_cmp (m_val, other.m_val) >= 0;
+  }
+
+  bool operator< (const gdb_mpz &other) const
+  {
+    return mpz_cmp (m_val, other.m_val) < 0;
+  }
+
+  bool operator<= (const gdb_mpz &other) const
+  {
+    return mpz_cmp (m_val, other.m_val) <= 0;
+  }
+
   bool operator< (int other) const
   {
     return mpz_cmp_si (m_val, other) < 0;
@@ -181,6 +314,11 @@ struct gdb_mpz
     return mpz_cmp (m_val, other.m_val) == 0;
   }
 
+  bool operator!= (const gdb_mpz &other) const
+  {
+    return mpz_cmp (m_val, other.m_val) != 0;
+  }
+
 private:
 
   /* Helper template for constructor and operator=.  */
-- 
2.39.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 2/8] Avoid a copy in gdb_mpz::safe_export
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
  2023-03-03 21:12 ` [PATCH 1/8] Add many operators to gdb_mpz Tom Tromey
@ 2023-03-03 21:12 ` Tom Tromey
  2023-03-03 21:12 ` [PATCH 3/8] Add truncation mode to gdb_mpz Tom Tromey
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-03 21:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

Currently, gdb_mpz::safe_export will always make a copy of *this.
However, this copy isn't always needed.  This patch makes this code
slightly more efficient, by avoiding the copy when possible.
---
 gdb/gmp-utils.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index d134bc32a1d..57f5f9766b9 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -81,7 +81,8 @@ gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
 {
   gdb_assert (buf.size () > 0);
 
-  if (mpz_sgn (m_val) == 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
@@ -121,17 +122,16 @@ gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
 	   lo.str ().c_str (),
 	   hi.str ().c_str ());
 
-  gdb_mpz exported_val (m_val);
-
-  if (mpz_cmp_ui (exported_val.m_val, 0) < 0)
+  const gdb_mpz *exported_val = this;
+  gdb_mpz un_signed;
+  if (sign < 0)
     {
       /* mpz_export does not handle signed values, so create a positive
 	 value whose bit representation as an unsigned of the same length
 	 would be the same as our negative value.  */
-      gdb_mpz neg_offset;
-
-      mpz_ui_pow_ui (neg_offset.m_val, 2, buf.size () * HOST_CHAR_BIT);
-      mpz_add (exported_val.m_val, exported_val.m_val, neg_offset.m_val);
+      gdb_mpz neg_offset = gdb_mpz::pow (2, buf.size () * HOST_CHAR_BIT);
+      un_signed = *exported_val + neg_offset;
+      exported_val = &un_signed;
     }
 
   /* Do the export into a buffer allocated by GMP itself; that way,
@@ -147,7 +147,7 @@ gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
   size_t word_countp;
   gdb::unique_xmalloc_ptr<void> exported
     (mpz_export (NULL, &word_countp, -1 /* order */, buf.size () /* size */,
-		 endian, 0 /* nails */, exported_val.m_val));
+		 endian, 0 /* nails */, exported_val->m_val));
 
   gdb_assert (word_countp == 1);
 
-- 
2.39.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 3/8] Add truncation mode to gdb_mpz
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
  2023-03-03 21:12 ` [PATCH 1/8] Add many operators to gdb_mpz Tom Tromey
  2023-03-03 21:12 ` [PATCH 2/8] Avoid a copy in gdb_mpz::safe_export Tom Tromey
@ 2023-03-03 21:12 ` Tom Tromey
  2023-03-03 21:12 ` [PATCH 4/8] Add value_as_mpz and value_from_mpz Tom Tromey
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-03 21:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This renames gdb_mpz::safe_export to export_bits, and adds a new flag
to export a truncated value.  This is needed by value arithmetic.
---
 gdb/gmp-utils.c | 93 ++++++++++++++++++++++++++++---------------------
 gdb/gmp-utils.h | 29 +++++++++++----
 2 files changed, 76 insertions(+), 46 deletions(-)

diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index 57f5f9766b9..0afa344781b 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -66,18 +66,8 @@ gdb_mpz::read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
 /* See gmp-utils.h.  */
 
 void
-gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
-		bool unsigned_p) const
-{
-  this->safe_export
-    (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */, unsigned_p);
-}
-
-/* See gmp-utils.h.  */
-
-void
-gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
-		      int endian, bool unsigned_p) const
+gdb_mpz::export_bits (gdb::array_view<gdb_byte> buf, int endian, bool unsigned_p,
+		      bool safe) const
 {
   gdb_assert (buf.size () > 0);
 
@@ -92,36 +82,39 @@ gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
       return;
     }
 
-  /* Determine the maximum range of values that our buffer can hold,
-     and verify that VAL is within that range.  */
-
-  gdb_mpz lo, hi;
-  const size_t max_usable_bits = buf.size () * HOST_CHAR_BIT;
-  if (unsigned_p)
-    {
-      lo = 0;
-
-      mpz_ui_pow_ui (hi.m_val, 2, max_usable_bits);
-      mpz_sub_ui (hi.m_val, hi.m_val, 1);
-    }
-  else
+  if (safe)
     {
-      mpz_ui_pow_ui (lo.m_val, 2, max_usable_bits - 1);
-      mpz_neg (lo.m_val, lo.m_val);
-
-      mpz_ui_pow_ui (hi.m_val, 2, max_usable_bits - 1);
-      mpz_sub_ui (hi.m_val, hi.m_val, 1);
+      /* Determine the maximum range of values that our buffer can
+	 hold, and verify that VAL is within that range.  */
+
+      gdb_mpz lo, hi;
+      const size_t max_usable_bits = buf.size () * HOST_CHAR_BIT;
+      if (unsigned_p)
+	{
+	  lo = 0;
+
+	  mpz_ui_pow_ui (hi.m_val, 2, max_usable_bits);
+	  mpz_sub_ui (hi.m_val, hi.m_val, 1);
+	}
+      else
+	{
+	  mpz_ui_pow_ui (lo.m_val, 2, max_usable_bits - 1);
+	  mpz_neg (lo.m_val, lo.m_val);
+
+	  mpz_ui_pow_ui (hi.m_val, 2, max_usable_bits - 1);
+	  mpz_sub_ui (hi.m_val, hi.m_val, 1);
+	}
+
+      if (mpz_cmp (m_val, lo.m_val) < 0 || mpz_cmp (m_val, hi.m_val) > 0)
+	error (_("Cannot export value %s as %zu-bits %s integer"
+		 " (must be between %s and %s)"),
+	       this->str ().c_str (),
+	       max_usable_bits,
+	       unsigned_p ? _("unsigned") : _("signed"),
+	       lo.str ().c_str (),
+	       hi.str ().c_str ());
     }
 
-  if (mpz_cmp (m_val, lo.m_val) < 0 || mpz_cmp (m_val, hi.m_val) > 0)
-    error (_("Cannot export value %s as %zu-bits %s integer"
-	     " (must be between %s and %s)"),
-	   this->str ().c_str (),
-	   max_usable_bits,
-	   unsigned_p ? _("unsigned") : _("signed"),
-	   lo.str ().c_str (),
-	   hi.str ().c_str ());
-
   const gdb_mpz *exported_val = this;
   gdb_mpz un_signed;
   if (sign < 0)
@@ -134,6 +127,28 @@ gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
       exported_val = &un_signed;
     }
 
+  /* If the value is too large, truncate it.  */
+  if (!safe
+      && mpz_sizeinbase (exported_val->m_val, 2) > buf.size () * HOST_CHAR_BIT)
+    {
+      /* If we don't already have a copy, make it now.  */
+      if (exported_val != &un_signed)
+	{
+	  un_signed = *exported_val;
+	  exported_val = &un_signed;
+	}
+
+      un_signed.mask (buf.size () * HOST_CHAR_BIT);
+    }
+
+  /* It's possible that one of the above results in zero, which has to
+     be handled specially.  */
+  if (exported_val->sgn () == 0)
+    {
+      memset (buf.data (), 0, buf.size ());
+      return;
+    }
+
   /* Do the export into a buffer allocated by GMP itself; that way,
      we can detect cases where BUF is not large enough to export
      our value, and thus avoid a buffer overlow.  Normally, this should
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index d4e5015e345..d378499d287 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -137,7 +137,20 @@ struct gdb_mpz
 
      UNSIGNED_P indicates whether the number has an unsigned type.  */
   void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
-	      bool unsigned_p) const;
+	      bool unsigned_p) const
+  {
+    export_bits (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
+		 unsigned_p, true /* safe */);
+  }
+
+  /* Like write, but truncates the value to the desired number of
+     bytes.  */
+  void truncate (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
+		 bool unsigned_p) const
+  {
+    export_bits (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
+		 unsigned_p, false /* safe */);
+  }
 
   /* Return a string containing VAL.  */
   std::string str () const { return gmp_string_printf ("%Zd", m_val); }
@@ -337,10 +350,11 @@ struct gdb_mpz
 	   . -1 for least significant byte first; or
 	   . 0 for native endianness.
 
-    An error is raised if BUF is not large enough to contain the value
-    being exported.  */
-  void safe_export (gdb::array_view<gdb_byte> buf,
-		    int endian, bool unsigned_p) const;
+    If SAFE is true, an error is raised if BUF is not large enough to
+    contain the value being exported.  If SAFE is false, the value is
+    truncated to fit in BUF.  */
+  void export_bits (gdb::array_view<gdb_byte> buf, int endian, bool unsigned_p,
+		    bool safe) const;
 
   friend struct gdb_mpq;
   friend struct gdb_mpf;
@@ -590,9 +604,10 @@ gdb_mpz::as_integer () const
 {
   T result;
 
-  this->safe_export ({(gdb_byte *) &result, sizeof (result)},
+  this->export_bits ({(gdb_byte *) &result, sizeof (result)},
 		     0 /* endian (0 = native) */,
-		     !std::is_signed<T>::value /* unsigned_p */);
+		     !std::is_signed<T>::value /* unsigned_p */,
+		     true /* safe */);
 
   return result;
 }
-- 
2.39.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 4/8] Add value_as_mpz and value_from_mpz
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
                   ` (2 preceding siblings ...)
  2023-03-03 21:12 ` [PATCH 3/8] Add truncation mode to gdb_mpz Tom Tromey
@ 2023-03-03 21:12 ` Tom Tromey
  2023-03-08 10:47   ` Lancelot SIX
  2023-03-03 21:12 ` [PATCH 5/8] Simplify binop_promote Tom Tromey
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Tom Tromey @ 2023-03-03 21:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds the two new functions, value_as_mpz and value_from_mpz,
useful for manipulation values via gdb_mpz.
---
 gdb/value.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/value.h |   7 ++++
 2 files changed, 113 insertions(+)

diff --git a/gdb/value.c b/gdb/value.c
index e9afa89c243..19da9e1a00b 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2551,6 +2551,76 @@ value_as_long (struct value *val)
   return unpack_long (val->type (), val->contents ().data ());
 }
 
+/* See value.h.  */
+
+gdb_mpz
+value_as_mpz (struct value *val)
+{
+  val = coerce_array (val);
+  struct type *type = check_typedef (val->type ());
+
+  switch (type->code ())
+    {
+    case TYPE_CODE_ENUM:
+    case TYPE_CODE_BOOL:
+    case TYPE_CODE_INT:
+    case TYPE_CODE_CHAR:
+    case TYPE_CODE_RANGE:
+      break;
+
+    default:
+      return gdb_mpz (value_as_long (val));
+    }
+
+  gdb_mpz result;
+
+  gdb::array_view<const gdb_byte> valbytes = val->contents ();
+  enum bfd_endian byte_order = type_byte_order (type);
+
+  /* Handle integers that are either not a multiple of the word size,
+     or that are stored at some bit offset.  */
+  unsigned bit_off = 0, bit_size = 0;
+  if (type->bit_size_differs_p ())
+    {
+      bit_size = type->bit_size ();
+      if (bit_size == 0)
+	{
+	  /* We can just handle this immediately.  */
+	  return result;
+	}
+
+      bit_off = type->bit_offset ();
+
+      unsigned n_bytes = ((bit_off % 8) + bit_size + 7) / 8;
+      valbytes = valbytes.slice (bit_off / 8, n_bytes);
+
+      if (byte_order == BFD_ENDIAN_BIG)
+	bit_off = (n_bytes * 8 - bit_off % 8 - bit_size);
+      else
+	bit_off %= 8;
+    }
+
+  result.read (val->contents (), byte_order, type->is_unsigned ());
+
+  /* Shift off any low bits, if needed.  */
+  if (bit_off != 0)
+    result >>= bit_off;
+
+  /* Mask off any high bits, if needed.  */
+  if (bit_size)
+    result.mask (bit_size);
+
+  /* Now handle any range bias.  */
+  if (type->code () == TYPE_CODE_RANGE && type->bounds ()->bias != 0)
+    {
+      /* Unfortunately we have to box here, because LONGEST is
+	 probably wider than long.  */
+      result += gdb_mpz (type->bounds ()->bias);
+    }
+
+  return result;
+}
+
 /* Extract a value as a C pointer.  Does not deallocate the value.
    Note that val's type may not actually be a pointer; value_as_long
    handles all the cases.  */
@@ -3378,6 +3448,42 @@ value_from_ulongest (struct type *type, ULONGEST num)
   return val;
 }
 
+/* See value.h.  */
+
+struct value *
+value_from_mpz (struct type *type, const gdb_mpz &v)
+{
+  struct type *real_type = check_typedef (type);
+
+  const gdb_mpz *val = &v;
+  gdb_mpz storage;
+  if (real_type->code () == TYPE_CODE_RANGE && type->bounds ()->bias != 0)
+    {
+      storage = *val;
+      val = &storage;
+      storage -= type->bounds ()->bias;
+    }
+
+  if (type->bit_size_differs_p ())
+    {
+      unsigned bit_off = type->bit_offset ();
+      unsigned bit_size = type->bit_size ();
+
+      if (val != &storage)
+	{
+	  storage = *val;
+	  val = &storage;
+	}
+
+      storage.mask ((ULONGEST) 1 << bit_size);
+      storage <<= bit_off;
+    }
+
+  struct value *result = value::allocate (type);
+  val->truncate (result->contents_raw (), type_byte_order (type),
+		 type->is_unsigned ());
+  return result;
+}
 
 /* Create a value representing a pointer of type TYPE to the address
    ADDR.  */
diff --git a/gdb/value.h b/gdb/value.h
index d83c4ab3674..1b4eff22f37 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1029,6 +1029,11 @@ extern bool is_floating_value (struct value *val);
 extern LONGEST value_as_long (struct value *val);
 extern CORE_ADDR value_as_address (struct value *val);
 
+/* Extract the value from VAL as a MPZ.  This coerces arrays and
+   handles various integer-like types as well.  */
+
+extern gdb_mpz value_as_mpz (struct value *val);
+
 extern LONGEST unpack_long (struct type *type, const gdb_byte *valaddr);
 extern CORE_ADDR unpack_pointer (struct type *type, const gdb_byte *valaddr);
 
@@ -1075,6 +1080,8 @@ extern struct value *value_from_history_ref (const char *, const char **);
 extern struct value *value_from_component (struct value *, struct type *,
 					   LONGEST);
 
+/* Convert the value V into a newly allocated value.  */
+extern struct value *value_from_mpz (struct type *type, const gdb_mpz &v);
 
 extern struct value *value_at (struct type *type, CORE_ADDR addr);
 extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr);
-- 
2.39.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 5/8] Simplify binop_promote
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
                   ` (3 preceding siblings ...)
  2023-03-03 21:12 ` [PATCH 4/8] Add value_as_mpz and value_from_mpz Tom Tromey
@ 2023-03-03 21:12 ` Tom Tromey
  2023-03-03 21:12 ` [PATCH 6/8] Use value_true in value_equal and value_less Tom Tromey
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-03 21:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

binop_promote currently only handles integer sizes up to
builtin_long_long.  However, this may not handle 128-bit types.
Simplify this code, unify the C and non-C (but not OpenCL, as I don't
know how to test this) cases, and handle 128-bit integers as well.

This still doesn't exactly follow C or C++ rules.  This could be
implemented, but if so, I think it makes more sense as a C-specific
expression node.
---
 gdb/eval.c | 55 +++++++++++++++++++-----------------------------------
 1 file changed, 19 insertions(+), 36 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index f8bbb9ef766..6b362f46424 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -371,29 +371,6 @@ binop_promote (const struct language_defn *language, struct gdbarch *gdbarch,
 
       switch (language->la_language)
 	{
-	case language_c:
-	case language_cplus:
-	case language_asm:
-	case language_objc:
-	  if (result_len <= builtin->builtin_int->length ())
-	    {
-	      promoted_type = (unsigned_operation
-			       ? builtin->builtin_unsigned_int
-			       : builtin->builtin_int);
-	    }
-	  else if (result_len <= builtin->builtin_long->length ())
-	    {
-	      promoted_type = (unsigned_operation
-			       ? builtin->builtin_unsigned_long
-			       : builtin->builtin_long);
-	    }
-	  else
-	    {
-	      promoted_type = (unsigned_operation
-			       ? builtin->builtin_unsigned_long_long
-			       : builtin->builtin_long_long);
-	    }
-	  break;
 	case language_opencl:
 	  if (result_len
 	      <= lookup_signed_typename (language, "int")->length())
@@ -413,23 +390,29 @@ binop_promote (const struct language_defn *language, struct gdbarch *gdbarch,
 	    }
 	  break;
 	default:
-	  /* For other languages the result type is unchanged from gdb
-	     version 6.7 for backward compatibility.
-	     If either arg was long long, make sure that value is also long
-	     long.  Otherwise use long.  */
-	  if (unsigned_operation)
+	  if (result_len <= builtin->builtin_int->length ())
 	    {
-	      if (result_len > gdbarch_long_bit (gdbarch) / HOST_CHAR_BIT)
-		promoted_type = builtin->builtin_unsigned_long_long;
-	      else
-		promoted_type = builtin->builtin_unsigned_long;
+	      promoted_type = (unsigned_operation
+			       ? builtin->builtin_unsigned_int
+			       : builtin->builtin_int);
+	    }
+	  else if (result_len <= builtin->builtin_long->length ())
+	    {
+	      promoted_type = (unsigned_operation
+			       ? builtin->builtin_unsigned_long
+			       : builtin->builtin_long);
+	    }
+	  else if (result_len <= builtin->builtin_long_long->length ())
+	    {
+	      promoted_type = (unsigned_operation
+			       ? builtin->builtin_unsigned_long_long
+			       : builtin->builtin_long_long);
 	    }
 	  else
 	    {
-	      if (result_len > gdbarch_long_bit (gdbarch) / HOST_CHAR_BIT)
-		promoted_type = builtin->builtin_long_long;
-	      else
-		promoted_type = builtin->builtin_long;
+	      promoted_type = (unsigned_operation
+			       ? builtin->builtin_uint128
+			       : builtin->builtin_int128);
 	    }
 	  break;
 	}
-- 
2.39.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 6/8] Use value_true in value_equal and value_less
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
                   ` (4 preceding siblings ...)
  2023-03-03 21:12 ` [PATCH 5/8] Simplify binop_promote Tom Tromey
@ 2023-03-03 21:12 ` Tom Tromey
  2023-03-03 21:12 ` [PATCH 7/8] Use gdb_gmp for scalar arithmetic Tom Tromey
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-03 21:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

Both value_equal and value_less use value_as_long to check a
presumably boolean result of calling value_binop.  However,
value_binop in this case actually returns an int as wide as its
arguments, and this approach can then fail for integers wider than
LONGEST.  Instead, rewrite this in a form that works for any size
integer.
---
 gdb/valarith.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/gdb/valarith.c b/gdb/valarith.c
index 9d681dc9d97..99597bef695 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -1761,8 +1761,7 @@ value_equal (struct value *arg1, struct value *arg2)
   is_int2 = is_integral_type (type2);
 
   if (is_int1 && is_int2)
-    return longest_to_int (value_as_long (value_binop (arg1, arg2,
-						       BINOP_EQUAL)));
+    return value_true (value_binop (arg1, arg2, BINOP_EQUAL));
   else if ((is_floating_value (arg1) || is_int1)
 	   && (is_floating_value (arg2) || is_int2))
     {
@@ -1849,8 +1848,7 @@ value_less (struct value *arg1, struct value *arg2)
 
   if ((is_int1 && is_int2)
       || (is_fixed_point_type (type1) && is_fixed_point_type (type2)))
-    return longest_to_int (value_as_long (value_binop (arg1, arg2,
-						       BINOP_LESS)));
+    return value_true (value_binop (arg1, arg2, BINOP_LESS));
   else if ((is_floating_value (arg1) || is_int1)
 	   && (is_floating_value (arg2) || is_int2))
     {
-- 
2.39.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 7/8] Use gdb_gmp for scalar arithmetic
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
                   ` (5 preceding siblings ...)
  2023-03-03 21:12 ` [PATCH 6/8] Use value_true in value_equal and value_less Tom Tromey
@ 2023-03-03 21:12 ` Tom Tromey
  2023-03-03 21:12 ` [PATCH 8/8] Fix 128-bit integer bug in Ada Tom Tromey
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-03 21:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes gdb to use scalar arithmetic for expression evaluation.

I suspect this patch is not truly complete, as there may be code paths
that still don't correctly handle 128-bit integers.  However, many
things do work now.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30190
---
 gdb/testsuite/gdb.rust/onetwoeight.exp |  65 ++++
 gdb/testsuite/gdb.rust/onetwoeight.rs  |  31 ++
 gdb/utils.c                            |  30 --
 gdb/utils.h                            |   7 -
 gdb/valarith.c                         | 489 ++++++++-----------------
 gdb/valops.c                           |  14 +-
 6 files changed, 253 insertions(+), 383 deletions(-)
 create mode 100644 gdb/testsuite/gdb.rust/onetwoeight.exp
 create mode 100644 gdb/testsuite/gdb.rust/onetwoeight.rs

diff --git a/gdb/testsuite/gdb.rust/onetwoeight.exp b/gdb/testsuite/gdb.rust/onetwoeight.exp
new file mode 100644
index 00000000000..317c848a899
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/onetwoeight.exp
@@ -0,0 +1,65 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test expression parsing and evaluation that requires Rust compiler.
+
+load_lib rust-support.exp
+require allow_rust_tests
+
+set v [split [rust_compiler_version] .]
+if {[lindex $v 0] == 1 && [lindex $v 1] < 43} {
+    untested "128-bit ints require rust 1.43 or greater"
+    return -1
+}
+
+standard_testfile .rs
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug rust}]} {
+    return -1
+}
+
+set line [gdb_get_line_number "BREAK"]
+if {![runto ${srcfile}:$line]} {
+    untested "could not run to breakpoint"
+    return -1
+}
+
+gdb_test "print x" " = 340282366920938463463374607431768211455"
+gdb_test "print y" " = 170141183460469231731687303715884105727"
+
+gdb_test "print x / 2" " = 170141183460469231731687303715884105727"
+gdb_test "print sm * 2" " = 170141183460469231731687303715884105726"
+gdb_test "print sm + sm" " = 170141183460469231731687303715884105726"
+gdb_test "print x - y" " = 170141183460469231731687303715884105728"
+gdb_test "print -y" " = -170141183460469231731687303715884105727"
+gdb_test "print +y" " = 170141183460469231731687303715884105727"
+
+gdb_test "print/x x" " = 0xffffffffffffffffffffffffffffffff"
+gdb_test "print x % 4" " = 3"
+gdb_test "print !x" " = 0"
+
+gdb_test "print x < 0" " = false"
+gdb_test "print -y < 0" " = true"
+gdb_test "print x > y" " = true"
+gdb_test "print y >= y" " = true"
+gdb_test "print y <= y" " = true"
+gdb_test "print y == y" " = true"
+gdb_test "print x != y" " = true"
+
+gdb_test "print sm << 2" "= 340282366920938463463374607431768211452"
+gdb_test "print x >> 2" "= 85070591730234615865843651857942052863"
+
+gdb_test "print/x x & mask" " = 0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0"
+gdb_test "print/x x ^ mask" " = 0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
+gdb_test "print/x mask | (mask >> 4)" " = 0xffffffffffffffffffffffffffffffff"
diff --git a/gdb/testsuite/gdb.rust/onetwoeight.rs b/gdb/testsuite/gdb.rust/onetwoeight.rs
new file mode 100644
index 00000000000..aa8cb1cf7b1
--- /dev/null
+++ b/gdb/testsuite/gdb.rust/onetwoeight.rs
@@ -0,0 +1,31 @@
+// Copyright (C) 2023 Free Software Foundation, Inc.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+
+fn empty() {
+}
+
+fn main () {
+    let x : u128 = 340_282_366_920_938_463_463_374_607_431_768_211_455;
+    let sm : u128 = x /4;
+    let y : i128 = 170_141_183_460_469_231_731_687_303_715_884_105_727;
+    let mask : u128 = 0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0;
+
+    empty();			// BREAK
+}
diff --git a/gdb/utils.c b/gdb/utils.c
index 0138c8e9fb6..9ca83246b24 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -723,36 +723,6 @@ myread (int desc, char *addr, int len)
   return orglen;
 }
 
-/* See utils.h.  */
-
-ULONGEST
-uinteger_pow (ULONGEST v1, LONGEST v2)
-{
-  if (v2 < 0)
-    {
-      if (v1 == 0)
-	error (_("Attempt to raise 0 to negative power."));
-      else
-	return 0;
-    }
-  else
-    {
-      /* The Russian Peasant's Algorithm.  */
-      ULONGEST v;
-
-      v = 1;
-      for (;;)
-	{
-	  if (v2 & 1L)
-	    v *= v1;
-	  v2 >>= 1;
-	  if (v2 == 0)
-	    return v;
-	  v1 *= v1;
-	}
-    }
-}
-
 \f
 
 /* An RAII class that sets up to handle input and then tears down
diff --git a/gdb/utils.h b/gdb/utils.h
index 6e240deccbf..a383036bcfe 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -303,13 +303,6 @@ extern pid_t wait_to_die_with_timeout (pid_t pid, int *status, int timeout);
 
 extern int myread (int, char *, int);
 
-/* Integer exponentiation: Return V1**V2, where both arguments
-   are integers.
-
-   Requires V1 != 0 if V2 < 0.
-   Returns 1 for 0 ** 0.  */
-extern ULONGEST uinteger_pow (ULONGEST v1, LONGEST v2);
-
 /* Resource limits used by getrlimit and setrlimit.  */
 
 enum resource_limit_kind
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 99597bef695..a8ae17e1730 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -34,13 +34,6 @@ static struct value *value_subscripted_rvalue (struct value *array,
 					       LONGEST index,
 					       LONGEST lowerbound);
 
-/* Define whether or not the C operator '/' truncates towards zero for
-   differently signed operands (truncation direction is undefined in C).  */
-
-#ifndef TRUNCATION_TOWARDS_ZERO
-#define TRUNCATION_TOWARDS_ZERO ((-5 / 2) == -2)
-#endif
-
 /* Given a pointer, return the size of its target.
    If the pointer type is void *, then return 1.
    If the target type is incomplete, then error out.
@@ -726,36 +719,6 @@ value_concat (struct value *arg1, struct value *arg2)
   return result;
 }
 \f
-/* Integer exponentiation: V1**V2, where both arguments are
-   integers.  Requires V1 != 0 if V2 < 0.  Returns 1 for 0 ** 0.  */
-
-static LONGEST
-integer_pow (LONGEST v1, LONGEST v2)
-{
-  if (v2 < 0)
-    {
-      if (v1 == 0)
-	error (_("Attempt to raise 0 to negative power."));
-      else
-	return 0;
-    }
-  else 
-    {
-      /* The Russian Peasant's Algorithm.  */
-      LONGEST v;
-      
-      v = 1;
-      for (;;)
-	{
-	  if (v2 & 1L) 
-	    v *= v1;
-	  v2 >>= 1;
-	  if (v2 == 0)
-	    return v;
-	  v1 *= v1;
-	}
-    }
-}
 
 /* Obtain argument values for binary operation, converting from
    other types if one of them is not floating point.  */
@@ -1099,33 +1062,39 @@ type_length_bits (type *type)
    both negative and too-large shift amounts, which are undefined, and
    would crash a GDB built with UBSan.  Depending on the current
    language, if the shift is not valid, this either warns and returns
-   false, or errors out.  Returns true if valid.  */
+   false, or errors out.  Returns true and sets NBITS if valid.  */
 
 static bool
 check_valid_shift_count (enum exp_opcode op, type *result_type,
-			 type *shift_count_type, ULONGEST shift_count)
+			 type *shift_count_type, const gdb_mpz &shift_count,
+			 unsigned long &nbits)
 {
-  if (!shift_count_type->is_unsigned () && (LONGEST) shift_count < 0)
+  if (!shift_count_type->is_unsigned ())
     {
-      auto error_or_warning = [] (const char *msg)
-      {
-	/* Shifts by a negative amount are always an error in Go.  Other
-	   languages are more permissive and their compilers just warn or
-	   have modes to disable the errors.  */
-	if (current_language->la_language == language_go)
-	  error (("%s"), msg);
-	else
-	  warning (("%s"), msg);
-      };
+      LONGEST count = shift_count.as_integer<LONGEST> ();
+      if (count < 0)
+	{
+	  auto error_or_warning = [] (const char *msg)
+	  {
+	    /* Shifts by a negative amount are always an error in Go.  Other
+	       languages are more permissive and their compilers just warn or
+	       have modes to disable the errors.  */
+	    if (current_language->la_language == language_go)
+	      error (("%s"), msg);
+	    else
+	      warning (("%s"), msg);
+	  };
 
-      if (op == BINOP_RSH)
-	error_or_warning (_("right shift count is negative"));
-      else
-	error_or_warning (_("left shift count is negative"));
-      return false;
+	  if (op == BINOP_RSH)
+	    error_or_warning (_("right shift count is negative"));
+	  else
+	    error_or_warning (_("left shift count is negative"));
+	  return false;
+	}
     }
 
-  if (shift_count >= type_length_bits (result_type))
+  nbits = shift_count.as_integer<unsigned long> ();
+  if (nbits >= type_length_bits (result_type))
     {
       /* In Go, shifting by large amounts is defined.  Be silent and
 	 still return false, as the caller's error path does the right
@@ -1249,299 +1218,135 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
       else
 	result_type = promotion_type (type1, type2);
 
-      if (result_type->is_unsigned ())
+      gdb_mpz v1 = value_as_mpz (arg1);
+      gdb_mpz v2 = value_as_mpz (arg2);
+      gdb_mpz v;
+
+      switch (op)
 	{
-	  LONGEST v2_signed = value_as_long (arg2);
-	  ULONGEST v1, v2, v = 0;
+	case BINOP_ADD:
+	  v = v1 + v2;
+	  break;
 
-	  v1 = (ULONGEST) value_as_long (arg1);
-	  v2 = (ULONGEST) v2_signed;
+	case BINOP_SUB:
+	  v = v1 - v2;
+	  break;
 
-	  switch (op)
-	    {
-	    case BINOP_ADD:
-	      v = v1 + v2;
-	      break;
-
-	    case BINOP_SUB:
-	      v = v1 - v2;
-	      break;
-
-	    case BINOP_MUL:
-	      v = v1 * v2;
-	      break;
-
-	    case BINOP_DIV:
-	    case BINOP_INTDIV:
-	      if (v2 != 0)
-		v = v1 / v2;
-	      else
-		error (_("Division by zero"));
-	      break;
-
-	    case BINOP_EXP:
-	      v = uinteger_pow (v1, v2_signed);
-	      break;
-
-	    case BINOP_REM:
-	      if (v2 != 0)
-		v = v1 % v2;
-	      else
-		error (_("Division by zero"));
-	      break;
-
-	    case BINOP_MOD:
-	      /* Knuth 1.2.4, integer only.  Note that unlike the C '%' op,
-		 v1 mod 0 has a defined value, v1.  */
-	      if (v2 == 0)
-		{
-		  v = v1;
-		}
-	      else
-		{
-		  v = v1 / v2;
-		  /* Note floor(v1/v2) == v1/v2 for unsigned.  */
-		  v = v1 - (v2 * v);
-		}
-	      break;
-
-	    case BINOP_LSH:
-	      if (!check_valid_shift_count (op, result_type, type2, v2))
-		v = 0;
-	      else
-		v = v1 << v2;
-	      break;
-
-	    case BINOP_RSH:
-	      if (!check_valid_shift_count (op, result_type, type2, v2))
-		v = 0;
-	      else
-		v = v1 >> v2;
-	      break;
-
-	    case BINOP_BITWISE_AND:
-	      v = v1 & v2;
-	      break;
-
-	    case BINOP_BITWISE_IOR:
-	      v = v1 | v2;
-	      break;
-
-	    case BINOP_BITWISE_XOR:
-	      v = v1 ^ v2;
-	      break;
-
-	    case BINOP_LOGICAL_AND:
-	      v = v1 && v2;
-	      break;
-
-	    case BINOP_LOGICAL_OR:
-	      v = v1 || v2;
-	      break;
-
-	    case BINOP_MIN:
-	      v = v1 < v2 ? v1 : v2;
-	      break;
-
-	    case BINOP_MAX:
-	      v = v1 > v2 ? v1 : v2;
-	      break;
-
-	    case BINOP_EQUAL:
-	      v = v1 == v2;
-	      break;
-
-	    case BINOP_NOTEQUAL:
-	      v = v1 != v2;
-	      break;
-
-	    case BINOP_LESS:
-	      v = v1 < v2;
-	      break;
-
-	    case BINOP_GTR:
-	      v = v1 > v2;
-	      break;
-
-	    case BINOP_LEQ:
-	      v = v1 <= v2;
-	      break;
-
-	    case BINOP_GEQ:
-	      v = v1 >= v2;
-	      break;
-
-	    default:
-	      error (_("Invalid binary operation on numbers."));
-	    }
+	case BINOP_MUL:
+	  v = v1 * v2;
+	  break;
 
-	  val = value::allocate (result_type);
-	  store_unsigned_integer (val->contents_raw ().data (),
-				  val->type ()->length (),
-				  type_byte_order (result_type),
-				  v);
-	}
-      else
-	{
-	  LONGEST v1, v2, v = 0;
+	case BINOP_DIV:
+	case BINOP_INTDIV:
+	  if (v2.sgn () != 0)
+	    v = v1 / v2;
+	  else
+	    error (_("Division by zero"));
+	  break;
 
-	  v1 = value_as_long (arg1);
-	  v2 = value_as_long (arg2);
+	case BINOP_EXP:
+	  v = v1.pow (v2.as_integer<unsigned long> ());
+	  break;
+
+	case BINOP_REM:
+	  if (v2.sgn () != 0)
+	    v = v1 % v2;
+	  else
+	    error (_("Division by zero"));
+	  break;
 
-	  switch (op)
+	case BINOP_MOD:
+	  /* Knuth 1.2.4, integer only.  Note that unlike the C '%' op,
+	     v1 mod 0 has a defined value, v1.  */
+	  if (v2.sgn () == 0)
+	    {
+	      v = v1;
+	    }
+	  else
 	    {
-	    case BINOP_ADD:
-	      v = v1 + v2;
-	      break;
-
-	    case BINOP_SUB:
-	      /* Avoid runtime error: signed integer overflow: \
-		 0 - -9223372036854775808 cannot be represented in type
-		 'long int'.  */
-	      v = (ULONGEST)v1 - (ULONGEST)v2;
-	      break;
-
-	    case BINOP_MUL:
-	      v = v1 * v2;
-	      break;
-
-	    case BINOP_DIV:
-	    case BINOP_INTDIV:
-	      if (v2 != 0)
-		v = v1 / v2;
-	      else
-		error (_("Division by zero"));
-	      break;
-
-	    case BINOP_EXP:
-	      v = integer_pow (v1, v2);
-	      break;
-
-	    case BINOP_REM:
-	      if (v2 != 0)
-		v = v1 % v2;
-	      else
-		error (_("Division by zero"));
-	      break;
-
-	    case BINOP_MOD:
-	      /* Knuth 1.2.4, integer only.  Note that unlike the C '%' op,
-		 X mod 0 has a defined value, X.  */
-	      if (v2 == 0)
-		{
-		  v = v1;
-		}
-	      else
-		{
-		  v = v1 / v2;
-		  /* Compute floor.  */
-		  if (TRUNCATION_TOWARDS_ZERO && (v < 0) && ((v1 % v2) != 0))
-		    {
-		      v--;
-		    }
-		  v = v1 - (v2 * v);
-		}
-	      break;
-
-	    case BINOP_LSH:
-	      if (!check_valid_shift_count (op, result_type, type2, v2))
-		v = 0;
-	      else
-		{
-		  /* Cast to unsigned to avoid undefined behavior on
-		     signed shift overflow (unless C++20 or later),
-		     which would crash GDB when built with UBSan.
-		     Note we don't warn on left signed shift overflow,
-		     because starting with C++20, that is actually
-		     defined behavior.  Also, note GDB assumes 2's
-		     complement throughout.  */
-		  v = (ULONGEST) v1 << v2;
-		}
-	      break;
-
-	    case BINOP_RSH:
-	      if (!check_valid_shift_count (op, result_type, type2, v2))
-		{
-		  /* Pretend the too-large shift was decomposed in a
-		     number of smaller shifts.  An arithmetic signed
-		     right shift of a negative number always yields -1
-		     with such semantics.  This is the right thing to
-		     do for Go, and we might as well do it for
-		     languages where it is undefined.  Also, pretend a
-		     shift by a negative number was a shift by the
-		     negative number cast to unsigned, which is the
-		     same as shifting by a too-large number.  */
-		  if (v1 < 0)
-		    v = -1;
-		  else
-		    v = 0;
-		}
-	      else
-		v = v1 >> v2;
-	      break;
-
-	    case BINOP_BITWISE_AND:
-	      v = v1 & v2;
-	      break;
-
-	    case BINOP_BITWISE_IOR:
-	      v = v1 | v2;
-	      break;
-
-	    case BINOP_BITWISE_XOR:
-	      v = v1 ^ v2;
-	      break;
-
-	    case BINOP_LOGICAL_AND:
-	      v = v1 && v2;
-	      break;
-
-	    case BINOP_LOGICAL_OR:
-	      v = v1 || v2;
-	      break;
-
-	    case BINOP_MIN:
-	      v = v1 < v2 ? v1 : v2;
-	      break;
-
-	    case BINOP_MAX:
-	      v = v1 > v2 ? v1 : v2;
-	      break;
-
-	    case BINOP_EQUAL:
-	      v = v1 == v2;
-	      break;
-
-	    case BINOP_NOTEQUAL:
-	      v = v1 != v2;
-	      break;
-
-	    case BINOP_LESS:
-	      v = v1 < v2;
-	      break;
-
-	    case BINOP_GTR:
-	      v = v1 > v2;
-	      break;
-
-	    case BINOP_LEQ:
-	      v = v1 <= v2;
-	      break;
-
-	    case BINOP_GEQ:
-	      v = v1 >= v2;
-	      break;
-
-	    default:
-	      error (_("Invalid binary operation on numbers."));
+	      v = v1 / v2;
+	      /* Note floor(v1/v2) == v1/v2 for unsigned.  */
+	      v = v1 - (v2 * v);
 	    }
+	  break;
 
-	  val = value::allocate (result_type);
-	  store_signed_integer (val->contents_raw ().data (),
-				val->type ()->length (),
-				type_byte_order (result_type),
-				v);
+	case BINOP_LSH:
+	  {
+	    unsigned long nbits;
+	    if (!check_valid_shift_count (op, result_type, type2, v2, nbits))
+	      v = 0;
+	    else
+	      v = v1 << nbits;
+	  }
+	  break;
+
+	case BINOP_RSH:
+	  {
+	    unsigned long nbits;
+	    if (!check_valid_shift_count (op, result_type, type2, v2, nbits))
+	      v = 0;
+	    else
+	      v = v1 >> nbits;
+	  }
+	  break;
+
+	case BINOP_BITWISE_AND:
+	  v = v1 & v2;
+	  break;
+
+	case BINOP_BITWISE_IOR:
+	  v = v1 | v2;
+	  break;
+
+	case BINOP_BITWISE_XOR:
+	  v = v1 ^ v2;
+	  break;
+
+	case BINOP_LOGICAL_AND:
+	  v = v1 && v2;
+	  break;
+
+	case BINOP_LOGICAL_OR:
+	  v = v1 || v2;
+	  break;
+
+	case BINOP_MIN:
+	  v = v1 < v2 ? v1 : v2;
+	  break;
+
+	case BINOP_MAX:
+	  v = v1 > v2 ? v1 : v2;
+	  break;
+
+	case BINOP_EQUAL:
+	  v = v1 == v2;
+	  break;
+
+	case BINOP_NOTEQUAL:
+	  v = v1 != v2;
+	  break;
+
+	case BINOP_LESS:
+	  v = v1 < v2;
+	  break;
+
+	case BINOP_GTR:
+	  v = v1 > v2;
+	  break;
+
+	case BINOP_LEQ:
+	  v = v1 <= v2;
+	  break;
+
+	case BINOP_GEQ:
+	  v = v1 >= v2;
+	  break;
+
+	default:
+	  error (_("Invalid binary operation on numbers."));
 	}
+
+      val = value_from_mpz (result_type, v);
     }
 
   return val;
@@ -1960,7 +1765,11 @@ value_complement (struct value *arg1)
   type = check_typedef (arg1->type ());
 
   if (is_integral_type (type))
-    val = value_from_longest (type, ~value_as_long (arg1));
+    {
+      gdb_mpz num = value_as_mpz (arg1);
+      num.complement ();
+      val = value_from_mpz (type, num);
+    }
   else if (type->code () == TYPE_CODE_ARRAY && type->is_vector ())
     {
       struct type *eltype = check_typedef (type->target_type ());
diff --git a/gdb/valops.c b/gdb/valops.c
index 2cef24fc4c5..f06969e92e6 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -569,7 +569,7 @@ value_cast (struct type *type, struct value *arg2)
 	   && (scalar || code2 == TYPE_CODE_PTR
 	       || code2 == TYPE_CODE_MEMBERPTR))
     {
-      LONGEST longest;
+      gdb_mpz longest;
 
       /* When we cast pointers to integers, we mustn't use
 	 gdbarch_pointer_to_address to find the address the pointer
@@ -578,12 +578,14 @@ value_cast (struct type *type, struct value *arg2)
 	 sees a cast as a simple reinterpretation of the pointer's
 	 bits.  */
       if (code2 == TYPE_CODE_PTR)
-	longest = extract_unsigned_integer
-	  (arg2->contents (), type_byte_order (type2));
+	longest = extract_unsigned_integer (arg2->contents (),
+					    type_byte_order (type2));
       else
-	longest = value_as_long (arg2);
-      return value_from_longest (to_type, convert_to_boolean ?
-				 (LONGEST) (longest ? 1 : 0) : longest);
+	longest = value_as_mpz (arg2);
+      if (convert_to_boolean)
+	longest = bool (longest);
+
+      return value_from_mpz (to_type, longest);
     }
   else if (code1 == TYPE_CODE_PTR && (code2 == TYPE_CODE_INT  
 				      || code2 == TYPE_CODE_ENUM 
-- 
2.39.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 8/8] Fix 128-bit integer bug in Ada
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
                   ` (6 preceding siblings ...)
  2023-03-03 21:12 ` [PATCH 7/8] Use gdb_gmp for scalar arithmetic Tom Tromey
@ 2023-03-03 21:12 ` Tom Tromey
  2023-03-04  7:04 ` [PATCH 0/8] Arithmetic for 128-bit types Eli Zaretskii
  2023-03-27 14:20 ` Tom Tromey
  9 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-03 21:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

While working on 128-bit integer support, I found one spot in Ada that
needed a fix as well.
---
 gdb/ada-lang.c                          | 27 ++++--------------
 gdb/testsuite/gdb.ada/verylong.exp      | 37 +++++++++++++++++++++++++
 gdb/testsuite/gdb.ada/verylong/prog.adb | 20 +++++++++++++
 3 files changed, 63 insertions(+), 21 deletions(-)
 create mode 100644 gdb/testsuite/gdb.ada/verylong.exp
 create mode 100644 gdb/testsuite/gdb.ada/verylong/prog.adb

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 7b07c4f9473..d1afb1a27b1 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -62,14 +62,6 @@
 #include "charset.h"
 #include "ax-gdb.h"
 
-/* Define whether or not the C operator '/' truncates towards zero for
-   differently signed operands (truncation direction is undefined in C).
-   Copied from valarith.c.  */
-
-#ifndef TRUNCATION_TOWARDS_ZERO
-#define TRUNCATION_TOWARDS_ZERO ((-5 / 2) == -2)
-#endif
-
 static struct type *desc_base_type (struct type *);
 
 static struct type *desc_bounds_type (struct type *);
@@ -9351,9 +9343,7 @@ coerce_for_assign (struct type *type, struct value *val)
 static struct value *
 ada_value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 {
-  struct value *val;
   struct type *type1, *type2;
-  LONGEST v, v1, v2;
 
   arg1 = coerce_ref (arg1);
   arg2 = coerce_ref (arg2);
@@ -9374,8 +9364,8 @@ ada_value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
       return value_binop (arg1, arg2, op);
     }
 
-  v2 = value_as_long (arg2);
-  if (v2 == 0)
+  gdb_mpz v2 = value_as_mpz (arg2);
+  if (v2.sgn () == 0)
     {
       const char *name;
       if (op == BINOP_MOD)
@@ -9394,13 +9384,12 @@ ada_value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   if (type1->is_unsigned () || op == BINOP_MOD)
     return value_binop (arg1, arg2, op);
 
-  v1 = value_as_long (arg1);
+  gdb_mpz v1 = value_as_mpz (arg1);
+  gdb_mpz v;
   switch (op)
     {
     case BINOP_DIV:
       v = v1 / v2;
-      if (!TRUNCATION_TOWARDS_ZERO && v1 * (v1 % v2) < 0)
-	v += v > 0 ? -1 : 1;
       break;
     case BINOP_REM:
       v = v1 % v2;
@@ -9409,14 +9398,10 @@ ada_value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
       break;
     default:
       /* Should not reach this point.  */
-      v = 0;
+      gdb_assert_not_reached ("invalid operator");
     }
 
-  val = value::allocate (type1);
-  store_unsigned_integer (val->contents_raw ().data (),
-			  val->type ()->length (),
-			  type_byte_order (type1), v);
-  return val;
+  return value_from_mpz (type1, v);
 }
 
 static int
diff --git a/gdb/testsuite/gdb.ada/verylong.exp b/gdb/testsuite/gdb.ada/verylong.exp
new file mode 100644
index 00000000000..93df785862b
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/verylong.exp
@@ -0,0 +1,37 @@
+# Copyright 2023 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib "ada.exp"
+
+require allow_ada_tests
+
+standard_ada_testfile prog
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable {debug}] != ""} {
+    return -1
+}
+
+clean_restart ${testfile}
+
+set bp_location [gdb_get_line_number "START" ${testdir}/prog.adb]
+runto "prog.adb:$bp_location"
+
+gdb_test "print x" " = 170141183460469231731687303715884105727"
+gdb_test "print x / 2" " = 85070591730234615865843651857942052863"
+gdb_test "print (x / 4) * 2" " = 85070591730234615865843651857942052862"
+gdb_test "print x - x" " = 0"
+gdb_test "print x - 99 + 1" " = 170141183460469231731687303715884105629"
+gdb_test "print -x" " = -170141183460469231731687303715884105727"
+gdb_test "print +x" " = 170141183460469231731687303715884105727"
diff --git a/gdb/testsuite/gdb.ada/verylong/prog.adb b/gdb/testsuite/gdb.ada/verylong/prog.adb
new file mode 100644
index 00000000000..766419d0a4f
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/verylong/prog.adb
@@ -0,0 +1,20 @@
+--  Copyright 2023 Free Software Foundation, Inc.
+--
+--  This program is free software; you can redistribute it and/or modify
+--  it under the terms of the GNU General Public License as published by
+--  the Free Software Foundation; either version 3 of the License, or
+--  (at your option) any later version.
+--
+--  This program is distributed in the hope that it will be useful,
+--  but WITHOUT ANY WARRANTY; without even the implied warranty of
+--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--  GNU General Public License for more details.
+--
+--  You should have received a copy of the GNU General Public License
+--  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+procedure Main is
+   X : Long_Long_Long_Integer := Long_Long_Long_Integer'Last;
+begin
+   null; -- START
+end Main;
-- 
2.39.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/8] Arithmetic for 128-bit types
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
                   ` (7 preceding siblings ...)
  2023-03-03 21:12 ` [PATCH 8/8] Fix 128-bit integer bug in Ada Tom Tromey
@ 2023-03-04  7:04 ` Eli Zaretskii
  2023-03-08 16:17   ` Tom Tromey
  2023-03-27 14:20 ` Tom Tromey
  9 siblings, 1 reply; 15+ messages in thread
From: Eli Zaretskii @ 2023-03-04  7:04 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> Date: Fri,  3 Mar 2023 14:11:59 -0700
> X-Spam-Status: No, score=-5.6 required=5.0 tests=BAYES_00, DKIM_SIGNED,
>  DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,
>  SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6
> From: Tom Tromey via Gdb-patches <gdb-patches@sourceware.org>
> 
> This series adss basic arithmetic for 128-bit integer types to gdb.

Can you tell where and in what situations will this be useful?

Also, don't we need to announce this, at least in NEWS?

Thanks.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/8] Add many operators to gdb_mpz
  2023-03-03 21:12 ` [PATCH 1/8] Add many operators to gdb_mpz Tom Tromey
@ 2023-03-07 13:38   ` Alexandra Petlanova Hajkova
  0 siblings, 0 replies; 15+ messages in thread
From: Alexandra Petlanova Hajkova @ 2023-03-07 13:38 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 318 bytes --]

On Fri, Mar 3, 2023 at 10:12 PM Tom Tromey via Gdb-patches <
gdb-patches@sourceware.org> wrote:

> This adds many operator overloads and other useful methods to gdb_mpz.
> This is preparation for using this class for scalar arithmetic in gdb
> expression evaluation.
> ---
>
> Looks great, applies cleanly.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/8] Add value_as_mpz and value_from_mpz
  2023-03-03 21:12 ` [PATCH 4/8] Add value_as_mpz and value_from_mpz Tom Tromey
@ 2023-03-08 10:47   ` Lancelot SIX
  2023-03-08 15:48     ` Tom Tromey
  0 siblings, 1 reply; 15+ messages in thread
From: Lancelot SIX @ 2023-03-08 10:47 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi,

On Fri, Mar 03, 2023 at 02:12:03PM -0700, Tom Tromey via Gdb-patches wrote:
> This adds the two new functions, value_as_mpz and value_from_mpz,
> useful for manipulation values via gdb_mpz.
> ---
>  gdb/value.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/value.h |   7 ++++
>  2 files changed, 113 insertions(+)
> 
> diff --git a/gdb/value.c b/gdb/value.c
> index e9afa89c243..19da9e1a00b 100644
> --- a/gdb/value.c
> +++ b/gdb/value.c
> @@ -2551,6 +2551,76 @@ value_as_long (struct value *val)
>    return unpack_long (val->type (), val->contents ().data ());
>  }
>  
> +/* See value.h.  */
> +
> +gdb_mpz
> +value_as_mpz (struct value *val)
> +{
> +  val = coerce_array (val);
> +  struct type *type = check_typedef (val->type ());
> +
> +  switch (type->code ())
> +    {
> +    case TYPE_CODE_ENUM:
> +    case TYPE_CODE_BOOL:
> +    case TYPE_CODE_INT:
> +    case TYPE_CODE_CHAR:
> +    case TYPE_CODE_RANGE:
> +      break;
> +
> +    default:
> +      return gdb_mpz (value_as_long (val));
> +    }
> +
> +  gdb_mpz result;
> +
> +  gdb::array_view<const gdb_byte> valbytes = val->contents ();
> +  enum bfd_endian byte_order = type_byte_order (type);
> +
> +  /* Handle integers that are either not a multiple of the word size,
> +     or that are stored at some bit offset.  */
> +  unsigned bit_off = 0, bit_size = 0;
> +  if (type->bit_size_differs_p ())
> +    {
> +      bit_size = type->bit_size ();
> +      if (bit_size == 0)
> +	{
> +	  /* We can just handle this immediately.  */
> +	  return result;
> +	}
> +
> +      bit_off = type->bit_offset ();
> +
> +      unsigned n_bytes = ((bit_off % 8) + bit_size + 7) / 8;

This is a bit out of the scope of this patch as gdbvalue.h says that
bit_off / bit_size are 8 based, but should they be HOST_CHAR_BIT based
instead?  The n_bytes is used to to access a
"gdb::array_view<const gdb_byte>".

> +      valbytes = valbytes.slice (bit_off / 8, n_bytes);
> +
> +      if (byte_order == BFD_ENDIAN_BIG)
> +	bit_off = (n_bytes * 8 - bit_off % 8 - bit_size);
> +      else
> +	bit_off %= 8;
> +    }
> +
> +  result.read (val->contents (), byte_order, type->is_unsigned ());
> +
> +  /* Shift off any low bits, if needed.  */
> +  if (bit_off != 0)
> +    result >>= bit_off;
> +
> +  /* Mask off any high bits, if needed.  */
> +  if (bit_size)
> +    result.mask (bit_size);
> +
> +  /* Now handle any range bias.  */
> +  if (type->code () == TYPE_CODE_RANGE && type->bounds ()->bias != 0)
> +    {
> +      /* Unfortunately we have to box here, because LONGEST is
> +	 probably wider than long.  */
> +      result += gdb_mpz (type->bounds ()->bias);
> +    }
> +
> +  return result;
> +}
> +
>  /* Extract a value as a C pointer.  Does not deallocate the value.
>     Note that val's type may not actually be a pointer; value_as_long
>     handles all the cases.  */
> @@ -3378,6 +3448,42 @@ value_from_ulongest (struct type *type, ULONGEST num)
>    return val;
>  }
>  
> +/* See value.h.  */
> +
> +struct value *
> +value_from_mpz (struct type *type, const gdb_mpz &v)
> +{
> +  struct type *real_type = check_typedef (type);
> +
> +  const gdb_mpz *val = &v;
> +  gdb_mpz storage;
> +  if (real_type->code () == TYPE_CODE_RANGE && type->bounds ()->bias != 0)
> +    {
> +      storage = *val;
> +      val = &storage;
> +      storage -= type->bounds ()->bias;
> +    }
> +
> +  if (type->bit_size_differs_p ())
> +    {
> +      unsigned bit_off = type->bit_offset ();
> +      unsigned bit_size = type->bit_size ();
> +
> +      if (val != &storage)
> +	{
> +	  storage = *val;
> +	  val = &storage;
> +	}
> +
> +      storage.mask ((ULONGEST) 1 << bit_size);

I do not think you should have the "(ULONGEST) 1 <<" part here.
gdb_mpz::mask does mask N bits (N being its arg).

> +      storage <<= bit_off;
> +    }

Best,
Lancelot.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/8] Add value_as_mpz and value_from_mpz
  2023-03-08 10:47   ` Lancelot SIX
@ 2023-03-08 15:48     ` Tom Tromey
  0 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-08 15:48 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: Tom Tromey, gdb-patches

>> +      unsigned n_bytes = ((bit_off % 8) + bit_size + 7) / 8;

Lancelot> This is a bit out of the scope of this patch as gdbvalue.h says that
Lancelot> bit_off / bit_size are 8 based, but should they be HOST_CHAR_BIT based
Lancelot> instead?  The n_bytes is used to to access a
Lancelot> "gdb::array_view<const gdb_byte>".

Yeah, I do not know.  I am not sure I've ever understood how gdb intends
to handle these scenarios, if it even really does.  I do see uses of
HOST_CHAR_BIT, but also plain '8'.

Also there's this weirdness:

    #if defined (CHAR_BIT)
    #define HOST_CHAR_BIT CHAR_BIT
    #else
    #define HOST_CHAR_BIT TARGET_CHAR_BIT
    #endif

It's hard to understand how this can ever make sense, even despite the
comment (which may be obsolete).

TARGET_CHAR_BIT is even worse because surely it cannot be a constant.

Anyway, this code in question in this patch is just copied from
elsewhere.

>> +      storage.mask ((ULONGEST) 1 << bit_size);

Lancelot> I do not think you should have the "(ULONGEST) 1 <<" part here.
Lancelot> gdb_mpz::mask does mask N bits (N being its arg).

Thank you.

Tom

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/8] Arithmetic for 128-bit types
  2023-03-04  7:04 ` [PATCH 0/8] Arithmetic for 128-bit types Eli Zaretskii
@ 2023-03-08 16:17   ` Tom Tromey
  0 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-08 16:17 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Tom Tromey, gdb-patches

>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

>> Date: Fri,  3 Mar 2023 14:11:59 -0700
>> X-Spam-Status: No, score=-5.6 required=5.0 tests=BAYES_00, DKIM_SIGNED,
>> DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,
>> SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6
>> From: Tom Tromey via Gdb-patches <gdb-patches@sourceware.org>
>> 
>> This series adss basic arithmetic for 128-bit integer types to gdb.

Eli> Can you tell where and in what situations will this be useful?

Right now, if the inferior uses 128-bit integer types, then 'print'
works but no other operations work.  So for example, you cannot "print x + 1".

128-bit types are somewhat more common now.  Several of the languages
gdb supports have them (at least C, C++, Rust, and Ada).

Eli> Also, don't we need to announce this, at least in NEWS?

I added this:

    * GDB now has some support for integer types larger than 64 bits.

Tom

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/8] Arithmetic for 128-bit types
  2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
                   ` (8 preceding siblings ...)
  2023-03-04  7:04 ` [PATCH 0/8] Arithmetic for 128-bit types Eli Zaretskii
@ 2023-03-27 14:20 ` Tom Tromey
  9 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2023-03-27 14:20 UTC (permalink / raw)
  To: Tom Tromey via Gdb-patches; +Cc: Tom Tromey

>>>>> "Tom" == Tom Tromey via Gdb-patches <gdb-patches@sourceware.org> writes:

Tom> This series adss basic arithmetic for 128-bit integer types to gdb.
Tom> This is done using GMP, which gdb already requires.  While this
Tom> involves extra allocation, my view is that this hardly matters in most
Tom> expression contexts.  However, if it does turn out to matter, we can
Tom> try to switch to GCC's wide-integer code.

Tom> While this series, or something like it, is necessary for supporting
Tom> 128-bit types, it is not sufficient.  In particular, none of the
Tom> lexers or parsers are touched, and integers that are part of types
Tom> (e.g., range bounds) are not handled.

Tom> This series is based on my earlier series to clean up the GMP classes.

Tom> Regression tested on x86-64 Fedora 36.

I've rebased this and re-run the regression tests.
I'm going to check it in now.

Tom

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2023-03-27 14:20 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-03 21:11 [PATCH 0/8] Arithmetic for 128-bit types Tom Tromey
2023-03-03 21:12 ` [PATCH 1/8] Add many operators to gdb_mpz Tom Tromey
2023-03-07 13:38   ` Alexandra Petlanova Hajkova
2023-03-03 21:12 ` [PATCH 2/8] Avoid a copy in gdb_mpz::safe_export Tom Tromey
2023-03-03 21:12 ` [PATCH 3/8] Add truncation mode to gdb_mpz Tom Tromey
2023-03-03 21:12 ` [PATCH 4/8] Add value_as_mpz and value_from_mpz Tom Tromey
2023-03-08 10:47   ` Lancelot SIX
2023-03-08 15:48     ` Tom Tromey
2023-03-03 21:12 ` [PATCH 5/8] Simplify binop_promote Tom Tromey
2023-03-03 21:12 ` [PATCH 6/8] Use value_true in value_equal and value_less Tom Tromey
2023-03-03 21:12 ` [PATCH 7/8] Use gdb_gmp for scalar arithmetic Tom Tromey
2023-03-03 21:12 ` [PATCH 8/8] Fix 128-bit integer bug in Ada Tom Tromey
2023-03-04  7:04 ` [PATCH 0/8] Arithmetic for 128-bit types Eli Zaretskii
2023-03-08 16:17   ` Tom Tromey
2023-03-27 14:20 ` Tom Tromey

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).