public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Joel Brobecker <brobecker@adacore.com>
To: gdb-patches@sourceware.org
Cc: Simon Marchi <simark@simark.ca>, Joel Brobecker <brobecker@adacore.com>
Subject: [pushed/v2 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
Date: Sun, 15 Nov 2020 03:35:39 -0500	[thread overview]
Message-ID: <1605429345-78384-4-git-send-email-brobecker@adacore.com> (raw)
In-Reply-To: <1605429345-78384-1-git-send-email-brobecker@adacore.com>

This API was motivated by a number of reasons:
  - GMP's API does not handle "long long" and "unsigned long long",
    so using LONGEST and ULONGEST is not straightforward;
  - Automate the need to initialize GMP objects before use, and
    clear them when no longer used.

However, this API grew also to help with similar matter such
as formatting to a string, and also reading/writing fixed-point
values from byte buffers.

Dedicated unit testing is also added.

gdb/ChangeLog:

        * gmp-utils.h,  gmp-utils.h: New file.
        * unittests/gmp-utils-selftests.c: New file.
        * Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
        unittests/gmp-utils-selftests.c.
        (COMMON_SFILES) Add gmp-utils.c.
        (HFILES_NO_SRCDIR): Add gmp-utils.h.
---
 gdb/ChangeLog                       |   9 +
 gdb/Makefile.in                     |   3 +
 gdb/gmp-utils.c                     | 172 ++++++++++++++
 gdb/gmp-utils.h                     | 282 ++++++++++++++++++++++
 gdb/unittests/gmp-utils-selftests.c | 460 ++++++++++++++++++++++++++++++++++++
 5 files changed, 926 insertions(+)
 create mode 100644 gdb/gmp-utils.c
 create mode 100644 gdb/gmp-utils.h
 create mode 100644 gdb/unittests/gmp-utils-selftests.c

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8de390a..a029109 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* gmp-utils.h,  gmp-utils.h: New file.
+	* unittests/gmp-utils-selftests.c: New file.
+	* Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
+	unittests/gmp-utils-selftests.c.
+	(COMMON_SFILES) Add gmp-utils.c.
+	(HFILES_NO_SRCDIR): Add gmp-utils.h.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* configure.ac: Generate an error if a usable GMP library
 	could not be found.
 	* configure: Regenerate.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c461964..9b48f73 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -446,6 +446,7 @@ SELFTESTS_SRCS = \
 	unittests/filtered_iterator-selftests.c \
 	unittests/format_pieces-selftests.c \
 	unittests/function-view-selftests.c \
+	unittests/gmp-utils-selftests.c \
 	unittests/lookup_name_info-selftests.c \
 	unittests/memory-map-selftests.c \
 	unittests/memrange-selftests.c \
@@ -1059,6 +1060,7 @@ COMMON_SFILES = \
 	gdb_regex.c \
 	gdbarch.c \
 	gdbtypes.c \
+	gmp-utils.c \
 	gnu-v2-abi.c \
 	gnu-v3-abi.c \
 	go-lang.c \
@@ -1304,6 +1306,7 @@ HFILES_NO_SRCDIR = \
 	gdbthread.h \
 	gdbtypes.h \
 	glibc-tdep.h \
+	gmp-utils.h \
 	gnu-nat.h \
 	go-lang.h \
 	gregset.h \
diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
new file mode 100644
index 0000000..db92e57
--- /dev/null
+++ b/gdb/gmp-utils.c
@@ -0,0 +1,172 @@
+/* Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "gmp-utils.h"
+
+/* See gmp-utils.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+gmp_string_asprintf (const char *fmt, ...)
+{
+  va_list vp;
+  char *buf;
+
+  va_start (vp, fmt);
+  gmp_vasprintf (&buf, fmt, vp);
+  va_end (vp);
+
+  return gdb::unique_xmalloc_ptr<char> (buf);
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+	       bool unsigned_p)
+{
+  mpz_import (val, 1 /* count */, -1 /* order */, len /* size */,
+	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
+	      0 /* nails */, buf /* op */);
+
+  if (!unsigned_p)
+    {
+      /* The value was imported as if it was a positive value,
+	 as mpz_import does not handle signs. If the original value
+	 was in fact negative, we need to adjust VAL accordingly.  */
+      gdb_mpz max;
+
+      mpz_ui_pow_ui (max.val, 2, len * TARGET_CHAR_BIT - 1);
+      if (mpz_cmp (val, max.val) >= 0)
+	mpz_submul_ui (val, max.val, 2);
+    }
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpz::write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+		bool unsigned_p) const
+{
+  gdb_mpz exported_val (val);
+
+  if (mpz_cmp_ui (val, 0) < 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.val, 2, len * TARGET_CHAR_BIT);
+      mpz_add (exported_val.val, exported_val.val, neg_offset.val);
+    }
+
+  /* Start by clearing the buffer, as mpz_export only writes as many
+     bytes as it needs (including none, if the value to export is zero.  */
+  memset (buf, 0, len);
+  mpz_export (buf, NULL /* count */, -1 /* order */, len /* size */,
+	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
+	      0 /* nails */, exported_val.val);
+}
+
+/* See gmp-utils.h.  */
+
+gdb_mpz
+gdb_mpq::get_rounded () const
+{
+  /* Work with a positive number so as to make the "floor" rounding
+     always round towards zero.  */
+
+  gdb_mpq abs_val (val);
+  mpq_abs (abs_val.val, abs_val.val);
+
+  /* Convert our rational number into a quotient and remainder,
+     with "floor" rounding, which in our case means rounding
+     towards zero.  */
+
+  gdb_mpz quotient, remainder;
+  mpz_fdiv_qr (quotient.val, remainder.val,
+	       mpq_numref (abs_val.val), mpq_denref (abs_val.val));
+
+  /* Multiply the remainder by 2, and see if it is greater or equal
+     to abs_val's denominator.  If yes, round to the next integer.  */
+
+  mpz_mul_ui (remainder.val, remainder.val, 2);
+  if (mpz_cmp (remainder.val, mpq_denref (abs_val.val)) >= 0)
+    mpz_add_ui (quotient.val, quotient.val, 1);
+
+  /* Re-apply the sign if needed.  */
+  if (mpq_sgn (val) < 0)
+    mpz_neg (quotient.val, quotient.val);
+
+  return quotient;
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpq::read_fixed_point (const gdb_byte *buf, int len,
+			   enum bfd_endian byte_order, bool unsigned_p,
+			   const gdb_mpq &scaling_factor)
+{
+  gdb_mpz vz;
+  vz.read (buf, len, byte_order, unsigned_p);
+
+  mpq_set_z (val, vz.val);
+  mpq_mul (val, val, scaling_factor.val);
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpq::write_fixed_point (gdb_byte *buf, int len,
+			    enum bfd_endian byte_order, bool unsigned_p,
+			    const gdb_mpq &scaling_factor) const
+{
+  gdb_mpq unscaled (val);
+
+  mpq_div (unscaled.val, unscaled.val, scaling_factor.val);
+
+  gdb_mpz unscaled_z = unscaled.get_rounded ();
+  unscaled_z.write (buf, len, byte_order, unsigned_p);
+}
+
+/* A wrapper around xrealloc that we can then register with GMP
+   as the "realloc" function.  */
+
+static void *
+xrealloc_for_gmp (void *ptr, size_t old_size, size_t new_size)
+{
+  return xrealloc (ptr, new_size);
+}
+
+/* A wrapper around xfree that we can then register with GMP
+   as the "free" function.  */
+
+static void
+xfree_for_gmp (void *ptr, size_t size)
+{
+  xfree (ptr);
+}
+
+void _initialize_gmp_utils ();
+
+void
+_initialize_gmp_utils ()
+{
+  /* Tell GMP to use GDB's memory management routines.  */
+  mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp);
+}
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
new file mode 100644
index 0000000..1214b64
--- /dev/null
+++ b/gdb/gmp-utils.h
@@ -0,0 +1,282 @@
+/* Miscellaneous routines making it easier to use GMP within GDB's framework.
+
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef GMP_UTILS_H
+#define GMP_UTILS_H
+
+#include "defs.h"
+
+/* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
+   access to GMP's various formatting functions.  */
+#include <stdio.h>
+#include <stdarg.h>
+#include <gmp.h>
+#include "gdbsupport/traits.h"
+
+/* Same as gmp_asprintf, but returning a convenient wrapper type.  */
+
+gdb::unique_xmalloc_ptr<char> gmp_string_asprintf (const char *fmt, ...);
+
+/* A class to make it easier to use GMP's mpz_t values within GDB.  */
+
+struct gdb_mpz
+{
+  mpz_t val;
+
+  /* Constructors.  */
+  gdb_mpz () { mpz_init (val); }
+
+  explicit gdb_mpz (const mpz_t &from_val)
+  {
+    mpz_init (val);
+    mpz_set (val, from_val);
+  }
+
+  gdb_mpz (const gdb_mpz &from)
+  {
+    mpz_init (val);
+    mpz_set (val, from.val);
+  }
+
+  /* Initialize using the given integral value.
+
+     The main advantage of this method is that it handles both signed
+     and unsigned types, with no size restriction.  */
+  template<typename T, typename = gdb::Requires<std::is_integral<T>>>
+  explicit gdb_mpz (T src)
+  {
+    mpz_init (val);
+    set (src);
+  }
+
+  explicit gdb_mpz (gdb_mpz &&from)
+  {
+    mpz_init (val);
+    mpz_swap (val, from.val);
+  }
+
+  
+  gdb_mpz &operator= (const gdb_mpz &from)
+  {
+    mpz_set (val, from.val);
+    return *this;
+  }
+
+  gdb_mpz &operator= (gdb_mpz &&other)
+  {
+    mpz_swap (val, other.val);
+    return *this;
+  }
+
+  template<typename T, typename = gdb::Requires<std::is_integral<T>>>
+  gdb_mpz &operator= (T src)
+  {
+    set (src);
+    return *this;
+  }
+
+  /* Convert VAL 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;
+
+  /* Set VAL by importing the number stored in the byte buffer (BUF),
+     given its size (LEN) and BYTE_ORDER.
+
+     UNSIGNED_P indicates whether the number has an unsigned type.  */
+  void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+	     bool unsigned_p);
+
+  /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
+
+     UNSIGNED_P indicates whether the number has an unsigned type.  */
+  void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+	      bool unsigned_p) const;
+
+  /* Return a string containing VAL.  */
+  gdb::unique_xmalloc_ptr<char> str () const
+  { return gmp_string_asprintf ("%Zd", val); }
+
+  /* The destructor.  */
+  ~gdb_mpz () { mpz_clear (val); }
+
+private:
+
+  /* Helper template for constructor and operator=.  */
+  template<typename T> void set (T src);
+};
+
+/* A class to make it easier to use GMP's mpq_t values within GDB.  */
+
+struct gdb_mpq
+{
+  mpq_t val;
+
+  /* Constructors.  */
+  gdb_mpq () { mpq_init (val); }
+
+  explicit gdb_mpq (const mpq_t &from_val)
+  {
+    mpq_init (val);
+    mpq_set (val, from_val);
+  }
+
+  gdb_mpq (const gdb_mpq &from)
+  {
+    mpq_init (val);
+    mpq_set (val, from.val);
+  }
+
+  explicit gdb_mpq (gdb_mpq &&from)
+  {
+    mpq_init (val);
+    mpq_swap (val, from.val);
+  }
+
+  /* Copy assignment operator.  */
+  gdb_mpq &operator= (const gdb_mpq &from)
+  {
+    mpq_set (val, from.val);
+    return *this;
+  }
+
+  gdb_mpq &operator= (gdb_mpq &&from)
+  {
+    mpq_swap (val, from.val);
+    return *this;
+  }
+
+  /* Return a string representing VAL as "<numerator> / <denominator>".  */
+  gdb::unique_xmalloc_ptr<char> str () const
+  { return gmp_string_asprintf ("%Qd", val); }
+
+  /* Return VAL rounded to the nearest integer.  */
+  gdb_mpz get_rounded () const;
+
+  /* Set VAL from the contents of the given buffer (BUF), which
+     contains the unscaled value of a fixed point type object
+     with the given size (LEN) and byte order (BYTE_ORDER).
+
+     UNSIGNED_P indicates whether the number has an unsigned type.
+     SCALING_FACTOR is the scaling factor to apply after having
+     read the unscaled value from our buffer.  */
+  void read_fixed_point (const gdb_byte *buf, int len,
+			 enum bfd_endian byte_order, bool unsigned_p,
+			 const gdb_mpq &scaling_factor);
+
+  /* Write VAL into BUF as a LEN-bytes fixed point value following
+     the given BYTE_ORDER.
+
+     UNSIGNED_P indicates whether the number has an unsigned type.
+     SCALING_FACTOR is the scaling factor to apply before writing
+     the unscaled value to our buffer.  */
+  void write_fixed_point (gdb_byte *buf, int len,
+			  enum bfd_endian byte_order, bool unsigned_p,
+			  const gdb_mpq &scaling_factor) const;
+
+  /* The destructor.  */
+  ~gdb_mpq () { mpq_clear (val); }
+};
+
+/* A class to make it easier to use GMP's mpf_t values within GDB.
+
+   Should MPFR become a required dependency, we should probably
+   drop this class in favor of using MPFR.  */
+
+struct gdb_mpf
+{
+  mpf_t val;
+
+  /* Constructors.  */
+  gdb_mpf () { mpf_init (val); }
+
+  DISABLE_COPY_AND_ASSIGN (gdb_mpf);
+
+  /* Set VAL from the contents of the given buffer (BUF), which
+     contains the unscaled value of a fixed point type object
+     with the given size (LEN) and byte order (BYTE_ORDER).
+
+     UNSIGNED_P indicates whether the number has an unsigned type.
+     SCALING_FACTOR is the scaling factor to apply after having
+     read the unscaled value from our buffer.  */
+  void read_fixed_point (const gdb_byte *buf, int len,
+			 enum bfd_endian byte_order, bool unsigned_p,
+			 const gdb_mpq &scaling_factor)
+  {
+    gdb_mpq tmp_q;
+
+    tmp_q.read_fixed_point (buf, len, byte_order, unsigned_p, scaling_factor);
+    mpf_set_q (val, tmp_q.val);
+  }
+
+  /* The destructor.  */
+  ~gdb_mpf () { mpf_clear (val); }
+};
+
+/* See declaration above.  */
+
+template<typename T>
+void
+gdb_mpz::set (T src)
+{
+  mpz_import (val, 1 /* count */, -1 /* order */,
+	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
+	      0 /* nails */, &src /* op */);
+  if (std::is_signed<T>::value && src < 0)
+    {
+      /* mpz_import does not handle the sign, so our value was imported
+	 as an unsigned. Adjust that imported value so as to make it
+	 the correct negative value.  */
+      gdb_mpz neg_offset;
+
+      mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
+      mpz_sub (val, val, neg_offset.val);
+    }
+}
+
+/* See declaration above.  */
+
+template<typename T>
+T
+gdb_mpz::as_integer () const
+{
+  /* Initialize RESULT, because mpz_export only write the minimum
+     number of bytes, including none if our value is zero!  */
+  T result = 0;
+
+  gdb_mpz exported_val (val);
+  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
+    {
+      /* We want to use mpz_export to set the return value, but
+	 this function does not handle the sign. So give exported_val
+	 a value which is at the same time positive, and has the same
+	 bit representation as our negative value.  */
+      gdb_mpz neg_offset;
+
+      mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
+      mpz_add (exported_val.val, exported_val.val, neg_offset.val);
+    }
+
+  mpz_export (&result, NULL /* count */, -1 /* order */,
+	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
+	      0 /* nails */, exported_val.val);
+  return result;
+}
+
+#endif
diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
new file mode 100644
index 0000000..e8c3c5c
--- /dev/null
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -0,0 +1,460 @@
+/* Self tests of the gmp-utils API.
+
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "gmp-utils.h"
+#include "gdbsupport/selftest.h"
+
+#include <math.h>
+
+namespace selftests {
+
+/* Perform a series of general tests of gdb_mpz's as_integer method.
+
+   This function tries to be reasonably exhaustive, by testing the edges,
+   as well as a resonable set of values including negative ones, zero,
+   and positive values.  */
+
+static void
+gdb_mpz_as_integer ()
+{
+  /* Test a range of values, both as LONGEST and ULONGEST.  */
+  gdb_mpz v;
+  LONGEST l_expected;
+  ULONGEST ul_expected;
+
+  /* Start with the smallest LONGEST  */
+  l_expected = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
+
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
+  mpz_neg (v.val, v.val);
+
+  SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
+
+  /* Try with a small range of integers including negative, zero,
+     and positive values.  */
+  for (int i = -256; i <= 256; i++)
+    {
+      l_expected = (LONGEST) i;
+      mpz_set_si (v.val, i);
+      SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
+
+      if (i >= 0)
+	{
+	  ul_expected = (ULONGEST) i;
+	  mpz_set_ui (v.val, i);
+	  SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
+	}
+    }
+
+  /* Try with LONGEST_MAX.  */
+  l_expected = LONGEST_MAX;
+  ul_expected = (ULONGEST) l_expected;
+
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
+  mpz_sub_ui (v.val, v.val, 1);
+
+  SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
+  SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
+
+  /* Try with ULONGEST_MAX.  */
+  ul_expected = ULONGEST_MAX;
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8);
+  mpz_sub_ui (v.val, v.val, 1);
+
+  SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
+}
+
+/* A helper function to store the given integer value into a buffer,
+   before reading it back into a gdb_mpz.  Sets ACTUAL to the value
+   read back, while at the same time setting EXPECTED as the value
+   we would expect to be read back.
+
+   Note that this function does not perform the comparison between
+   EXPECTED and ACTUAL.  The caller will do it inside a SELF_CHECK
+   call, allowing the line information shown when the test fails
+   to provide a bit more information about the kind of values
+   that were used when the check failed.  This makes the writing
+   of the tests a little more verbose, but the debugging in case
+   of problems should hopefuly be easier.  */
+
+template<typename T>
+void
+store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
+		     gdb_mpz &expected, gdb_mpz &actual)
+{
+  gdb_byte *buf;
+
+  expected = val;
+
+  buf = (gdb_byte *) alloca (buf_len);
+  store_integer (buf, buf_len, byte_order, val);
+
+  /* Pre-initialize ACTUAL to something that's not the expected value.  */
+  mpz_set (actual.val, expected.val);
+  mpz_sub_ui (actual.val, actual.val, 500);
+
+  actual.read (buf, buf_len, byte_order, !std::is_signed<T>::value);
+}
+
+/* Test the gdb_mpz::read method over a reasonable range of values.
+
+   The testing is done by picking an arbitrary buffer length, after
+   which we test every possible value that this buffer allows, both
+   with signed numbers as well as unsigned ones.  */
+
+static void
+gdb_mpz_read_all_from_small ()
+{
+  /* Start with a type whose size is small enough that we can afford
+     to check the complete range.  */
+
+  int buf_len = 1;
+  LONGEST l_min = -pow (2, buf_len * 8 - 1);
+  LONGEST l_max = pow (2, buf_len * 8 - 1) - 1;
+
+  for (LONGEST l = l_min; l <= l_max; l++)
+    {
+      gdb_mpz expected, actual;
+
+      store_and_read_back (l, buf_len, BFD_ENDIAN_BIG, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+      store_and_read_back (l, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+    }
+
+  /* Do the same as above, but with an unsigned type.  */
+  ULONGEST ul_min = 0;
+  ULONGEST ul_max = pow (2, buf_len * 8) - 1;
+
+  for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
+    {
+      gdb_mpz expected, actual;
+
+      store_and_read_back (ul, buf_len, BFD_ENDIAN_BIG, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+      store_and_read_back (ul, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+    }
+}
+
+/* Test the gdb_mpz::read the extremes of LONGEST and ULONGEST.  */
+
+static void
+gdb_mpz_read_min_max ()
+{
+  gdb_mpz expected, actual;
+
+  /* Start with the smallest LONGEST.  */
+
+  LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
+
+  store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  /* Same with LONGEST_MAX.  */
+
+  LONGEST l_max = LONGEST_MAX;
+
+  store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  /* Same with the smallest ULONGEST.  */
+
+  ULONGEST ul_min = 0;
+
+  store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  /* Same with ULONGEST_MAX.  */
+
+  ULONGEST ul_max = ULONGEST_MAX;
+
+  store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+}
+
+/* A helper function which creates a gdb_mpz object from the given
+   integer VAL, and then writes it using its gdb_mpz::write method.
+
+   The written value is then extracted from the buffer and returned,
+   for comparison with the original.
+
+   Note that this function does not perform the comparison between
+   VAL and the returned value.  The caller will do it inside a SELF_CHECK
+   call, allowing the line information shown when the test fails
+   to provide a bit more information about the kind of values
+   that were used when the check failed.  This makes the writing
+   of the tests a little more verbose, but the debugging in case
+   of problems should hopefuly be easier.  */
+
+template<typename T>
+T
+write_and_extract (T val, int buf_len, enum bfd_endian byte_order)
+{
+  gdb_mpz v (val);
+
+  SELF_CHECK (v.as_integer<T> () == val);
+
+  gdb_byte *buf = (gdb_byte *) alloca (buf_len);
+  v.write (buf, buf_len, byte_order, !std::is_signed<T>::value);
+
+  return extract_integer<T> (buf, buf_len, byte_order);
+}
+
+/* Test the gdb_mpz::write method over a reasonable range of values.
+
+   The testing is done by picking an arbitrary buffer length, after
+   which we test every possible value that this buffer allows.  */
+
+static void
+gdb_mpz_write_all_from_small ()
+{
+  int buf_len = 1;
+  LONGEST l_min = -pow (2, buf_len * 8 - 1);
+  LONGEST l_max = pow (2, buf_len * 8 - 1) - 1;
+
+  for (LONGEST l = l_min; l <= l_max; l++)
+    {
+      SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_BIG) == l);
+      SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_LITTLE) == l);
+    }
+
+    /* Do the same as above, but with an unsigned type.  */
+  ULONGEST ul_min = 0;
+  ULONGEST ul_max = pow (2, buf_len * 8) - 1;
+
+  for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
+    {
+      SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_BIG) == ul);
+      SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_LITTLE) == ul);
+    }
+}
+
+/* Test the gdb_mpz::write the extremes of LONGEST and ULONGEST.  */
+
+static void
+gdb_mpz_write_min_max ()
+{
+  /* Start with the smallest LONGEST.  */
+
+  LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
+  SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG)
+	      == l_min);
+  SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
+	      == l_min);
+
+  /* Same with LONGEST_MAX.  */
+
+  LONGEST l_max = LONGEST_MAX;
+  SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG)
+	      == l_max);
+  SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
+	      == l_max);
+
+  /* Same with the smallest ULONGEST.  */
+
+  ULONGEST ul_min = (ULONGEST) 1 << (sizeof (ULONGEST) * 8 - 1);
+  SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG)
+	      == ul_min);
+  SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
+	      == ul_min);
+
+  /* Same with ULONGEST_MAX.  */
+
+  ULONGEST ul_max = ULONGEST_MAX;
+  SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG)
+	      == ul_max);
+  SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
+	      == ul_max);
+}
+
+/* A helper function which stores the signed number, the unscaled value
+   of a fixed point object, into a buffer, and then uses gdb_mpq's
+   read_fixed_point to read it as a fixed_point value, with
+   the given parameters.
+
+   EXPECTED is set to the value we expected to get after the call
+   to read_fixed_point.  ACTUAL is the value we actually do get.
+
+   Note that this function does not perform the comparison between
+   EXPECTED and ACTUAL.  The caller will do it inside a SELF_CHECK
+   call, allowing the line information shown when the test fails
+   to provide a bit more information about the kind of values
+   that were used when the check failed.  This makes the writing
+   of the tests a little more verbose, but the debugging in case
+   of problems should hopefuly be easier.  */
+
+static void
+read_fp_test (int unscaled, const gdb_mpq &scaling_factor,
+	      enum bfd_endian byte_order,
+	      gdb_mpq &expected, gdb_mpq &actual)
+{
+  /* For this kind of testing, we'll use a buffer the same size as
+     our unscaled parameter.  */
+  const int len = sizeof (unscaled);
+  gdb_byte buf[len];
+  store_signed_integer (buf, len, byte_order, unscaled);
+
+  actual.read_fixed_point (buf, len, byte_order, 0, scaling_factor);
+
+  mpq_set_si (expected.val, unscaled, 1);
+  mpq_mul (expected.val, expected.val, scaling_factor.val);
+}
+
+/* Perform various tests of the gdb_mpq::read_fixed_point method.  */
+
+static void
+gdb_mpq_read_fixed_point ()
+{
+  gdb_mpq expected, actual;
+  gdb_mpq scaling_factor;
+
+  /* Pick an arbitrary scaling_factor; this operation is trivial enough
+     thanks to GMP that the value we use isn't really important.  */
+  mpq_set_ui (scaling_factor.val, 3, 5);
+
+  /* Try a few values, both negative and positive... */
+
+  read_fp_test (-256, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (-256, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (-1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (-1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (0, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (0, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (1025, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (1025, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+}
+
+/* A helper function which builds a gdb_mpq object from the given
+   NUMERATOR and DENOMINATOR, and then calls gdb_mpq's write_fixed_point
+   method to write it to a buffer.
+
+   The value written into the buffer is then read back as is,
+   and returned.  */
+
+static LONGEST
+write_fp_test (int numerator, unsigned int denominator,
+	       const gdb_mpq &scaling_factor,
+	       enum bfd_endian byte_order)
+{
+  /* For this testing, we'll use a buffer the size of LONGEST.
+     This is really an arbitrary decision, as long as the buffer
+     is long enough to hold the unscaled values that we'll be
+     writing.  */
+  const int len = sizeof (LONGEST);
+  gdb_byte buf[len];
+  memset (buf, 0, len);
+
+  gdb_mpq v;
+  mpq_set_ui (v.val, numerator, denominator);
+  mpq_canonicalize (v.val);
+  v.write_fixed_point (buf, len, byte_order, 0, scaling_factor);
+
+  return extract_unsigned_integer (buf, len, byte_order);
+}
+
+/* Perform various tests of the gdb_mpq::write_fixed_point method.  */
+
+static void
+gdb_mpq_write_fixed_point ()
+{
+  /* Pick an arbitrary factor; this operations is sufficiently trivial
+     with the use of GMP that the value of this factor is not really
+     all that important.  */
+  gdb_mpq scaling_factor;
+  mpq_set_ui (scaling_factor.val, 1, 3);
+
+  gdb_mpq vq;
+
+  /* Try a few multiples of the scaling factor, both negative,
+     and positive... */
+
+  SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_BIG) == -24);
+  SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_LITTLE) == -24);
+
+  SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_BIG) == -2);
+  SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_LITTLE) == -2);
+
+  SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_BIG) == 0);
+  SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 0);
+
+  SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_BIG) == 5);
+  SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 5);
+}
+
+}
+
+void _initialize_gmp_utils_selftests ();
+
+void
+_initialize_gmp_utils_selftests ()
+{
+  selftests::register_test ("gdb_mpz_as_integer",
+			    selftests::gdb_mpz_as_integer);
+  selftests::register_test ("gdb_mpz_read_all_from_small",
+			    selftests::gdb_mpz_read_all_from_small);
+  selftests::register_test ("gdb_mpz_read_min_max",
+			    selftests::gdb_mpz_read_min_max);
+  selftests::register_test ("gdb_mpz_write_all_from_small",
+			    selftests::gdb_mpz_write_all_from_small);
+  selftests::register_test ("gdb_mpz_write_min_max",
+			    selftests::gdb_mpz_write_min_max);
+  selftests::register_test ("gdb_mpq_read_fixed_point",
+			    selftests::gdb_mpq_read_fixed_point);
+  selftests::register_test ("gdb_mpq_write_fixed_point",
+			    selftests::gdb_mpq_write_fixed_point);
+}
-- 
2.1.4


  parent reply	other threads:[~2020-11-15  8:36 UTC|newest]

Thread overview: 140+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
2020-11-08  6:30 ` [PATCH 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
2020-11-08  6:30 ` [PATCH 2/9] gdb: Make GMP a required dependency for building GDB Joel Brobecker
2020-12-15  6:55   ` Sebastian Huber
2020-12-15  8:57     ` Joel Brobecker
2020-11-08  6:30 ` [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects Joel Brobecker
2020-11-10 20:15   ` Simon Marchi
2020-11-13  8:12     ` Joel Brobecker
2020-11-13 15:04       ` Tom Tromey
2020-11-13 15:06         ` Simon Marchi
2020-11-16 16:18         ` Tom Tromey
2020-11-16 16:34   ` Luis Machado
2020-11-18  3:52     ` Joel Brobecker
2020-11-08  6:30 ` [PATCH 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public Joel Brobecker
2020-11-08  6:30 ` [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects Joel Brobecker
2020-11-10 21:06   ` Simon Marchi
2020-11-14 10:48     ` Joel Brobecker
2020-11-14 13:20       ` Simon Marchi
2020-11-14 11:30     ` Joel Brobecker
2020-11-14 16:14       ` Simon Marchi
2020-11-15  5:30         ` Joel Brobecker
2020-11-15  6:33     ` Joel Brobecker
2020-11-16  0:13       ` Simon Marchi
2020-11-08  6:30 ` [PATCH 6/9] fix printing of DWARF fixed-point type objects with format modifier Joel Brobecker
2020-11-10 22:50   ` Simon Marchi
2020-11-08  6:30 ` [PATCH 7/9] Add ptype support for DWARF-based fixed-point types Joel Brobecker
2020-11-10 23:00   ` Simon Marchi
2020-11-15  6:57     ` Joel Brobecker
2020-11-15  7:09       ` Joel Brobecker
2020-11-16  0:16         ` Simon Marchi
2020-11-16  4:03           ` Joel Brobecker
2020-11-08  6:30 ` [PATCH 8/9] Add support for fixed-point type arithmetic Joel Brobecker
2020-11-10 23:18   ` Simon Marchi
2020-11-08  6:30 ` [PATCH 9/9] Add support for fixed-point type comparison operators Joel Brobecker
2020-11-10 23:21 ` RFA: Add support for DWARF-based fixed point types Simon Marchi
2020-11-11  4:53   ` Joel Brobecker
2020-11-15  8:35 ` pushed: " Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
2020-11-15 15:52     ` Bernd Edlinger
2020-11-16  3:45       ` Joel Brobecker
2020-11-16 14:20         ` Bernd Edlinger
2020-11-17  7:41           ` [PATCH] Enable GDB build with in-tree GMP and MPFR Bernd Edlinger
2020-11-18  3:44             ` Joel Brobecker
2020-11-18  8:14               ` Bernd Edlinger
2020-12-01 19:29                 ` Bernd Edlinger
2020-12-01 19:32                   ` Simon Marchi
2020-12-01 19:38                     ` Bernd Edlinger
2020-12-01 20:29                       ` Bernd Edlinger
2020-12-01 20:30                         ` Simon Marchi
2020-12-02  3:21                           ` Joel Brobecker
2020-12-08 20:39                             ` [PING] " Bernd Edlinger
2020-12-14 17:40                         ` [PATCH v2] " Bernd Edlinger
2020-12-14 18:47                           ` Simon Marchi
2020-12-14 21:35                             ` Tom Tromey
2020-12-14 22:17                               ` Simon Marchi
2020-12-15  2:33                                 ` Joel Brobecker
2020-12-15 14:39                                   ` Simon Marchi
2020-12-15 16:24                                     ` Bernd Edlinger
2020-12-16  7:33                                     ` Joel Brobecker
2020-12-16 18:16                                       ` Bernd Edlinger
2020-12-25 12:05                                         ` Bernd Edlinger
2020-12-27 22:01                                           ` Simon Marchi
2020-12-29  8:36                                             ` Bernd Edlinger
2020-12-29 14:50                                               ` Simon Marchi
2021-01-10 14:12                                                 ` Bernd Edlinger
2021-01-10 15:32                                                   ` Simon Marchi
2021-01-11  3:22                                                   ` Joel Brobecker
2021-01-16 18:01                                                     ` Bernd Edlinger
2020-12-15 15:33                                 ` Bernd Edlinger
2020-12-15 15:10                             ` Bernd Edlinger
2020-11-15  8:35   ` [pushed/v2 2/9] gdb: Make GMP a required dependency for building GDB Joel Brobecker
2020-11-15  8:35   ` Joel Brobecker [this message]
2020-11-15  8:35   ` [pushed/v2 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 5/9] Add support for printing value of DWARF-based fixed-point type objects Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 6/9] fix printing of DWARF fixed-point type objects with format modifier Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 7/9] Add ptype support for DWARF-based fixed-point types Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 8/9] Add support for fixed-point type arithmetic Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 9/9] Add support for fixed-point type comparison operators Joel Brobecker
2020-11-16 23:48   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
2020-11-17 14:25     ` Simon Marchi
2020-11-18  3:47       ` Joel Brobecker
2020-11-22 13:12         ` [RFA] Add TYPE_CODE_FIXED_POINT handling in print_type_scalar Joel Brobecker
2020-11-22 14:35           ` Simon Marchi
2020-11-24  3:04             ` Joel Brobecker
2020-11-22 14:00         ` pushed: Add support for DWARF-based fixed point types Joel Brobecker
2020-11-22 20:11           ` Simon Marchi
2020-11-23  4:27             ` Joel Brobecker
2020-11-23 16:12               ` Simon Marchi
2020-11-24  2:39                 ` Joel Brobecker
2020-11-29 15:45               ` RFA: wrap mpz_export into gdb_mpz::safe_export Joel Brobecker
2020-11-29 15:45                 ` [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c Joel Brobecker
2020-11-30 15:42                   ` Simon Marchi
2020-12-05  8:05                     ` Joel Brobecker
2020-11-29 15:45                 ` [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values Joel Brobecker
2020-11-30 15:56                   ` Simon Marchi
2020-12-01  3:37                     ` Joel Brobecker
2020-12-01  4:02                       ` Simon Marchi
2020-12-01  7:11                         ` Joel Brobecker
2020-12-05  8:10                   ` [RFAv2 " Joel Brobecker
2020-12-05 23:26                     ` Simon Marchi
2020-12-06  4:58                       ` Joel Brobecker
2020-11-30 12:44                 ` RFA: wrap mpz_export into gdb_mpz::safe_export Christian Biesinger
2020-11-20 14:08   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
2020-11-20 14:14     ` Joel Brobecker
2020-11-22 11:56   ` RFA/doco: Various changes related to GMP and fixed point type support Joel Brobecker
2020-11-22 11:56     ` [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP Joel Brobecker
2020-11-22 15:31       ` Eli Zaretskii
2020-11-24  3:11         ` Joel Brobecker
2020-11-22 11:56     ` [RFA/doco 2/4] gdb/NEWS: Document that GDB now supports DWARF-based fixed point types Joel Brobecker
2020-11-22 15:33       ` Eli Zaretskii
2020-11-24  3:12         ` Joel Brobecker
2020-11-22 11:56     ` [RFA/doco 3/4] gdb/README: Document the --with-libgmp-prefix configure option Joel Brobecker
2020-11-22 15:32       ` Eli Zaretskii
2020-11-24  3:11         ` Joel Brobecker
2020-11-22 11:56     ` [RFA/doco 4/4] gdb/README: Fix the URL of the MPFR website (now https) Joel Brobecker
2020-11-22 15:33       ` Eli Zaretskii
2020-11-24  3:11         ` Joel Brobecker
2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
2020-11-15  8:49   ` [RFA 1/6] change gmp_string_asprintf to return an std::string Joel Brobecker
2020-11-16  0:41     ` Simon Marchi
2020-11-16  3:55       ` Joel Brobecker
2020-11-16 20:10         ` Simon Marchi
2020-11-15  8:49   ` [RFA 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view Joel Brobecker
2020-11-16  0:52     ` Simon Marchi
2020-11-16 23:05       ` Pedro Alves
2020-11-17 14:32         ` Simon Marchi
2020-11-15  8:49   ` [RFA 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro Joel Brobecker
2020-11-15  8:49   ` [RFA 4/6] Make fixed_point_type_base_type a method of struct type Joel Brobecker
2020-11-15  8:49   ` [RFA 5/6] Make function fixed_point_scaling_factor " Joel Brobecker
2020-11-15  8:49   ` [RFA 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda Joel Brobecker
2020-11-16  1:01   ` RFA: Various enhancements to the fixed-point support implementation Simon Marchi
2020-11-22 11:14   ` RFA v2: " Joel Brobecker
2020-11-22 11:14     ` [RFA v2 1/6] change and rename gmp_string_asprintf to return an std::string Joel Brobecker
2020-11-22 11:14     ` [RFA v2 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view Joel Brobecker
2020-11-22 11:14     ` [RFA v2 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro Joel Brobecker
2020-11-22 11:14     ` [RFA v2 4/6] Make fixed_point_type_base_type a method of struct type Joel Brobecker
2020-11-22 11:14     ` [RFA v2 5/6] Make function fixed_point_scaling_factor " Joel Brobecker
2020-11-22 11:14     ` [RFA v2 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda Joel Brobecker
2020-11-23 16:46     ` RFA v2: Various enhancements to the fixed-point support implementation Simon Marchi
2020-11-24  2:56       ` Joel Brobecker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1605429345-78384-4-git-send-email-brobecker@adacore.com \
    --to=brobecker@adacore.com \
    --cc=gdb-patches@sourceware.org \
    --cc=simark@simark.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).