Re: Has there been historical work done to investigate small integer optimization?
On Sun, 11 Feb 2024, Stefan Koch wrote: There is a fair amount of recent activity in the c++ world to optimize for speed by minimizing processor cache misses. One example is for in the std::string class there is a concept of "short string optimization". What this does is that for shorter strings the data is stored in the string class itself without need for dynamic memory allocation. This has two advantages: it does not need to make a call to dynamic memory allocation, and the string data is in the same location as the meta data, and so only in one cache fetch. Both of which are potentially slow. When I was looking at the implementation the _mp_d member of __mpz_struct is 8 bytes, which is also the size of a single limb entry. (I suspect that this is common on recent systems, but it is probably not be universal.) My thought was that if _mp_alloc is one, then we have one limb needed. In that case, the space of _mp_d could serve as the limb itself instead of the pointer to the limb. That would eliminate dynamic memory allocation for all integers under 2^64. I was coming at this from a computer algebra system standpoint. I think (but I really don't know), that much of the arithmetic that is done is done with integers under 2^64, and so those systems may be much faster if gmp had a small integer optimization. This approach will add a check when accessing the limb data for all accesses but will save accessing potentially non cpu cache data for small integers. It may turn out that the small delay is not so noticeable for large numbers, and the optimization for small numbers makes a large difference for small numbers. A second thought is to do the arithmetic if the sources are and result will fit in a single limb with inline functions or macros. That would eliminate the function call entirely for small numbers. It would make the code longer, and add additional overhead for when the integers are not short, but is it not clear how much of an impact that is for lager numbers. Anyway, I know you guys take performance very seriously, so I was wondering if you had experience with this? 1. Is there real potential for performance improvements in cas systems if gmp has a small integer optimization? 2. Have you looked at an approach like this in the past? and if so what have you found? 3. If you think this is something worth pursuing, do you have any advice? Several software already wrap GMP using this kind of strategy: a "number" is either a 63-bit integer or a pointer to a GMP big integer (this is determined by one bit), operations on 63-bit integers are inline. What is efficient depends on your use case. If you want to use the same integer type everywhere, you should definitely optimize for the small case. If you use separate types for small vs big, and big integers are always big, then you should optimize for the big case. There is also an intermediate size where numbers occupy just a few limbs, where allocation can still dominate computation, and a small-string-like optimization can help significantly (see Boost.Multiprecision's cpp_int). Again, a one-size-fits-all seems optimistic. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Requests from Microsoft IP Addresses
On Sun, 18 Jun 2023, Niels Möller wrote: It would be reasonable for any project that wants to pull GMP sources from 100 machines very often to set up their own mirror, do *incremental* updates of the mirror rather than a full clone, and do that at most a few times a day. I am not disagreeing with that (see my last sentence). But I don't think it's the GMP project's responsibility to provide such a mirror. It shouldn't be your responsibility to not get robbed, yet you lock your door when you are away. I am trying to be realistic. The current trend is an ever more wasteful use of resources in continuous integration (why would people bother optimizing this as long as it works?). A mirror is probably less work than what it saves, and pushes the problem to someone else (github). Of course that's assuming the current issue is indeed a very wasteful CI setup. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Requests from Microsoft IP Addresses
One thing that should be doable is set up a mirror of GMP's repository on github, and advertise that one for CI purposes. Any user could do that (there are already a few), but if it was advertised on the GMP website, it would be more likely to be used by more people. Of course it would be good if people didn't set up their CI in such a wasteful way, but the trend doesn't make me very optimistic. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: C++ long long
If nobody complains and I don't see something horribly flawed in the patch, I am going to push this version, which for now only adds initialization and assignment from long long when in C++11 mode (I expect we will remove support for C++ compilers without long long in the next release, but for now it is conditional). It doesn't add interoperability for other operations, so z+1LL will still fail. Handling all operations can require a lot more code, depending on how it is done, and can be done later. Conversions are already quite useful for users, in particular they are sufficient to let Eigen use mpq_class as a custom scalar type on windows. -- Marc Glissediff -r 88e4445a72d1 doc/gmp.texi --- a/doc/gmp.texi Mon Apr 18 16:19:20 2022 +0200 +++ b/doc/gmp.texi Tue Apr 19 20:06:00 2022 +0200 @@ -6919,7 +6919,7 @@ @deftypefun {} mpz_class::mpz_class (type @var{n}) Construct an @code{mpz_class}. All the standard C++ types may be used, except -@code{long long} and @code{long double}, and all the GMP C++ classes can be +@code{long long} (in C++98) and @code{long double}, and all the GMP C++ classes can be used, although conversions from @code{mpq_class} and @code{mpf_class} are @code{explicit}. Any necessary conversion follows the corresponding C function, for example @code{double} follows @code{mpz_set_d} @@ -7026,7 +7026,7 @@ Construct an @code{mpq_class}. The initial value can be a single value of any type (conversion from @code{mpf_class} is @code{explicit}), or a pair of integers (@code{mpz_class} or standard C++ integer types) representing a -fraction, except that @code{long long} and @code{long double} are not +fraction, except that @code{long long} (in C++98) and @code{long double} are not supported. For example, @example @@ -7124,7 +7124,7 @@ @deftypefun {} mpf_class::mpf_class (type @var{op}) @deftypefunx {} mpf_class::mpf_class (type @var{op}, mp_bitcnt_t @var{prec}) Construct an @code{mpf_class}. Any standard C++ type can be used, except -@code{long long} and @code{long double}, and any of the GMP C++ classes can be +@code{long long} (in C++98) and @code{long double}, and any of the GMP C++ classes can be used. If @var{prec} is given, the initial precision is that value, in bits. If diff -r 88e4445a72d1 gmpxx.h --- a/gmpxx.h Mon Apr 18 16:19:20 2022 +0200 +++ b/gmpxx.h Tue Apr 19 20:06:00 2022 +0200 @@ -106,6 +106,23 @@ // Note: we know the high bit of l is 0 so we could do slightly better } +#if __GMPXX_USE_CXX11 +inline void __mpz_set_ull_safe(mpz_ptr z, unsigned long long l) +{ +# if ULONG_MAX == ULLONG_MAX + __mpz_set_ui_safe(z, static_cast(l)); +# else + mp_limb_t *p = z->_mp_d; + while (l != 0) + { +*p++ = static_cast(l & GMP_NUMB_MASK); +l >>= GMP_NUMB_BITS; + } + z->_mp_size = p - z->_mp_d; +# endif +} +#endif + // Fake temporary variables #define __GMPXX_TMPZ_UI \ mpz_t temp;\ @@ -154,6 +171,13 @@ return l >= 0 ? static_cast(l) : -static_cast(l); } +#if __GMPXX_USE_CXX11 +inline unsigned long long __gmpxx_abs_ull (signed long long l) +{ + return l >= 0 ? static_cast(l) + : -static_cast(l); +} +#endif / Function objects / /* Any evaluation of a __gmp_expr ends up calling one of these functions @@ -1511,6 +1535,35 @@ inline __gmp_expr & fun(); \ inline __gmp_expr fun(int); +#if __GMPXX_USE_CXX11 +#define __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS \ + __gmp_expr(signed char c) { init_si(c); } \ + __gmp_expr(unsigned char c) { init_ui(c); } \ + __gmp_expr(signed int i) { init_si(i); } \ + __gmp_expr(unsigned int i) { init_ui(i); } \ + __gmp_expr(signed short int s) { init_si(s); } \ + __gmp_expr(unsigned short int s) { init_ui(s); } \ + __gmp_expr(signed long int l) { init_si(l); } \ + __gmp_expr(unsigned long int l) { init_ui(l); } \ + __gmp_expr(signed long long l) { init_sll(l); } \ + __gmp_expr(unsigned long long l) { init_ull(l); } \ + __gmp_expr(float f) { init_d(f); } \ + __gmp_expr(double d) { init_d(d); } + +#define __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS \ + __gmp_expr & operator=(signed char c) { assign_si(c); return *this; } \ + __gmp_expr & operator=(unsigned char c) { assign_ui(c); return *this; } \ + __gmp_expr & operator=(signed int i) { assign_si(i); return *this; } \ + __gmp_expr & operator=(unsigned int i) { assign_ui(i); return *this; } \ + __gmp_expr & operator=(signed short int s) { assign_si(s); return *this; } \ + __gmp_expr & operator=(unsigned short int s) { assign_ui(s); return *this; } \ + __gmp_expr & operator=(signed long int l) { assign_si(l); return *this; } \ + __gmp_expr & operator=(unsigned long int l) { assign_ui(l); return *this; } \ + __gmp_expr & operator=(signed long long l) { assign_sll(l); return *this; } \ + __gmp_expr & operator=(unsigned long long l) { assign_ull(l); return *this; } \ + __gmp_expr & operator=(float f) { assign_d(f); return *this; } \ + __gmp_expr &
mpq_mul_ui
Hello, What would you think of adding mpq_mul_ui, mpq_div_ui, mpq_ui_div, and also the _z versions? Something like (untested) void mpq_mul_ui (mpq_ptr prod, mpq_srcptr op, unsigned long m) { unsigned long gcd_ui; if (SIZ (NUM (op)) == 0 || m == 0) { /* We special case this to simplify allocation logic; gcd(0,x) = x is a singular case for the allocations. */ SIZ (NUM (prod)) = 0; MPZ_NEWALLOC (DEN (prod), 1)[0] = 1; SIZ (DEN (prod)) = 1; return; } #if 0 if (m == 1) { if (prod != op) mpq_set (prod, op); return; } #endif gcd_ui = mpz_gcd_ui (0, DEN (op), m); #if 0 if (gcd_ui == 1) { mpz_mul_ui (NUM (prod), NUM (op), m); if (prod != op) mpz_set (DEN (prod), DEN (op)); } #endif mpz_mul_ui (NUM (prod), NUM (op), m / gcd_ui); mpz_divexact_ui (DEN (prod), DEN (op), gcd_ui); // mpz_divexact_gcd (DEN (prod), DEN (op), gcd_z); } mpq_add_ui is easy to emulate with mpz_addmul_ui, but mpq_mul_ui is a bit harder (3 operations plus the need to handle 0 explicitly). I can add similar code directly in gmpxx.h, but I first wanted to check if a C version was desirable. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Doc tweak
Hello, someone got confused by the text saying that all the GMP declarations are in gmp.h and thought the C++ class interface would be there as well, so I'll probably add this patch unless someone has a better proposition. (shell seems to be missing some packages to build the doc in ps or pdf) --- a/doc/gmp.texi Tue Nov 02 02:02:59 2021 +0100 +++ b/doc/gmp.texi Sat Nov 06 13:32:05 2021 +0100 @@ -1860,7 +1860,9 @@ @cindex Include files @cindex @code{#include} All declarations needed to use GMP are collected in the include file -@file{gmp.h}. It is designed to work with both C and C++ compilers. +@file{gmp.h}, except for the @ref{C++ Class Interface} which comes with its +own separate header @file{gmpxx.h}. @file{gmp.h} is designed to work with +both C and C++ compilers. @example #include @@ -1868,7 +1870,7 @@ @cindex @code{stdio.h} Note however that prototypes for GMP functions with @code{FILE *} parameters -are only provided if @code{} is included too. +are only provided if @code{} is included before. @example #include @@ -1892,9 +1894,10 @@ @end example @cindex @code{libgmpxx} -GMP C++ functions are in a separate @file{libgmpxx} library. This is built -and installed if C++ support has been enabled (@pxref{Build Options}). For -example, +GMP C++ functions are in a separate @file{libgmpxx} library, including the +@ref{C++ Class Interface} but also @ref{C++ Formatted Output} for regular +GMP types. This is built and installed if C++ support has been enabled +(@pxref{Build Options}). For example, @example g++ mycxxprog.cc -lgmpxx -lgmp -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: gmp-6.2.1 on Tru64 with gcc.
Please check the repository https://gmplib.org/repo/gmp/rev/37cee5a85875 On Sat, 3 Jul 2021, Jay K wrote: On OSF/1/Tru64, inttypes.h lacks uint_least32_t and gcc's stdint.h does have uint_least32_t. autoconf says uint_least32_t is there because it includes stdint.h, but then: #if HAVE_INTTYPES_H /* for uint_least32_t */ # include #else<== the problem # if HAVE_STDINT_H # include # endif #endif leading to: ../gmp-impl.h:233:1: error: unknown type name 'uint_least32_t' In file included from hgcd_appr.c:35:0: ../gmp-impl.h:233:1: error: unknown type name 'uint_least32_t' So please remove the else? and then whitespace and comment: diff -u gmp-impl.h.orig gmp-impl.h --- gmp-impl.h.orig 2021-07-03 18:23:37 -0400 +++ gmp-impl.h 2021-07-03 18:25:04 -0400 @@ -152,12 +152,12 @@ #endif #endif -#if HAVE_INTTYPES_H /* for uint_least32_t */ +/* uint_least32_t can be in inttypes.h or stdint.h */ +#if HAVE_INTTYPES_H # include -#else -# if HAVE_STDINT_H -# include -# endif +#endif +#if HAVE_STDINT_H +# include #endif Thank you, - Jay ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: pointers vs arrays
On Fri, 11 Jun 2021, Emmanuel Thomé wrote: On Thu, Jun 10, 2021 at 03:02:25PM +0200, Marc Glisse wrote: On Thu, 10 Jun 2021, Emmanuel Thomé wrote: > And as it turns out, we even discussed that very documentation bit about > three years ago (here a link to an actual patch -- original discussion > was in may 2018). > > https://gmplib.org/list-archives/gmp-devel/2019-January/005182.html The description of mpq_numref is a bit misleading, it does not cast away constness (as opposed to say the C function strstr), but that's not new with your patch. I assume that patch was covered by an assignment to the FSF? First: a good share of the text is actually Niels's. Ah, I didn't go far enough back to see that. Niels, is enough of this text yours that we don't need an assignment from Emmanuel? Do you want to commit it yourself, or would you rather I do it? I haven't filled a copyright assignment, based on the idea that my contribution is in the ballpark of trivial enough changes. But I don't object to doing the paperwork if needed. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: pointers vs arrays
On Thu, 10 Jun 2021, Emmanuel Thomé wrote: And as it turns out, we even discussed that very documentation bit about three years ago (here a link to an actual patch -- original discussion was in may 2018). https://gmplib.org/list-archives/gmp-devel/2019-January/005182.html The description of mpq_numref is a bit misleading, it does not cast away constness (as opposed to say the C function strstr), but that's not new with your patch. I assume that patch was covered by an assignment to the FSF? Would someone object if I applied that patch, after making sure it still compiles? -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: pointers vs arrays
On Wed, 9 Jun 2021, Marco Bodrato wrote: Il 2021-05-12 15:17 Marc Glisse ha scritto: the latest version of gcc has a new (questionable) warning that complains if a function is declared as taking a mpz_t parameter and redeclared as taking mpz_ptr, or the reverse. We might as well be consistent and use pointers everywhere, as in the attached patch. Does someone disagree? Maybe this will move the warnings on the users side :-/ Maybe, but only if people redeclare the GMP functions themselves in addition to including gmp.h, which looks like a strange idea. I wondered about using gmp_randstate_t instead of gmp_randstate_ptr to avoid changing gmp.h, but that would not be consistent with mpz_t, etc. Or maybe change all prototypes to use mpz_t instead of mpz_ptr... To me, the most sensible option for users remains disabling this warning globally. By the way, I think that also the documentation should be updated accordingly. We have never documented mpz_ptr/mpz_srcptr, my patch does not change this discrepancy. Maybe this is a new motivation to document it, but that seems like a lot of boring work... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
C++ long long
Hello, I am tempted to go with something like the attached patch to support long long in gmpxx.h. (the patch is not quite ready) Essentially, it adds a way to build mpz_class from long long, and for all other operations, long long is converted to long if it fits and to mpz_class otherwise. So z+1LL is turned into z+1L on x86_64-linux and z+mpz_class(1LL) on win64. A possible improvement would be to delay the replacement until evaluation, so we can check at runtime if the long long fits a long, instead of just checking if the 2 types have the same size. It would also allow using an mpz_t pointing to a local buffer to avoid a dynamic allocation. It is a bit more code though. I am tempted to require a compiler that supports long long for gmpxx.h. We could require C++11 for that, but just long long is a much weaker requirement. I currently use a fake type for C++98 to avoid repeating #if all over the place. Of course this can be updated once GMP itself adds support for long long, but I think it can be merged first without causing trouble. -- Marc Glissediff -r 632506b00743 gmpxx.h --- a/gmpxx.h Sat May 08 19:34:05 2021 +0200 +++ b/gmpxx.h Sun Jun 06 23:37:17 2021 +0200 @@ -65,8 +65,18 @@ #if __GMPXX_USE_CXX11 #define __GMPXX_NOEXCEPT noexcept #include // for common_type +typedef signed long long int __gmp_slli; +typedef unsigned long long int __gmp_ulli; #else #define __GMPXX_NOEXCEPT +// Fake long long to avoid too many #ifdef +struct __gmp_slli { bool operator<(int) const; }; +struct __gmp_ulli { + __gmp_ulli(__gmp_slli); + operator unsigned long() const; + __gmp_ulli operator-() const; + __gmp_ulli operator>>(int) const; +}; #endif // Max allocations for plain types when converted to GMP types @@ -154,6 +164,11 @@ return l >= 0 ? static_cast(l) : -static_cast(l); } +inline __gmp_ulli __gmpxx_abs_ull (__gmp_slli l) +{ + return l < 0 ? -static_cast<__gmp_ulli>(l) + : static_cast<__gmp_ulli>(l); +} / Function objects / /* Any evaluation of a __gmp_expr ends up calling one of these functions @@ -1333,6 +1348,9 @@ template class __gmp_expr; +typedef __gmp_expr mpz_class; +typedef __gmp_expr mpq_class; +typedef __gmp_expr mpf_class; // templates for resolving expression types template @@ -1411,6 +1429,27 @@ typedef mpf_t value_type; }; +// To reduce code bloat, signed char, short and int are cast to long +// internally, and similarly for unsigned types. long long is cast to long if +// that has the same size, or mpz_class otherwise. +template ::is_signed> +struct __gmpxx_int_canonical +{ + typedef mpz_class Type; +}; + +template +struct __gmpxx_int_canonical +{ + typedef long Type; +}; + +template +struct __gmpxx_int_canonical +{ + typedef unsigned long Type; +}; + #if __GMPXX_USE_CXX11 namespace std { template @@ -1449,6 +1488,8 @@ __GMPXX_DECLARE_COMMON_TYPE(unsigned short int); __GMPXX_DECLARE_COMMON_TYPE(signed long int); __GMPXX_DECLARE_COMMON_TYPE(unsigned long int); + __GMPXX_DECLARE_COMMON_TYPE(__gmp_slli); + __GMPXX_DECLARE_COMMON_TYPE(__gmp_ulli); __GMPXX_DECLARE_COMMON_TYPE(float); __GMPXX_DECLARE_COMMON_TYPE(double); #undef __GMPXX_DECLARE_COMMON_TYPE @@ -1496,6 +1537,8 @@ __gmp_expr & fun(unsigned short int); \ __gmp_expr & fun(signed long int); \ __gmp_expr & fun(unsigned long int);\ + __gmp_expr & fun(__gmp_slli); \ + __gmp_expr & fun(__gmp_ulli); \ __gmp_expr & fun(float);\ __gmp_expr & fun(double); \ /* __gmp_expr & fun(long double); */ @@ -1520,6 +1563,8 @@ __gmp_expr(unsigned short int s) { init_ui(s); } \ __gmp_expr(signed long int l) { init_si(l); } \ __gmp_expr(unsigned long int l) { init_ui(l); } \ + __gmp_expr(__gmp_slli l) { init_sll(l); } \ + __gmp_expr(__gmp_ulli l) { init_ull(l); } \ __gmp_expr(float f) { init_d(f); } \ __gmp_expr(double d) { init_d(d); } @@ -1532,6 +1577,8 @@ __gmp_expr & operator=(unsigned short int s) { assign_ui(s); return *this; } \ __gmp_expr & operator=(signed long int l) { assign_si(l); return *this; } \ __gmp_expr & operator=(unsigned long int l) { assign_ui(l); return *this; } \ + __gmp_expr & operator=(__gmp_slli l) { assign_sll(l); return *this; } \ + __gmp_expr & operator=(__gmp_ulli l) { assign_ull(l); return *this; } \ __gmp_expr & operator=(float f) { assign_d(f); return *this; } \ __gmp_expr & operator=(double d) { assign_d(d); return *this; } @@ -1544,22 +1591,22 @@ static inline __gmp_expr >\ fun(type expr); -#define __GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type) \ -__GMPNN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, signed long) -#define __GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type) \ -__GMPNN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, unsigned long) +#define __GMPNI_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type) \
pointers vs arrays
Hello, the latest version of gcc has a new (questionable) warning that complains if a function is declared as taking a mpz_t parameter and redeclared as taking mpz_ptr, or the reverse. We might as well be consistent and use pointers everywhere, as in the attached patch. Does someone disagree? -- Marc Glissediff -r 632506b00743 gmp-h.in --- a/gmp-h.in Sat May 08 19:34:05 2021 +0200 +++ b/gmp-h.in Wed May 12 15:07:25 2021 +0200 @@ -227,6 +227,8 @@ typedef __mpf_struct *mpf_ptr; typedef const __mpq_struct *mpq_srcptr; typedef __mpq_struct *mpq_ptr; +typedef __gmp_randstate_struct *gmp_randstate_ptr; +typedef const __gmp_randstate_struct *gmp_randstate_srcptr; #if __GMP_LIBGMP_DLL @@ -498,37 +500,37 @@ /* obsolete */ #define gmp_randinit __gmp_randinit -__GMP_DECLSPEC void gmp_randinit (gmp_randstate_t, gmp_randalg_t, ...); +__GMP_DECLSPEC void gmp_randinit (gmp_randstate_ptr, gmp_randalg_t, ...); #define gmp_randinit_default __gmp_randinit_default -__GMP_DECLSPEC void gmp_randinit_default (gmp_randstate_t); +__GMP_DECLSPEC void gmp_randinit_default (gmp_randstate_ptr); #define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp -__GMP_DECLSPEC void gmp_randinit_lc_2exp (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t); +__GMP_DECLSPEC void gmp_randinit_lc_2exp (gmp_randstate_ptr, mpz_srcptr, unsigned long int, mp_bitcnt_t); #define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size -__GMP_DECLSPEC int gmp_randinit_lc_2exp_size (gmp_randstate_t, mp_bitcnt_t); +__GMP_DECLSPEC int gmp_randinit_lc_2exp_size (gmp_randstate_ptr, mp_bitcnt_t); #define gmp_randinit_mt __gmp_randinit_mt -__GMP_DECLSPEC void gmp_randinit_mt (gmp_randstate_t); +__GMP_DECLSPEC void gmp_randinit_mt (gmp_randstate_ptr); #define gmp_randinit_set __gmp_randinit_set -__GMP_DECLSPEC void gmp_randinit_set (gmp_randstate_t, const __gmp_randstate_struct *); +__GMP_DECLSPEC void gmp_randinit_set (gmp_randstate_ptr, gmp_randstate_srcptr); #define gmp_randseed __gmp_randseed -__GMP_DECLSPEC void gmp_randseed (gmp_randstate_t, mpz_srcptr); +__GMP_DECLSPEC void gmp_randseed (gmp_randstate_ptr, mpz_srcptr); #define gmp_randseed_ui __gmp_randseed_ui -__GMP_DECLSPEC void gmp_randseed_ui (gmp_randstate_t, unsigned long int); +__GMP_DECLSPEC void gmp_randseed_ui (gmp_randstate_ptr, unsigned long int); #define gmp_randclear __gmp_randclear -__GMP_DECLSPEC void gmp_randclear (gmp_randstate_t); +__GMP_DECLSPEC void gmp_randclear (gmp_randstate_ptr); #define gmp_urandomb_ui __gmp_urandomb_ui -__GMP_DECLSPEC unsigned long gmp_urandomb_ui (gmp_randstate_t, unsigned long); +__GMP_DECLSPEC unsigned long gmp_urandomb_ui (gmp_randstate_ptr, unsigned long); #define gmp_urandomm_ui __gmp_urandomm_ui -__GMP_DECLSPEC unsigned long gmp_urandomm_ui (gmp_randstate_t, unsigned long); +__GMP_DECLSPEC unsigned long gmp_urandomm_ui (gmp_randstate_ptr, unsigned long); / Formatted output routines. / @@ -1008,7 +1010,7 @@ __GMP_DECLSPEC void mpz_rootrem (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int); #define mpz_rrandomb __gmpz_rrandomb -__GMP_DECLSPEC void mpz_rrandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t); +__GMP_DECLSPEC void mpz_rrandomb (mpz_ptr, gmp_randstate_ptr, mp_bitcnt_t); #define mpz_scan0 __gmpz_scan0 __GMP_DECLSPEC mp_bitcnt_t mpz_scan0 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE; @@ -1108,10 +1110,10 @@ __GMP_DECLSPEC void mpz_ui_pow_ui (mpz_ptr, unsigned long int, unsigned long int); #define mpz_urandomb __gmpz_urandomb -__GMP_DECLSPEC void mpz_urandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t); +__GMP_DECLSPEC void mpz_urandomb (mpz_ptr, gmp_randstate_ptr, mp_bitcnt_t); #define mpz_urandomm __gmpz_urandomm -__GMP_DECLSPEC void mpz_urandomm (mpz_ptr, gmp_randstate_t, mpz_srcptr); +__GMP_DECLSPEC void mpz_urandomm (mpz_ptr, gmp_randstate_ptr, mpz_srcptr); #define mpz_xor __gmpz_xor #define mpz_eor __gmpz_xor @@ -1457,7 +1459,7 @@ __GMP_DECLSPEC void mpf_ui_sub (mpf_ptr, unsigned long int, mpf_srcptr); #define mpf_urandomb __gmpf_urandomb -__GMP_DECLSPEC void mpf_urandomb (mpf_t, gmp_randstate_t, mp_bitcnt_t); +__GMP_DECLSPEC void mpf_urandomb (mpf_ptr, gmp_randstate_ptr, mp_bitcnt_t); / Low level positive-integer (i.e. N) routines. / diff -r 632506b00743 gmp-impl.h --- a/gmp-impl.h Sat May 08 19:34:05 2021 +0200 +++ b/gmp-impl.h Wed May 12 15:07:25 2021 +0200 @@ -1287,14 +1287,11 @@ return itch; } -typedef __gmp_randstate_struct *gmp_randstate_ptr; -typedef const __gmp_randstate_struct *gmp_randstate_srcptr; - /* Pseudo-random number generator function pointers structure. */ typedef struct { - void (*randseed_fn) (gmp_randstate_t, mpz_srcptr); - void (*randget_fn) (gmp_randstate_t, mp_ptr, unsigned long int); - void (*randclear_fn) (gmp_randstate_t); + void (*randseed_fn) (gmp_randstate_ptr, mpz_srcptr); + void (*randget_fn) (gmp_randstate_ptr, mp_ptr, unsigned long int); + void
Re: strange install directory
On Sat, 27 Feb 2021, Paul Zimmermann wrote: thank you all for your answers. Maybe the solution would be to check for $prefix/lib64 (and $prefix/lib32) if we don't find libgmp in $prefix/lib. That would help for this case. Of course, it might end up in $prefix/libx32 (X32 ABI on x86_64), $prefix/lib64le (some 64-bit little-endian ABI), $prefix/lib/$triplet (debian and derived distributions), etc... $prefix/*lib*/ + $prefix/lib/*/ roughly seems to cover it for now (I may be missing more). Or you could consider that people in this situation should use --with-gmp-lib and avoid guessing. I think it could be interesting if you asked on the autoconf list what they think. (I just realized that we can bypass the lib->lib64 renaming by specifying libdir with an extra '/' in the name, say at the beginning or the end, although that doesn't solve your problem) With recent GMP, you can also get some information with `pkg-config --libs gmp` (or other options than --libs), but that requires that the .pc file be in PKG_CONFIG_PATH, which just shifts the issue. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: strange install directory
On Fri, 26 Feb 2021, Niels Möller wrote: Paul Zimmermann writes: on the gcc118 machine from the gcc compile farm, with gmp-6.2.1, make install puts the libgmp.{a,so} files in $PREFIX/lib64 instead of $PREFIX/lib. Is there any reason for that? I don't know about GMP (and this is the first time I hear about automake's genered install target using a different default than libdir=${exec_prefix}/lib). Maybe a recent change in autoconf, automake, (or possibly libtool)? But I've been doing somethignsimilar in Nettle for years, and the problem case I want to avoid is this: 1. Assume we have a libfoo.so installed in /usr/local/lib, and that this is a the directory for 32-bit libraries. 2. User now builds and installs a new version of libfoo.so, for 64-bit abi, with default prefix. Say, "./configure CC='gcc -m64' && make && make check && make install". If make install installs in /usr/local/lib, it will overwrite a working .so file with a new one completely breaking 32-bit programs on the system that depend on that 32-bit library. To avoid this kind of breakage one can apply some heuristics to tweak the default location, depending on the api built for, OS flavor, current structure under /usr/lib*, etc. Does it work to override it by explicitly passing --libdir=$PREFIX/lib? We have CONFIG_SITE=/usr/share/site/aarch64-unknown-linux-gnu by default in our environment on this machine, and this file does # If user did not specify libdir, guess the correct target: # Use lib64 for 64 bit bi-arch targets, keep the default for the rest. if test "$libdir" = '${exec_prefix}/lib' ; then [...] so it looks like you can override it with anything but what you want (the file is sourced by configure after it has set libdir). Anyway, I think Paul's goal is more once GMP has been installed in lib64, how can MPFR, knowing only the prefix, guess the right libdir? Except for a hack of creating a dummy project, calling configure with that prefix, and checking what libdir is used, I don't see a great way to do that. Trying to use CONFIG_SITE directly would be messy. An alternative would be to guess that if there is only one subdirectory lib* in prefix, that might be it, or try each lib* until one works, hoping that the name never gets weirder. You could also complain to SUSE... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: strange install directory
On Fri, 26 Feb 2021, Paul Zimmermann wrote: on the gcc118 machine from the gcc compile farm, with gmp-6.2.1, make install puts the libgmp.{a,so} files in $PREFIX/lib64 instead of $PREFIX/lib. Is there any reason for that? /usr/share/site/aarch64-unknown-linux-gnu does it? -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Funny clang behaviour
On Mon, 17 Feb 2020, Marco Bodrato wrote: Ciao, Il 2020-02-17 20:34 Marc Glisse ha scritto: easiest would be to rename the test from bit to something less common. Do you mean that we should $ hg rename tests/mpz/bit.c tests/mpz/t-bit.c $ sed -i orig 's/ bit / t-bit /' tests/mpz/Makefile.am ? Yes, I think that's the easiest way to avoid this issue. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Funny clang behaviour
On Mon, 17 Feb 2020, Torbjörn Granlund wrote: Marc Glisse writes: It looks like there is now a standard header called . We also have a test bit.c that compiles to bit. And we have a -I flag pointing to the location of this second bit file. Now, when clang sees #include inside the libc++ headers, it finds this binary file instead of the standard header. I think we should fix that on the GMP side. The easiest would be to rename the test from bit to something less common. What you say makes sense, but clang's behaviour does not. I added broad testing using C++ compilers for GMP now; there are 56 variants. Only clang 8 on FreeBSD fails. All gcc versions (at least 6 to 9) and older and newer clang worked fine. It is possible that it is timing-dependent; if a parallel compile generates ./bit late enough for other compiles to not see it, things will work. But I don't see why all 4 clang8/fbsd compiles fail and all the other 52 compiles work. I managed to reproduce on linux (debian) with CC='clang++-10 -stdlib=libc++'. For the failure to occur, you need to compile GMP with a C++ compiler (the error is in tests/mpz/ which would normally be C), the standard library has to be recent enough to have the header , and it needs to include from some other standard header. Sure, the failure may appear or disappear depending on various factors, but in any case it seems like a good idea to avoid having a file with the same name as a standard header in a directory with a -I pointing to it. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Funny clang behaviour
On Mon, 17 Feb 2020, Torbjörn Granlund wrote: We upgraded the FreeBSD GMP test systems from 11.2 to 11.3 and 12.0 to 12.1 and with those upgrades came clang 8.0. We got some really novel failures when using clang++ for compiling GMP. It spews out binary error messages which appears to be dumps of its own RAM! What clang actually thinks is wromg is anyone's guess. It looks like there is now a standard header called . We also have a test bit.c that compiles to bit. And we have a -I flag pointing to the location of this second bit file. Now, when clang sees #include inside the libc++ headers, it finds this binary file instead of the standard header. I think we should fix that on the GMP side. The easiest would be to rename the test from bit to something less common. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Overflow in mpz_cmp
On Tue, 11 Feb 2020, Niels Möller wrote: Marco Bodrato writes: Ciao, Il 2020-02-10 18:25 Guillaume Melquiond ha scritto: When the operand sizes do not match, the mpz_cmp function function just returns the difference of the signed sizes. Unfortunately, this difference might not fit inside the "int" return type, when the numbers are of opposite sign. In mini-gmp we defined a macro: #define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b))) We may use the same idea here too. I mean something like the following: diff -r f5601c2a8b11 mpz/cmp.c --- a/mpz/cmp.c Sun Feb 09 16:16:19 2020 +0100 +++ b/mpz/cmp.c Tue Feb 11 14:20:39 2020 +0100 @@ -35,15 +35,15 @@ int mpz_cmp (mpz_srcptr u, mpz_srcptr v) __GMP_NOTHROW { - mp_size_t usize, vsize, dsize, asize; + mp_size_t usize, vsize, asize; mp_srcptr up, vp; intcmp; usize = SIZ(u); vsize = SIZ(v); - dsize = usize - vsize; - if (dsize != 0) -return dsize; + cmp = (usize > vsize) - (usize < vsize); + if (cmp != 0) +return cmp; I would be tempted to keep it simple, if (usize != vsize) return (usize > vsize) ? 1 : -1; It's not clear to me if this is worth micro optimizing, and ensure we get only a single branch. On x86_64, both gcc and clang optimize (usize > vsize) ? 1 : -1 to 2 * (usize > vsize) - 1 (as a single LEA for gcc, 2 ADD for llvm). So the generated code may be just as good with the simple code. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: ASSERT and __builtin_unreachable
On Tue, 3 Sep 2019, Niels Möller wrote: I think we discussed this earlier, but I don't recall the conclusion, if any. Would it make sense to use ASSERT to guide the compiler, and define it like #define ASSERT(expr) do { if (!(expr)) __builtin_unreachable(); } while (0) (unless building with --enable-assert)? The idea is to tell the compiler to assume that the asserted expression is true, and not care what the behavior of the generated code is in case it nevertheless happens to be false at run time. As far as I understand, this should aid optimization in some (rare?) cases. Drawbacks are small: we'd need a configure test for __builtin_unreachable, and there are a few places with code like ASSERT_CODE (char *bp_orig = bp - bytes); ... ASSERT (bp > bp_orig); that needs the current definition of ASSERT and have to be updated in one way or the other. That seems fine for small assertions, say ASSERT(x>0), but it seems bad for more expensive ones, because it becomes an ASSERT_ALWAYS. In ASSERT (refmpn_mul_1c (prod, rp, size, divisor, carry) == carry_orig) we may end up calling refmpn_mul_1c needlessly, same in ASSERT (mpn_mod_1 (up, n, d) == 0). So we may need to introduce ASSERT_EXPENSIVE at the same time. There are other drawbacks, it may hinder inlining because the tests make the functions temporarily bigger than they should be (though __builtin_constant_p is much worse in that respect), and it may limit other optimizations, but we can probably ignore that unless we notice a regression. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Patch for pkg-config file
On Thu, 15 Aug 2019, Niels Möller wrote: Hugh McMaster writes: Generate and install a pkg-config file for the gmp library This patch looks good to me. I take it you have tested that make install does install a working gmp.pc in the right place? I'm not very familiar with what automake does. Generate and install a pkg-config file for the gmpxx library [...] diff -r 93c8fcc2cab4 -r 4b0e794dd777 gmpxx.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 + +++ b/gmpxx.pc.in Thu Aug 08 23:48:03 2019 +1000 @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ +libdir=@libdir@ + +Name: @PACKAGE_NAME@ C++ +Description: GNU Multiple Precision Arithmetic Library (C++ bindings) +URL: https://gmplib.org +Version: @PACKAGE_VERSION@ +Requires: gmp +Cflags: -I${includedir} +Libs: -L${libdir} -lgmpxx For gmpxx, perhaps -lgmp should be added as well, either Libs: -L${libdir} -lgmpxx -lgmp or Libs: -L${libdir} -lgmpxx Libs.private: -lgmp ? I assume that "Requires: gmp" already handles that. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Patch for pkg-config file
On Mon, 5 Aug 2019, Niels Möller wrote: Hugh McMaster writes: --- /dev/null Thu Jan 01 00:00:00 1970 + +++ b/gmp.pc.in Sun Aug 04 22:35:15 2019 +1000 Should there also be a gmpxx.pc ? @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ +libdir=@libdir@ + +Name: @PACKAGE_NAME@ +Description: GNU Multiple Precision Arithmetic Library +URL: https://gmplib.org +Version: @PACKAGE_VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lgmp +Libs.private: @LIBM@ @LIBM@ shouldn't be needed. I don't know why configure checks for it, from comments, possibly libtool-related. IIRC -lm is used in the build, the tuning, the tests, the demos, but not in the library itself. (the use in tests/cxx looks bad, it does -lm instead of using the result of autoconf) -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmpxx - mini-gmp C++ interface
On Fri, 12 Jul 2019, Vladimir S. FONOV wrote: I needed a mini version of gmp, to work with C++ inteface, so I created mini-gmpxx.h (gmpxx.h for mini-gmp) , mostly for the purpose of compiling cork on macOS without libgmp present, take a look in https://github.com/vfonov/cork/tree/master/contrib/gmp-6.1.2/mini-gmp , it Thanks for sharing. is basically original gmpxx.h with commented out pieces of code that wouldn't work without mpq and mpf interfaces. Note that we have a mini-mpq now. I also had to add couple of defines from omp.h to mini-omp.h , so there are small changes too. Maybe it would be of interest to somebody? I guess if it used some #ifdef instead of commenting out the code, so the same file could be user for gmp and mini-gmp, it could be interesting (not particularly to me since I never used mini-gmp, but to others). Maybe gmpxx.h could check if __MINI_GMP_H__ is defined and in that case not include gmp.h and not use anything mpf-related. __MINI_MPQ_H__ could be used to conditionally enable mpq if we don't want to enable it by default. (I am not saying any of the above is a good idea, just the first things that come to mind) Or we could have a much more simplistic mini C++ wrapper without expression templates, if we are going to maintain 2 versions, although I am not fond of the idea of maintaining 2 versions. I don't see a corresponding mini-gmpxx.cc file. That could cause problems for numeric_limits at least. You kept some operator<< that seems unlikely to compile. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Documentation patch for mpz_millerrabin
On Sun, 16 Jun 2019, Niels Möller wrote: Marc Glisse writes: https://github.com/sethtroisi/libgmp/pull/5.diff (or .patch for a different format). AFAIK you have to modify the URL by hand... But that gives me a sequence of patches, not a single patch ("squashed", in git terms) representing all the changes. I thought .patch gave a sequence of patches while .diff gave a single patch. The link I gave does look like a single patch to me... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Documentation patch for mpz_millerrabin
On Sun, 16 Jun 2019, Niels Möller wrote: Seth Troisi writes: I believe this and the jacobi documentation are more accurate than what's currently committed. Jacobi patch https://github.com/sethtroisi/libgmp/pull/5 How do I get a complete patch file from github? I'm looking at the htmlized patch at https://github.com/sethtroisi/libgmp/pull/5/files but I have difficulty spotting a "download raw patch" link. https://github.com/sethtroisi/libgmp/pull/5.diff (or .patch for a different format). AFAIK you have to modify the URL by hand... (or you can just use git with the command line instead of going though the web interface) -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: GMP and C++11 move constructors
On Wed, 23 May 2018, Marco Bodrato wrote: From gmp-discuss: Il Lun, 21 Maggio 2018 12:15 pm, Marc Glisse ha scritto: If m is a moved-from object, it is fine to assign a new value to it with m = whatever. That's even what std::swap does. It should also be fine to read from it, although you can't rely on any specific value so that's not very useful. Should the non specific value be somehow valid? Preferably, though that's not really important, many types have a state where you can only destruct or assign a new value. With lazy allocation, we should define NaN as an admissible value for mpq, and use it whenever we init a variable that will immediately be overwritten. Ah, as an implementation detail, not a public interface, this avoids a lot of trouble. I did this, internally in mini-mpq: https://gmplib.org/repo/gmp/rev/8e0a2e94ae5a The idea might be useful also for some mpq constructor from double, from string... if not for move. Ah, I see where you are going now. That's an interesting idea. Wile we are looking into this, is there a motivation why we have the assignment "operator=(mpz_class &)" for mpq_class, but not a constructor from mpz_class&& ? Hmm, I forgot to add one? ;-) -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: _ptr and _srcptr types
On Mon, 14 May 2018, Torbjörn Granlund wrote: I've personally always used the mpz_ptr and mpz_srcptr in functions that take mpz arguments, taking the liberty to use this undocumented type. I suppose we could declare these. I'd like to hear from the rest of the GMP "core team". I am in favor of documenting them. I don't think we are losing much by exposing those types to the user, it seems hard to modify the implementation of mpz_t in a way that would break those types without breaking a lot of other things. The main question in my mind is how to document them so users don't get too confused about what they should use and when. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpq_get_d [Was: mini-gmp and mpq]
On Tue, 15 May 2018, Marco Bodrato wrote: Ciao Marc, Il Lun, 19 Febbraio 2018 5:24 pm, Marc Glisse ha scritto: On Mon, 19 Feb 2018, Marco Bodrato wrote: mpq_get_d currently gives a double, but rounded towards zero... Except when it uses the broken generic code :-( If you want, you can check the changed generic code, https://gmplib.org/repo/gmp/rev/89e43a9eab63 to test if it is less broken... That looks sensible. I didn't test, I assume it is still broken for denormals and infinity (it may be doable using DBL_MAX_EXP, DBL_MIN_EXP, DBL_HAS_SUBNORM, etc), but it is already a good improvement if it works for normal numbers. (I never use GMP's get_d functions, they don't quite provide what I need) Thanks, -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: documentation on internals not up to date
On Fri, 27 Apr 2018, Niels Möller wrote: Marc Glisse <marc.gli...@inria.fr> writes: There would be a significant advantage to mpq if we could have a non-allocated 1 for the denominator. But indeed, with the current code where only some mpz functions would work, it seems safer to document that none work. We could do that internally, even if we don't advertise it for other gmp users. We document that users can use the denominator of a mpq_t as a regular mpz_t and apply pretty much any mpz_t operation to it. So it seems hard to handle just that case internally. Then mpq_init wouldn't do any allocation, right? Right. We could have a single mpq object representing 0/1 with _mp_alloc == 0 for both parts, and initialize with struct assignment or memcpy. We would just ensure that mpz realloc keeps supporting thuis case. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: documentation on internals not up to date
On Fri, 27 Apr 2018, Niels Möller wrote: _mp_alloc == 0 and _mp_size != 0 is a read-only value, _mp_d is neither written, reallocated or freed by mpz functions. It must not be passed as destination argument to any mpz function. Should also link to docs for mpz_roinit_n and MPZ_ROINIT_N. Currently, if an mpz_t is initialised with _roinit, it can be passed to _clear or _clears with no errors. Should we document this? I think we should. Moreover, the various mpz_set_ functions should work smoothly too. I'd prefer that we not document any way to pass _roinit values to any mpz functions taking a non-const mpz_t, even if it happens to work in the current implementation. Maybe as a later extension, *if* we find some use cases where it provides a significant advantage. There would be a significant advantage to mpq if we could have a non-allocated 1 for the denominator. But indeed, with the current code where only some mpz functions would work, it seems safer to document that none work. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: C99 and GMP
On Fri, 27 Apr 2018, Marc Glisse wrote: On Fri, 27 Apr 2018, paul zimmermann wrote: quite interesting. Why is gmp/mpn not tested in the head coverage? It is tested. It appears as /var/tmp/lcov/gmp/mpn because it is a set of symlinks created at build time. sorry I missed that. I see some of the files are not tested at all (add_err3_n.c for example), and some have a low coverage (div_qr_1.c for example). Are there any plans to improve that? Even for the generic files, the coverage varies per target, maybe add_err3_n is better tested on ARM or something (not really answering your question). Hmm, no, mpn_add_err3_n really seems completely unused. There is a refmpn implementation ready for comparisons... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: C99 and GMP
On Fri, 27 Apr 2018, paul zimmermann wrote: quite interesting. Why is gmp/mpn not tested in the head coverage? It is tested. It appears as /var/tmp/lcov/gmp/mpn because it is a set of symlinks created at build time. sorry I missed that. I see some of the files are not tested at all (add_err3_n.c for example), and some have a low coverage (div_qr_1.c for example). Are there any plans to improve that? Even for the generic files, the coverage varies per target, maybe add_err3_n is better tested on ARM or something (not really answering your question). -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: C99 and GMP
On Fri, 27 Apr 2018, paul zimmermann wrote: https://gmplib.org/devel/lcov/shell/gmp/mini-gmp/mini-mpq.c.gcov.html quite interesting. Why is gmp/mpn not tested in the head coverage? It is tested. It appears as /var/tmp/lcov/gmp/mpn because it is a set of symlinks created at build time. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: C99 and GMP
On Wed, 4 Apr 2018, Torbjörn Granlund wrote: I'd suggest to make a 6.2 release of pretty much what we have today. Marco had a mini-mpq that seemed to be in a working state. I guess it is missing tests, so too much work for 6.2. Is that a correct interpretation of the status? (I am trying to think of things lying around that would be easy / safe to push) -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpn_mul is embarrassingly slow
On Fri, 20 Apr 2018, Marc Glisse wrote: On Fri, 20 Apr 2018, Marc Glisse wrote: On Fri, 20 Apr 2018, Marc Glisse wrote: On Fri, 20 Apr 2018, Vincent Lefevre wrote: On 2018-04-20 04:14:15 +0200, Fredrik Johansson wrote: For operands with 1-4 limbs, that is; on my machine, mpn_mul takes up to twice as long as mpn_mul_basecase, and inline assembly for 1x1, 2x1 or 2x2 multiplication is even faster. The problem is that there are three function calls (mpn_mul -> mpn_mul_n -> mpn_mul_basecase) + branches between the user code and GMP's lightning fast assembly code. I was reminded of this old issue when seeing this new paper on arXiv: https://arxiv.org/abs/1804.07236. Here, the author benchmarked a C++ implementation of bignum arithmetic against mpn_mul for small operand sizes and came to the conclusion that the former approach performs better than hand-optimized assembly (one wishes that compilers really were that clever about bignum code by now!). Some advanced GMP users (including myself) know about the issue and simply avoid mpn_mul for performance-critical code with short operands. The most convenient solution is to call mpn_mul_basecase directly instead of mpn_mul. Unfortunately, mpn_mul_basecase is not public, so this is a bit iffy to rely on. One feature request would be to simply make mpn_mul_basecase / mpn_sqr_basecase public. [...] I'm wondering... With the current GMP code, does LTO help to avoid such issues? mpn_mul and mpn_mul_n are too large to be completely inlined (unless that's the only place where they are used, which could happen in a microtest, but doesn't seem realistic in an application). What could happen is partial inlining of the first test of each. Maybe using LTO+PGO (profile-guided optimization)? Still, I am not particularly optimistic. I just tried (LTO+PGO) on a trivial testcase, and gcc didn't manage to do anything clever with it. Doing it by hand to see how much potential gain there is, the timings are: mpn_mul: .56 mpn_mul_n: .36 mpn_mul_basecase: .16 Let me mention here that LLVM does manage to take advantage of LTO to get the running time of mpn_mul down to .16 for this trivial example (only call mpn_mul, only on 1 limb numbers). Avec la propagation des constantes, GCC ne peut-il pas en déduire que tout un tas de choses est du code mort, en tout cas passer directement à mpn_mul_basecase (p, a, n, b, n) puisque le test BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD) est vrai? I took a closer look at what gcc is doing. Propagating constants (the sizes) from one function to another (mpn_mul) means either inlining (unlikely, the function is very large and has several callers including itself) or cloning, i.e. creating a similar function that takes fewer arguments and assumes that the few missing are those constants. I can see in the logs: Evaluating opportunities for __gmpn_mul/68. - considering value for param #0 mp_limb_t * (caller_count: 1) good_cloning_opportunity_p (time: 2, size: 698, count_sum: 1, scc, single_call) -> evaluation: 0, threshold: 500 good_cloning_opportunity_p (time: 264, size: 59564, count_sum: 1, scc, single_call) -> evaluation: 1, threshold: 500 - considering value for param #1 const mp_limb_t * (caller_count: 1) good_cloning_opportunity_p (time: 2, size: 698, count_sum: 1, scc, single_call) -> evaluation: 0, threshold: 500 good_cloning_opportunity_p (time: 50, size: 12795, count_sum: 1, scc, single_call) -> evaluation: 0, threshold: 500 - considering value 1 for param #2 mp_size_t (caller_count: 1) good_cloning_opportunity_p (time: 75, size: 689, count_sum: 1, scc, single_call) -> evaluation: 54, threshold: 500 good_cloning_opportunity_p (time: 721, size: 4091, count_sum: 1, scc, single_call) -> evaluation: 89, threshold: 500 - considering value for param #3 const mp_limb_t * (caller_count: 3) good_cloning_opportunity_p (time: 1, size: 699, count_sum: 1, scc, single_call) -> evaluation: 0, threshold: 500 good_cloning_opportunity_p (time: 49, size: 12796, count_sum: 1, scc, single_call) -> evaluation: 0, threshold: 500 - considering value 1 for param #4 mp_size_t (caller_count: 3) good_cloning_opportunity_p (time: 72, size: 123, count_sum: 1, scc, single_call) -> evaluation: 298, threshold: 500 good_cloning_opportunity_p (time: 72, size: 123, count_sum: 1, scc, single_call) -> evaluation: 298, threshold: 500 So gcc did consider this optimization, but its heuristics mistakenly convinced it it wasn't worth the trouble. On simpler examples not using GMP, I can get gcc to do the transformation, it would be quite some work to analyse why gcc is not more enthusiastic here. I tried again with --param ipa-cp-eval-threshold=50 to convince gcc to clone... and the running time went down to .29. It did clone mpn_mul and mpn_mul_n, and the clo
Re: mpn_mul is embarrassingly slow
On Fri, 20 Apr 2018, Marco Bodrato wrote: Il Ven, 20 Aprile 2018 12:39 pm, Marc Glisse ha scritto: I just tried (LTO+PGO) on a trivial testcase, and gcc didn't manage to do anything clever with it. Doing it by hand to see how much potential gain there is, the timings are: mpn_mul: .56 mpn_mul_n: .36 mpn_mul_basecase: .16 Did you try also the documented function mpn_sec_mul? .19 If you know in advance that the size of your operand are bounded by some given sizes, you can preallocate the required scratch space... I'll admit that since I don't care about the security aspects, it didn't even occur to me to look at those functions for performance. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpn_mul is embarrassingly slow
On Fri, 20 Apr 2018, Marc Glisse wrote: On Fri, 20 Apr 2018, Marc Glisse wrote: On Fri, 20 Apr 2018, Vincent Lefevre wrote: On 2018-04-20 04:14:15 +0200, Fredrik Johansson wrote: For operands with 1-4 limbs, that is; on my machine, mpn_mul takes up to twice as long as mpn_mul_basecase, and inline assembly for 1x1, 2x1 or 2x2 multiplication is even faster. The problem is that there are three function calls (mpn_mul -> mpn_mul_n -> mpn_mul_basecase) + branches between the user code and GMP's lightning fast assembly code. I was reminded of this old issue when seeing this new paper on arXiv: https://arxiv.org/abs/1804.07236. Here, the author benchmarked a C++ implementation of bignum arithmetic against mpn_mul for small operand sizes and came to the conclusion that the former approach performs better than hand-optimized assembly (one wishes that compilers really were that clever about bignum code by now!). Some advanced GMP users (including myself) know about the issue and simply avoid mpn_mul for performance-critical code with short operands. The most convenient solution is to call mpn_mul_basecase directly instead of mpn_mul. Unfortunately, mpn_mul_basecase is not public, so this is a bit iffy to rely on. One feature request would be to simply make mpn_mul_basecase / mpn_sqr_basecase public. [...] I'm wondering... With the current GMP code, does LTO help to avoid such issues? mpn_mul and mpn_mul_n are too large to be completely inlined (unless that's the only place where they are used, which could happen in a microtest, but doesn't seem realistic in an application). What could happen is partial inlining of the first test of each. Maybe using LTO+PGO (profile-guided optimization)? Still, I am not particularly optimistic. I just tried (LTO+PGO) on a trivial testcase, and gcc didn't manage to do anything clever with it. Doing it by hand to see how much potential gain there is, the timings are: mpn_mul: .56 mpn_mul_n: .36 mpn_mul_basecase: .16 Let me mention here that LLVM does manage to take advantage of LTO to get the running time of mpn_mul down to .16 for this trivial example (only call mpn_mul, only on 1 limb numbers). -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpn_mul is embarrassingly slow
On Fri, 20 Apr 2018, Marc Glisse wrote: On Fri, 20 Apr 2018, Vincent Lefevre wrote: On 2018-04-20 04:14:15 +0200, Fredrik Johansson wrote: For operands with 1-4 limbs, that is; on my machine, mpn_mul takes up to twice as long as mpn_mul_basecase, and inline assembly for 1x1, 2x1 or 2x2 multiplication is even faster. The problem is that there are three function calls (mpn_mul -> mpn_mul_n -> mpn_mul_basecase) + branches between the user code and GMP's lightning fast assembly code. I was reminded of this old issue when seeing this new paper on arXiv: https://arxiv.org/abs/1804.07236. Here, the author benchmarked a C++ implementation of bignum arithmetic against mpn_mul for small operand sizes and came to the conclusion that the former approach performs better than hand-optimized assembly (one wishes that compilers really were that clever about bignum code by now!). Some advanced GMP users (including myself) know about the issue and simply avoid mpn_mul for performance-critical code with short operands. The most convenient solution is to call mpn_mul_basecase directly instead of mpn_mul. Unfortunately, mpn_mul_basecase is not public, so this is a bit iffy to rely on. One feature request would be to simply make mpn_mul_basecase / mpn_sqr_basecase public. [...] I'm wondering... With the current GMP code, does LTO help to avoid such issues? mpn_mul and mpn_mul_n are too large to be completely inlined (unless that's the only place where they are used, which could happen in a microtest, but doesn't seem realistic in an application). What could happen is partial inlining of the first test of each. Maybe using LTO+PGO (profile-guided optimization)? Still, I am not particularly optimistic. I just tried (LTO+PGO) on a trivial testcase, and gcc didn't manage to do anything clever with it. Doing it by hand to see how much potential gain there is, the timings are: mpn_mul: .56 mpn_mul_n: .36 mpn_mul_basecase: .16 -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpn_mul is embarrassingly slow
On Fri, 20 Apr 2018, Vincent Lefevre wrote: On 2018-04-20 04:14:15 +0200, Fredrik Johansson wrote: For operands with 1-4 limbs, that is; on my machine, mpn_mul takes up to twice as long as mpn_mul_basecase, and inline assembly for 1x1, 2x1 or 2x2 multiplication is even faster. The problem is that there are three function calls (mpn_mul -> mpn_mul_n -> mpn_mul_basecase) + branches between the user code and GMP's lightning fast assembly code. I was reminded of this old issue when seeing this new paper on arXiv: https://arxiv.org/abs/1804.07236. Here, the author benchmarked a C++ implementation of bignum arithmetic against mpn_mul for small operand sizes and came to the conclusion that the former approach performs better than hand-optimized assembly (one wishes that compilers really were that clever about bignum code by now!). Some advanced GMP users (including myself) know about the issue and simply avoid mpn_mul for performance-critical code with short operands. The most convenient solution is to call mpn_mul_basecase directly instead of mpn_mul. Unfortunately, mpn_mul_basecase is not public, so this is a bit iffy to rely on. One feature request would be to simply make mpn_mul_basecase / mpn_sqr_basecase public. [...] I'm wondering... With the current GMP code, does LTO help to avoid such issues? mpn_mul and mpn_mul_n are too large to be completely inlined (unless that's the only place where they are used, which could happen in a microtest, but doesn't seem realistic in an application). What could happen is partial inlining of the first test of each. Maybe using LTO+PGO (profile-guided optimization)? Still, I am not particularly optimistic. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Lazy mpz allocation
On Fri, 20 Apr 2018, paul zimmermann wrote: Only 0 can have lazy allocation, and I think we document that it isn't legal to put 0 on the denominator. where is this documented? That was in a "I think" sentence. Now that I looked a bit more, I don't find it... Well, you can't call any mpq function that reads that mpq_t, but we don't say you can't write to that mpq_t. In mpfr_set_q we use the fact that the user can set q to 1/0 for example to represent +Inf. I didn't remember that MPFR did that, but I did remember that some people did that. I'll count it as a vote for Marco's patch. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Lazy mpz allocation
On Fri, 20 Apr 2018, Marco Bodrato wrote: Ciao, Il Gio, 19 Aprile 2018 4:37 pm, Marc Glisse ha scritto: I finally pushed it. It seemed unsafe to keep mpq unaware of lazy allocation, in case people start swapping the numerator of a rational with a lazy 0 integer or something like that. If we fear swaps, then ... what about swapping the deoniminator? Only 0 can have lazy allocation, and I think we document that it isn't legal to put 0 on the denominator. Should we support a code like: mpz_init (saved_denominator); mpz_swap (saved_denominator, mpq_denref(rational)); /* Code overwriting rational*/ ? Hmmm... I don't know. It does seem vaguely possible that someone would do: mpz_class den; mpq_class q = some_computation(); den = std::move(q.get_den()); // won't need this value of q anymore q = other_computation(); (the third line does a swap) But that seems unlikely and contrived. If testing for this case is costly (it is likely cheap enough that I shouldn't worry), I'd be sad to pay for it :-( I'd be less negative if we were reaping some benefit from those new tests, for instance allowing a lazy denominator of 1. But safety is a strong argument indeed. If yes, a larger patch is needed, I attach a proposal. If yes, then something like that looks right, thanks. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Lazy mpz allocation
On Mon, 11 Apr 2016, Marc Glisse wrote: On Mon, 9 Nov 2015, Marco Bodrato wrote: Moreover, the mpq layer and mini-gmp need to migrate to lazy allocation too... For mpq, the attached seems sufficient to pass make check. I finally pushed it. It seemed unsafe to keep mpq unaware of lazy allocation, in case people start swapping the numerator of a rational with a lazy 0 integer or something like that. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: How large are arbitrarily large integers? (Was Re: Bitfield subtlety)
On Thu, 29 Mar 2018, Richard Biener wrote: On Thu, 29 Mar 2018, Torbjörn Granlund wrote: Richard Biener <rguent...@suse.de> writes: You can also steal low-order bits from the pointer depending on alignment... and depending on the host also some high-order bits. I will resist those temptations. :-) (I have contemplates using the 2-3 low point bits for some other purposes, most likely to track used allocators. But I don't think that will happen.) You can also simply off-load the allocation size to the allocated area (like to *(size_t)(_mp_d - 8)). In fact you are already breaking the ABI in some sort by re-purposing fields given that the internals of __mpz_struct is exposed. Unfortunately, while that would be desirable, I have the feeling that it is not 100% portable. I would be surprised if that wouldn't work everywhere - any reason you have doubts? To clarify, allocation would work like void *ptr = malloc (... + sizeof (size_t)); ->_mp_d = (char *)ptr + sizeof (size_t); size_t *size = ptr; if you think the pointer arithmetic on _mp_d is problematic you can always go through uintptr_t ... IIRC that's roughly what MPFR does. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Bitfield subtlety
On Wed, 28 Mar 2018, Torbjörn Granlund wrote: I am playing with a GMP version which allows greater mpz numbers than what is currently handled. The idea is to combine the _mp_size and _mp_alloc fields such that _mp_size becomes 40 bits while _mp_alloc becomes a custom float. I ran into some problems with C and C++ when it comes to bit fields. In C++, a bit field whose base type is not explicitly signed or unsigned gets undefined signedness. It would be desirable to use stdint.h's int64_t, but while that is signed, it is not guaranteed to be explicitly so. ISTR that this has changed (maybe only recently for C++20 though). In C, at least old C, allows just (signed or unsigned ) int as base types. I.e., long is not allowed, and thus int64_t is also not allowed. Does anybody on this list know if C99 is more tolerant wrt base type? If so, will implicity signed basetypes result in signed bit fields (unlike C++)? C11 still seems to limit bit-fields quite strictly: "A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type." In C++, there is also the strange behavior that long bit-fields are not necessarily promoted to long, so g++ happily generates operations on a 51-bit integer type... (clang does promote IIRC) I see no nice solution to the C++ rule. I suppose that if we decide to go with bit fields here, we will simply not support problematic C++ compilers. Or we arm autoconf to probe for this too, and stay away from stdint.h. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp mpz_{get,set}_d not fully compatible with GMP
On Sat, 17 Mar 2018, Vincent Lefevre wrote: On 2018-03-16 22:22:39 +0100, Marc Glisse wrote: On Fri, 16 Mar 2018, Marco Bodrato wrote: float.h was defined by C99, right? I am pretty sure it was already in C89. Yes, but was DBL_MANT_DIG necessarily an integer constant expression (in case this is needed) at that time? Indeed it wasn't (only FLT_RADIX was), but I would be surprised if implementations made it non-constant, and we probably don't need to use it as a constant anyway. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp mpz_{get,set}_d not fully compatible with GMP
On Fri, 16 Mar 2018, Marco Bodrato wrote: float.h was defined by C99, right? I am pretty sure it was already in C89. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp mpz_{get,set}_d not fully compatible with GMP
On Tue, 13 Mar 2018, Niels Möller wrote: I'd still prefer the simpler way of reying on float.h constants, though +1 to that. For mini-gmp, maybe put all the functions using 'double' behind some macro or in a separate file so it is easy for a user to remove them, and document that they are only supported with a standard float.h header. Or just assume that float.h is always available nowadays. Or even assume that all double are 64-bit binary IEEE numbers... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp mpz_{get,set}_d not fully compatible with GMP
On Fri, 9 Mar 2018, Torbjörn Granlund wrote: For GMP, it's desirable to fix also the non IEEE-version. That would have some value, I suppose, although non-IEEE formats of course have become largely obsolete. This code is mostly used not for non-IEEE formats, but for cases where we fail to detect that it *is* IEEE. For instance when compiling to bitcode (gcc LTO, LLVM, webassembly, etc). Of course, better IEEE detection would help those more than fixing the fallback path. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp mpz_{get,set}_d not fully compatible with GMP
On Tue, 6 Mar 2018, Niels Möller wrote: Marc Glisse <marc.gli...@inria.fr> writes: On Tue, 6 Mar 2018, Marco Bodrato wrote: Which solutions do you suggest? I see 3 possible ways: - removing the non "fully compatible" functions; - adding them to the "with a few exceptions:" section; - correct the behaviour of the functions... As discussed for instance last October, the generic, non-IEEE version of mpn_get_d has a similar issue. Maybe they could both be fixed at the same time with the same code? For mini-gmp, it's highly desirable for the get_d function to be fully compatible with gmp at least for the common case of standard IEEE floats. I'm fine with documenting different behavior for obscure floating point variants. For GMP, it's desirable to fix also the non IEEE-version. Can we rely on FLT_RADIX and DBL_MANT_DIG (float.h, see http://pubs.opengroup.org/onlinepubs/009695399/basedefs/float.h.html), to get correct rounding at least as long as FLT_RADIX == 2 ? The code shouldn't be too hard to write using count_leading_zeros and DBL_MANT_DIG, but I have no idea how many platforms are missing DBL_MANT_DIG. I am not really interested in such platforms... If I recall earlier discussion correctly, we really need to know the size of the mantissa, from the compiler or a configure check (and the latter is not applicable to mini-gmp). It is also possible to determine it at runtime (comparing 2^n+{0,1,2} for instance should work whether we round up, down or to the nearest; tests/misc.c compares 2^n+1-2^n to 1, which also looks good), doing it once and storing the result somewhere. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp mpz_{get,set}_d not fully compatible with GMP
On Tue, 6 Mar 2018, Marco Bodrato wrote: Which solutions do you suggest? I see 3 possible ways: - removing the non "fully compatible" functions; - adding them to the "with a few exceptions:" section; - correct the behaviour of the functions... As discussed for instance last October, the generic, non-IEEE version of mpn_get_d has a similar issue. Maybe they could both be fixed at the same time with the same code? Obviously this assumes that someone can find time to do it... Otherwise, I guess that option 2 could do, until a volunteer appears. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp and mpq
On Wed, 28 Feb 2018, Marco Bodrato wrote: Something like that, yes. But it feels like this is duplicating functionality that should be elsewhere... Bah, I am probably too picky for so few lines, feel free to go ahead and commit your patch (I don't Pushed it. remember if any of the tests do q+1). I hope I added them with another patch: https://gmplib.org/repo/gmp/rev/7cae59f06a21 Yes, I think that works. In the meanwhile I also pushed some small shortcuts for __gmp_binary_equal applied to mpq and integers: https://gmplib.org/repo/gmp/rev/a22c11d52f05 Thanks, that's a good idea. If we wanted to, we could also specialize the test q == 0 (and q < 0), which is probably common enough, but that's independent, and a negligible gain. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp and mpq
On Tue, 27 Feb 2018, Marco Bodrato wrote: Il Mar, 27 Febbraio 2018 8:22 pm, Marc Glisse ha scritto: If I write q = 1 + 1 / q, gmpxx currently generates: mpq_inv(q, q); mpz_addmul_ui(num, den, 1); Not quite optimal yet :-( May the following help? Something like that, yes. But it feels like this is duplicating functionality that should be elsewhere... Bah, I am probably too picky for so few lines, feel free to go ahead and commit your patch (I don't remember if any of the tests do q+1). -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp and mpq
On Tue, 27 Feb 2018, Marco Bodrato wrote: The realway to speed-up that loop is to use the suggestion in gmpxx.h to compute a rational+1, both for mini-gmp and the full GMP library: struct __gmp_unary_increment { static void eval(mpz_ptr z) { mpz_add_ui(z, z, 1); } static void eval(mpq_ptr q) { mpz_add(mpq_numref(q), mpq_numref(q), mpq_denref(q)); } static void eval(mpf_ptr f) { mpf_add_ui(f, f, 1); } }; If I write q = 1 + 1 / q, gmpxx currently generates: mpq_inv(q, q); mpz_addmul_ui(num, den, 1); Not quite optimal yet :-( -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Why set zero in zero.c rather than use xor_n
On Mon, 5 Feb 2018, Vincent Lefevre wrote: On 2018-02-05 21:48:47 +0100, Torbjorn Granlund wrote: I suppose memset is not used as it might come with more overhead for checking alignment. I haven't timed it, though. The compiler knows the alignment from the types. Quite often it does not, the C type system is too weak. This is where the optimization should be. Sadly, I don't think gcc has an optimization like what Niels suggested, with multiple memset entry points according to the alignment. Searching a bit, it looks like Intel's compiler does (they recommend using __assume_aligned on the target of memset). The GCC manual mentions a __builtin_memset builtin, though I don't know what it does exactly. That's how a regular call to memset is encoded internally... For small constant sizes, it may be expanded inline, but usually it remains a call to memset. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Why set zero in zero.c rather than use xor_n
On Mon, 5 Feb 2018, Niels Möller wrote: I am not sure it is important enough to write in asm, though. Probably not. But it might make sense to rewrite as a wrapper for memset, which I'd expect to be well optimized in gcc and libc. If you compile the current zero.c with -O3, gcc generates a call to memset (protected by a test). If that's what we are getting, we might as well write it this way and make the function inline. Supposedly, for small sizes, mpn_zero can have a smaller overhead than memset, since it has more alignment information. But I don't think I've ever used mpn_zero... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Why set zero in zero.c rather than use xor_n
On Mon, 5 Feb 2018, Win C wrote: int main() { int i; mp_limb_t *pi = malloc(16); That's not nearly enough, the code crashes for me. $./zeroing 73491 17651 Try testing xor before zero... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mini-gmp
Hello, I am curious why you are trying to support mini-gmp in mpfr at all. As far as I understand, the goal of mini-gmp is that a user can take a copy of those 2 files, stick them in his project, and get a self-contained program. Unless you provide a similar mini-mpfr, your user is going to have to install the mpfr dependency anyway, his project is not self-contained, so he might as well install the real GMP. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Generic get_d_2exp failures
On Sat, 28 Oct 2017, Niels Möller wrote: Marc Glisse <marc.gli...@inria.fr> writes: 2) The rounding occurs in the addition in weight = 1/MP_BASE_AS_DOUBLE; d = up[size - 1]; for (i = size - 2; i >= 0; i--) { d += up[i] * weight; weight /= MP_BASE_AS_DOUBLE; if (weight == 0) break; } we could make that code uglier to make sure there is no rounding up, maybe comparing d+up[i]*weight to d+oldweight, and trying again by zeroing out an increasing number of low bits of up[i]. It would be nice if we could find a portable way to add two floating point values without rounding up. Would something like this work? s = a + b; /* Assume a > b */ r = (s - a) - b; /* No rounding expected here. */ if (r > 0) s -= 2*r; Not sure where the 2*r is coming from. And I am not very optimistic that there is such a simple formula that works for any rounding mode, though I could easily be wrong. There is also the question of how portable exactly it needs to be. C99 nextafter can be helpful. But doesn't make the tests pass in my initial testing. I guess it might be necessary to isolate the high bit of r (possibly be converting to mp_limb_t ans usign count_leading_zeros), which should correspond to the lsb of the mantissa (or if it's half the lsb). And might also need special handling of the case that s, after rounding, is a power of two. The variant I tested: @@ -368,7 +369,13 @@ mpn_get_d (mp_srcptr up, mp_size_t size, d = up[size - 1]; for (i = size - 2; i >= 0; i--) { - d += up[i] * weight; + double l, s, r; + l = up[i] * weight; + s = d + l; + r = (s - d) - l; + if (r > 0) + s -= 2*r; + d = s; weight /= MP_BASE_AS_DOUBLE; if (weight == 0) break; It may be easier to assert that FLT_RADIX==2 and use DBL_MANT_DIG to avoid any rounding. There is even code in one of the tests to compute DBL_MANT_DIG at runtime (preferably once, at startup) if it isn't available / reliable at compile-time. 3) Drop the generic path. It hasn't passed the testsuite for a long time, can't be that important. If we keep it, we'd need to (i) fix it, and (ii) test it regularly. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpn_sqrtrem{1,2} - patch for pure C implem
On Sat, 1 Apr 2017, Adrien Prost-Boucle wrote: On Sat, 2017-04-01 at 18:15 +0200, Marco Bodrato wrote: Sorry, but even correcting the obvious typos, it doesn't pass the tests. I think I have found the error. The final correction was wrong. I hope it's OK now, but... I still can't compile GMP with ABI=32. Like you suggested I launched: ./configure ABI=32 && make && make check The 5th or 6th source file does not compile: libtool: compile: gcc -DHAVE_CONFIG_H -I. -I.. -D__GMP_WITHIN_GMP -I.. -DOPERATION_com -m32 -O2 -pedantic -fomit-frame-pointer -mtune=core2 -march=core2 -c com.c -fPIC -DPIC -o .libs/com.o In file included from ../gmp-impl.h:147:0, from com.c:31: ../fib_table.h:4:1: warning: data definition has no type or storage class Error, error, this data is for 64 bits ^ Did you run "make distclean" between the 64-bit build and the 32-bit build? (doing the build out-of-tree avoids this kind of problem, since you can easily do the 32-bit build in a different directory) -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpn_sqrtrem{1,2}
On Sat, 25 Mar 2017, Torbjörn Granlund wrote: The sqrtss and sqrtds are SIMD operations, right? That means that if we don't initialise all input fields with something, they might contain special values which triggers exceptional conditions. I don't think so. sqrtsd computes sqrt of the lower half of the source and stores it to the lower half of the destination, it doesn't touch the rest, so exceptional condition because of the rest seems unlikely. On the other hand, false dependencies are possible and can affect performance. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpz reuse test takes too much time
On Sat, 3 Dec 2016, Niels Möller wrote: "Marco Bodrato" <bodr...@mail.dm.unipi.it> writes: ! #define GCDEXT_CHECK2(i1, i2) do {\ ! mpz_gcdext (res1, res2, NULL, i1, i2); \ ! MPZ_CHECK_FORMAT (res1);\ ! MPZ_CHECK_FORMAT (res2);\ ! if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0) \ ! FAIL2 (mpz_gcdext, i1, i2, NULL); \ ! } while (0) Should we check both mpz_gcdext (res1, res2, NULL, i1, i2); and mpz_gcdext (res1, NULL, res2, i2, i1) in this macro? Hmm, you changed the code to not only allow G to be NULL, but allow NULL S too? That was already the case before my patch. Since s and t may get swapped depending on the values of a and b, you cannot really support t==NULL without supporting s==NULL. You may prefer not documenting it though... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpz_gcd_ext(NULL, ...)
On Sat, 3 Dec 2016, Marco Bodrato wrote: The modified manual now says that "If @var{s}, @var{t} or @var{g} is @code{NULL} then that value is not computed.", but g is computed anyway, even if it is not returned... The only change is that it is about g, s and t instead of just t. But that was already not quite true before, since depending on a < b or b < a, we swap the arguments and the mpn function ends up computing t anyway. We are saving the copy, which counts as computation, so the formulation seemed good enough to me, and most importantly easy to understand for a user. If you want to rewrite it to clarify that the gains aren't much, please go ahead... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Help stabilising mini-gmp
On Fri, 25 Nov 2016, Marc Glisse wrote: On Mon, 21 Nov 2016, Torbjörn Granlund wrote: Marc Glisse <marc.gli...@inria.fr> writes: On Sun, 20 Nov 2016, Niels Möller wrote: > It would make sense to test both gmp and mini-gmp with > -fsanitize=undefined. If we are not already doing it, yes, I highly recommend it. It is now running for ivydeb64v9 and ivydeb32v9. Two errors were triggered for the former, one in mini-gmp (presumably fixed by nisse) and one on cxx/t-ops2z. Please take a look, glisse. Fixed. It was unhappy about (-13) << 2. I am a bit surprised it doesn't complain about (-13) >> 2 on the next line, we'll see if it ever becomes an issue. There is something strange with https://gmplib.org/devel/tm/gmp/date.html . When I click to get the logs for ivydeb32v9.gmplib.org-dyn-noasm-ubsan, the build log is from 26/11, but the check log is from 21/11... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Help stabilising mini-gmp
On Fri, 25 Nov 2016, Torbjörn Granlund wrote: Marc Glisse <marc.gli...@inria.fr> writes: Fixed. It was unhappy about (-13) << 2. I am a bit surprised it doesn't complain about (-13) >> 2 on the next line, we'll see if it ever becomes an issue. This must be a compiler problem. At least in C, shifting negative integers is undefined. It is a pity that it is, but the standard say so. I am less sure about C++. Some googling did not provide a definitive answer. But if left shift of negative integers is undefined, surely right shift is too! Surprisingly, shifting negative numbers left is undefined, while shifting them right it implementation-defined. The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 × 2^E2 , reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1 × 2^E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise, the behavior is undefined. The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a non-negative value, the value of the result is the integral part of the quotient of E1/2^E2 . If E1 has a signed type and a negative value, the resulting value is implementation-defined. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpz_gcd_ext(NULL, ...)
On Fri, 25 Nov 2016, Niels Möller wrote: Marc Glisse <marc.gli...@inria.fr> writes: a user was asking if we could support calling mpz_gcd_ext with a NULL first argument (the gcd), since they are only interested in the coefficients s and t and would like to save the unnecessary allocation. I doubt it would save that much, but it seems trivial to add a check if(g!=NULL) similar to the tests for s and t. Does it make sense to you? Sounds reasonable to me. Done. But then I'd also consider adding a return value, returning one if the inputs were coprime (gcd == 1), otherwise zero. Would be useful for mpz_invert. Makes sense. If you want to do it... It won't save much for the computation, only the final copy. But it's also a gain to clarity if callers don't have to pass in dummy, unused, result arguments. Agreed. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Help stabilising mini-gmp
On Mon, 21 Nov 2016, Torbjörn Granlund wrote: Marc Glisse <marc.gli...@inria.fr> writes: On Sun, 20 Nov 2016, Niels Möller wrote: > It would make sense to test both gmp and mini-gmp with > -fsanitize=undefined. If we are not already doing it, yes, I highly recommend it. It is now running for ivydeb64v9 and ivydeb32v9. Two errors were triggered for the former, one in mini-gmp (presumably fixed by nisse) and one on cxx/t-ops2z. Please take a look, glisse. Fixed. It was unhappy about (-13) << 2. I am a bit surprised it doesn't complain about (-13) >> 2 on the next line, we'll see if it ever becomes an issue. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Help stabilising mini-gmp
On Sun, 20 Nov 2016, Niels Möller wrote: It would make sense to test both gmp and mini-gmp with -fsanitize=undefined. If we are not already doing it, yes, I highly recommend it. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Help stabilising mini-gmp
On Sun, 20 Nov 2016, Torbjörn Granlund wrote: Marc Glisse <marc.gli...@inria.fr> writes: After inlining, there are subtractions. check_si is called at least once with oi = si + c (c is ±1). gcc simplifies the test si > si - 1 Inlining of check_si? Of all the functions. (note that I am just speculating, but the warning does not surprise me) If the code becomes undefined by gcc's transformations, that it's a compiler bug. That's not at all what I said, the code doesn't become undefined. If it was fine, it remains fine. If it was broken, the brokenness may become more obvious. Let me rephrase the warning: "Reminder: computing INT_MIN-1 is forbidden. If you are not doing that, you can ignore this message. I am giving you this warning because you are computing X-1 and I decided to key the launch of nuclear missiles to the value X==INT_MIN. Have a safe day!" (the computation of X-1 is in try_op_si, but the warning points at the location where the compiler inserts the trigger for the nuclear missiles) -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Help stabilising mini-gmp
On Sun, 20 Nov 2016, Niels Möller wrote: ni...@lysator.liu.se (Niels Möller) writes: It seems "trivially" reproducible on ppc64 though, both real metal versions and fake ones like ppceb-debv8 (and ppcel-debv8). I'll try to debug (if no one else beats me to it), but not today. I've logged in to ppceb-debv8, and it's easy to reproduce. No gdb installed, so I'm attempting printf debugging. And then I noticed that the test succeeds if adding a few debug printouts... I next tried adding -Wall to the command line flags, and I see gcc -std=gnu99 -m64 -mtune=power7 -O3 -Wall -I../.. -c /home/nisse/hack/gmp/mini-gmp/tests/t-signed.c -o t-signed.o /home/nisse/hack/gmp/mini-gmp/tests/t-signed.c: In function 'testmain': /home/nisse/hack/gmp/mini-gmp/tests/t-signed.c:45:26: warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false [-Wstrict-overflow] if ((si < oi ? -1 : si > oi) != c) ^ /home/nisse/hack/gmp/mini-gmp/tests/t-signed.c:45:21: warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true [-Wstrict-overflow] if ((si < oi ? -1 : si > oi) != c) ^ I don't quite understand neither what the testcase is doing, nor what the warning means, since there's no subtraction in there. After inlining, there are subtractions. check_si is called at least once with oi = si + c (c is ±1). gcc simplifies the test si > si - 1 to true, and warns that this optimization may break your program if you rely on wrapping. The usefulness of such a warning is debatable, and we tend to drop some of them from gcc when we think nobody will notice. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Help stabilising mini-gmp
On Sat, 19 Nov 2016, Niels Möller wrote: I don't think so. But I think the right way is to simply add $(CFLAGS) to the linker command line. That's the usual way to use it, right? That's a common hack (that I am ok with), but I don't think I would call it "the right way"... The first failure was also a bit interesting, an internal compiler error with gcc-6. In file included from gmp/mini-gmp/tests/testutils.c:24:0: gmp/mini-gmp/tests/../mini-gmp.c: In function 'mpz_set_d': gmp/mini-gmp/tests/../mini-gmp.c:1647:3: internal compiler error: Aborted if (x != x || x == x * 0.5) ^~ https://gmplib.org/devel/tm/gmp/build/failure/sky.gmplib.org-dyn-fat-fake:64.txt Strange that it only shows up there, the command line does not have anything specific to skylake (no -march or -mtune). I can't reproduce on another machine. (btw, some compilers warn about the trailing comma in enum hex_random_op) -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Adding support for the Fuchsia OS
On Fri, 4 Nov 2016, Josh Conner wrote: Hello - I'd like to add support for fuchsia (https://github.com/fuchsia-mirror) to libgmp. I believe the change is trivial (just adding it to the $os conditional). I'm not sure what the process is for submitting a proposed change to this library -- would you like me to just send a patch? Posting a patch to this list seems fine. What kind of special support do you need? I would expect most support work to happen in autoconf, libtool, config.guess, etc, all things were we can just import a new upstream version. If the patch is not a trivial one-liner, we may also need a copyright assignment. Are there easy ways to test GMP on fuchsia? One of the most convenient things for developers is when there is a machine (possibly virtual) available in the gcc compile farm. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Flurry of GMP check failures
On Sat, 5 Nov 2016, Niels Möller wrote: Marc Glisse <marc.gli...@inria.fr> writes: Uh? I have 2 very natural use cases for libgmp.a: 1) to build a static (or at least with few dependencies) executable that I am going to send to someone else [...] 2) I am rebuilding GMP on my specific platform in order to get the best possible performance. [...] I see. In these cases, is it important whether or not libgmp.a uses pic code? In the first case, it doesn't matter. In the second case, we would have to run benchmarks where one build uses --with-pic and not the other. The PIC library is a tiny bit larger (1321280 vs 1319632). GMPbench doesn't really see the difference on x86_64 core2 (2117 vs 2124), but it may not be the best test for this. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Flurry of GMP check failures
On Sat, 5 Nov 2016, Niels Möller wrote: At this point in time, I think use-cases involving static libgmp.a (or libnettle.a) are somewhat obscure. Uh? I have 2 very natural use cases for libgmp.a: 1) to build a static (or at least with few dependencies) executable that I am going to send to someone else who doesn't have much control over the computer he uses (either lack of permission or lack of competence). 2) I am rebuilding GMP on my specific platform in order to get the best possible performance. I might as well use a static libgmp to squeeze that extra bit of speed out of it (I might even want to use LTO in that case, although IIRC it currently causes some trouble in configure). Note that I do not care about security in either case. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: GMP work on symbol visibility
On Wed, 31 Aug 2016, Torbjörn Granlund wrote: There are several complex issues I need to understand and resolve. One issue is how to handle (unit) testing of hidden functions. I will probably resolve that with alias symbols such as foo_for_testing as an alias for foo. Would that be only in a temporary, testing-only libgmp.so, or also in the installed libgmp.so? I am guessing the second, but it seems a bit sad that the exported symbol list remains polluted. Another issue is with libgmpxx.so and its dependency on libgmp.so. As separate shared libs, hidden symbols of libgmp.so will not be reachable from libgmpxx.so, which of course means we cannot hide them. Also, there will be no performance wins for any libgmpxx.so references to libgmp.so. I see two solutions: (1) If we really want to discourage external use, arrange an alias to something wierd, making libgmpxx reach the symbol foo as fuckhead_foo. (2) Put (allmost) all of libgmp.so in libgmpxx.so. This gives the best performance. Does libgmpxx.so use that many private functions from libgmp.so and are they performance critical? To me, libgmpxx.so is very small and only contains I/O functions, where the overhead of a few calls shouldn't matter that much. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
RE: [PATCH] longlong.h: Fix obsolete ARC asm constraints
On Wed, 24 Aug 2016, Claudiu Zissulescu wrote: The J-constant was mainly used by Arc 4 architecture for 32-bit integer constants. It got obsoleted once we pushed the new ARCompact architecture to gcc (GCC5.x+). The replace constraint is the Cal which is again a 32 bit constraint fitted for arithmetic ops. On Wed, 24 Aug 2016, Vlad Zakharov wrote: I got inspiration from the following gcc patch: https://gcc.gnu.org/ml/gcc-patches/2016-04/msg01964.html "J" constraint is rejected with recent gcc, so we have to replace it. Thanks to both of you. My main concerns were (sorry, I should have stated it this way in the first place) 1) Does the patch break things for people using an older compiler? (how old?) Is it worth having both versions with an #if on the compiler version? 2) Do we need to backport the patch if we ever do a 6.1.2 release? From your messages, it seems clear that the answer to 2) is yes. 1) is not quite clear yet though. As far as I can tell from gcc's sources, the current ARC port was added for gcc-4.9 and already supported "Cal". A previous ARC port was obsoleted in gcc-4.6. That usually means the port already didn't work so well in previous releases, so it may indeed be unnecessary to support the old syntax. Does that make sense or did I misunderstand something? I'll probably push the patch in a few days, when I get the chance. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: [PATCH] longlong.h: Fix obsolete ARC asm constraints
On Wed, 17 Aug 2016, Vlad Zakharov wrote: We replace obsolete "J" constraint with "Cal" constraint. Hello, could you give a little more information please? In particular, does "Cal" work with older versions of gcc? Does "J" still work or is it rejected with a recent gcc? Do they mean the same thing? I trust that you know what you are doing, I just like to understand a patch before applying it. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Lazy mpz allocation
On Wed, 4 May 2016, Niels Möller wrote: Marc Glisse <marc.gli...@inria.fr> writes: The fact that an mpq is made of 2 mpz that can be accessed directly is part of the interface. I think following your suggestion would mean changing that. I guess you're right, it would break mpq_denref. Which I guess is also expected to work on a const mpq_t, so it's not an easy solution to redefine it to do lazy assignment. And it's used in quite a lot of places, debian codesearch lists the following packages: python-gmpy, llvm-toolchain-3.8, mpfr4, lcalc, yap, flint-arb, mlgmp, ats-lang-anairiats, givaro, parrot, llvm-toolchain-snapshot, librep, linbox, python-gmpy2, swi-prolog, libgmpada, isl, polymake, kcalc, pynac, flint, pike7.8, apron, cloog, llvm-toolchain-3.7, pike8.0, ocamlcreal, qsopt-ex, gambas3, cgal, surf-alggeo, singular, cvc3, gmp, regina-normal, gcl, ppl, libaqbanking, gmp-ecm, zimpl, ats2-lang, ledger, libalkimia, gfan, guile-1.8, genius, postgresql-pgmp But I'm not giving up just yet. Would it be possible to initialize the denominator as static const mp_limb_t the_one = 1; q->_mp_den._mp_alloc = 0; q->_mp_den._mp_size = 1; q->_mp_den._mp_d = (mp_limb_t*) _one; (This kind-of requires that _mp_alloc == 0, _mp_size != 0 is supported in general for mpz_t, meaning any modification requires new storage, and that the storage pointed to by _mp_d should not be deallocated by gmp). That looks pretty much like the copy-on-write thing you and Marco were discussing last year https://gmplib.org/list-archives/gmp-devel/2015-September/004169.html It should be possible, but it may require changing quite a number of places in the code. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Lazy mpz allocation
On Wed, 4 May 2016, Niels Möller wrote: t...@gmplib.org (Torbjörn Granlund) writes: I forgot about that we need to have an explicit denominator. We could surely point that to some static read-only data, but that would of course incur a cost when "re-allocating". I'm not familiar with mpq internals, but I guess it might be possible to get away with leaving the denominator as zero on initialization. Then one would need to follow the convention that if numerator is zero, then the denominator is ignored. Or (but I guess that's more cumbersome) adapt the convention that zero denominator means "this is an integer", and treated as one. The fact that an mpq is made of 2 mpz that can be accessed directly is part of the interface. I think following your suggestion would mean changing that. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Lazy mpz allocation
On Mon, 9 Nov 2015, Marco Bodrato wrote: Moreover, the mpq layer and mini-gmp need to migrate to lazy allocation too... For mpq, the attached seems sufficient to pass make check. Of course, without a copy-on-write mechanism for the 1 in the denominator, the gains are not comparable to the mpz case, it is more for consistency. -- Marc Glissediff -r 835f8974ff6e mpq/clear.c --- a/mpq/clear.c Thu Apr 07 22:50:07 2016 +0200 +++ b/mpq/clear.c Mon Apr 11 11:42:59 2016 +0200 @@ -34,6 +34,7 @@ void mpq_clear (mpq_t x) { - __GMP_FREE_FUNC_LIMBS (PTR(NUM(x)), ALLOC(NUM(x))); + if (ALLOC (NUM(x))) +__GMP_FREE_FUNC_LIMBS (PTR(NUM(x)), ALLOC(NUM(x))); __GMP_FREE_FUNC_LIMBS (PTR(DEN(x)), ALLOC(DEN(x))); } diff -r 835f8974ff6e mpq/clears.c --- a/mpq/clears.c Thu Apr 07 22:50:07 2016 +0200 +++ b/mpq/clears.c Mon Apr 11 11:42:59 2016 +0200 @@ -41,7 +41,8 @@ do { - __GMP_FREE_FUNC_LIMBS (PTR(NUM(x)), ALLOC(NUM(x))); + if (ALLOC (NUM(x))) + __GMP_FREE_FUNC_LIMBS (PTR(NUM(x)), ALLOC(NUM(x))); __GMP_FREE_FUNC_LIMBS (PTR(DEN(x)), ALLOC(DEN(x))); x = va_arg (ap, mpq_ptr); } diff -r 835f8974ff6e mpq/init.c --- a/mpq/init.cThu Apr 07 22:50:07 2016 +0200 +++ b/mpq/init.cMon Apr 11 11:42:59 2016 +0200 @@ -34,8 +34,9 @@ void mpq_init (mpq_t x) { - ALLOC(NUM(x)) = 1; - PTR(NUM(x)) = __GMP_ALLOCATE_FUNC_LIMBS (1); + static const mp_limb_t dummy_limb=0xc1a0; + ALLOC(NUM(x)) = 0; + PTR(NUM(x)) = (mp_ptr) _limb; SIZ(NUM(x)) = 0; ALLOC(DEN(x)) = 1; PTR(DEN(x)) = __GMP_ALLOCATE_FUNC_LIMBS (1); diff -r 835f8974ff6e mpq/set_si.c --- a/mpq/set_si.c Thu Apr 07 22:50:07 2016 +0200 +++ b/mpq/set_si.c Mon Apr 11 11:42:59 2016 +0200 @@ -56,7 +56,7 @@ } else { - PTR(NUM(dest))[0] = abs_num; + MPZ_NEWALLOC (NUM(dest), 1)[0] = abs_num; SIZ(NUM(dest)) = num > 0 ? 1 : -1; } diff -r 835f8974ff6e mpq/set_ui.c --- a/mpq/set_ui.c Thu Apr 07 22:50:07 2016 +0200 +++ b/mpq/set_ui.c Mon Apr 11 11:42:59 2016 +0200 @@ -52,7 +52,7 @@ } else { - PTR(NUM(dest))[0] = num; + MPZ_NEWALLOC (NUM(dest), 1)[0] = num; SIZ(NUM(dest)) = 1; } ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Lazy mpz allocation
Hello, the function mpz_init could now be marked __GMP_NOTHROW. Do we want to do it? I could then propagate the change to the C++ wrapper, which would have a significant impact on the performance of std::vector for instance. On the other hand, this is a promise in the interface, going back to a throwing mpz_init would be an ABI break. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: __uint128_t
On Wed, 23 Mar 2016, Victor Shoup wrote: This may be a bit off topic, but I figure the people on this list might know something about this. In some code I've been developing lately (NTL related, of course), I've been making more use of the __uint128_t type that is available on gcc (and its clang and icc clones). It's all ifdef'd properly, so I only use it when it actually works. Anyway, I find that on x86-64 machines and recent gcc's, the compiler does a pretty good job of code generation...much better than I recall some years ago. However, I was wondering about the 64-bit ARM machine. I don't have access to such a machine, but I tried some code out at https://gcc.godbolt.org (which is a very convenient site, by the way). I was somewhat surprised that the code generated there by gcc-4.8 for 64-bit ARM was terrible: a 64x64->128 mul gets mapped to a generic128x128->128 function call. You realize ARM64 barely existed at the time of gcc-4.8? If gcc-5, or better yet a snapshot of gcc-6, still generates suboptimal code, please report to https://gcc.gnu.org/bugzilla/ with a testcase, and the asm you would like gcc to generate instead. So I'm starting to question whether relying on __uint128_t is such a good idea. Maybe it would be better for me to isolate all of that code so that I can just drop in appropriate assembly (as in GMP's longlong.h), as an alternative. It is always a compromise... I could also ask gcc people what their plans for future optimizations in this area are, but I don't know who or where to ask. You could ask on g...@gcc.gnu.org, but reporting bugs when you see suboptimal code generated seems much more likely to get you answers, and by showing constructive interest it may spark further optimizations. If this is for the development of free software, the GCC compile farm includes some aarch64 machines on which you could experiment. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Move -DNO_ASM to config.h?
On Mon, 21 Mar 2016, Vincent Lefevre wrote: On 2016-03-20 12:14:49 +0100, Marc Glisse wrote: but it seems likely that a user who went to the trouble of disabling assembly for GMP doesn't want to use that same assembly in MPFR. I'm not so sure about that. AFAIK, longlong.h has far less asm code than the whole GMP. So, it is less likely that a user would want to disable asm from MPFR's copy of longlong.h. In https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69134 ( https://gcc.gnu.org/ml/gcc-patches/2016-01/msg00127.html ), users specifically wanted to disable MPFR's copy ;-) On the other hand, MPFR could probably add a --disable-assembly configure flag to define NO_ASM, so the user would just have to pass the same option to MPFR that he already passed to GMP. I don't think that such an option would really be useful (unless there is a demand for it). The user could still pass -DNO_ASM in CFLAGS. The drawback is that the user won't benefit from the default CFLAGS, but if he wants -DNO_ASM, this is quite specific so that he may not need the default CFLAGS anyway. Ok. I guess I saw --disable-assembly mostly as a way to document this, but probably NO_ASM is not worth documenting in MPFR. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Move -DNO_ASM to config.h?
On Sun, 20 Mar 2016, Torbjörn Granlund wrote: Marc Glisse <marc.gli...@inria.fr> writes: One issue with changing it is MPFR: src/mpfr-longlong.h tests for NO_ASM, but there is no code to define it. As far as I understand, MPFR uses __GMP_CFLAGS by default, in which GMP may have included -DNO_ASM. If we move NO_ASM to config.h, that also affects them (not that it should necessarily stop us). We could also define NO_ASM both in CFLAGS and config.h. It looks like gcc and clang only warn when redefining a macro to something different, they don't warn for -DNO_ASM with #define NO_ASM 1, so it wouldn't be so bad. In what way is it relevant to MPFR whether a GMP build included asm or not? I am guessing that, just like they want to use the exact same flags as GMP to compile (__GMP_CFLAGS), they also want to mimic this part of the build process. I don't know if their version of longlong.h is kept in sync with GMP's, but it seems likely that a user who went to the trouble of disabling assembly for GMP doesn't want to use that same assembly in MPFR. On the other hand, MPFR could probably add a --disable-assembly configure flag to define NO_ASM, so the user would just have to pass the same option to MPFR that he already passed to GMP. I currently think I'll go with just config.h (no CFLAGS). -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Move -DNO_ASM to config.h?
On Sun, 20 Mar 2016, Niels Möller wrote: Marc Glisse <marc.gli...@inria.fr> writes: when configure wants to define a macro, it usually puts it in config.h. We do have one exception: NO_ASM, which ends up defined in CFLAGS. Was there a particular reason for this choice? I'm greping for its uses, and it is used only in C files as far as I can see. I sure hope we don't use NO_ASM inside asm files ;-) I was wondering if it was useful in the rest of the configure script, but it seems to be done late enough that it is unlikely. Moving it to config.h makes sense to me. If we move it, we have make sure that config.h is always included before longlong.h. Most files get config.h via gmp-impl.h. So, e.g., #include "longlong.h" followed by #include "gmp-impl.h" would break. longlong.h requires some types like UWtype which we provide in gmp-impl.h, so I am hoping that the inclusions are already handled properly. I think the autoconf manual recommends an explicit include of config.h (guarded by HAVE_CONFIG_H) first in every C file. We don't have to do it that way of course, just be aware that we depart from that convention. Thanks. autoconf is still rather unfamiliar to me (though at least it makes more sense than the cmake I am forced to use at work). -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpz_export to file?
On Wed, 9 Dec 2015, paul zimmermann wrote: mpz_export() exports an integer to some allocated array. For saving huge integers to a file, this is not optimal since one has first to allocate a huge array in memory, "export" the mpz_t to that array, and then copy that array to memory. Can't you use mmap for that? (not arguing against your interface, just wondering) Would it be possible to have a function that exports directly to a file (and of course the corresponding import function)? void mpz_export_file (FILE *f, mpz_t op); void mpz_import_file (mpz_t op, FILE *f); One could imagine a format where several numbers can be exported in the same file: f = fopen ("toto", "w"); mpz_export_file (f, a); mpz_export_file (f, b); mpz_export_file (f, c); fclose (f); ... f = fopen ("toto", "r"); mpz_import_file (a, f); mpz_import_file (b, f); mpz_import_file (c, f); fclose (f); -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
mp_bitcnt_signed_t
Hello, mpz_get_d_2exp and mpf_get_d_2exp currently take as argument a long*. Since we introduced a type mp_bitcnt_t, I guess it would make sense to add mp_bitcnt_signed_t and use it there. Any objection? For the mpz case, the answer should always be nonnegative, so we could use an unsigned type if we wanted, but I guess it is better to keep the current signed type, which is consistent with the mpf case. What do you think of introducing 2 typedefs mp_builtin_[su]i (or mp_native_[su]i or gmp_[su]i or whatever) and using them in all the functions with _si or _ui in their name ? Just trying to clarify why each type is used (unsigned long is mp_bitcnt_t in some places, mp_builtin_ui in others, etc). -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpq_cmp_z
On Fri, 21 Aug 2015, Marco Bodrato wrote: On Thu, August 20, 2015 9:56 am, Marc Glisse wrote: Is casting an mpz to an mpq, then accessing only the NUM() part of it, portable? From what I understand of the aliasing model currently used by gcc, to be safe, in the function using it, we should have: mpz_srcptr op2n = NUM(op2); and then use SIZ(op2n) instead of directly SIZ(NUM(op2)). The reason is x=op2-_mp_den._mp_size promises that op2 points to a __mpq_struct while x=op2n-_mp_size only promises a __mpz_struct (and gcc folds * Maybe we can promise the right type, by adding an explicit cast? SIZ((mpz_srcptr) NUM(op2)) I think that cast would be ignored, you really want them in separate expressions. Another thing I forgot: computing DEN(op2) could also be illegal unless the layout of __mpq_struct is the same as __mpz_struct[2], in which case we are computing the past-the-end pointer of the mpz_t, which is ok. Anyway, I was just trying to think of potential issues with the code, feel free to ignore it as long as nobody reports an issue with it. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpq_cmp_z
On Fri, 21 Aug 2015, Torbjörn Granlund wrote: Marco Bodrato bodr...@mail.dm.unipi.it writes: Maybe we can promise the right type, by adding an explicit cast? SIZ((mpz_srcptr) NUM(op2)) Except that we should cast op2, not NUM(ops). I am not sure Marc's reasoning is accurate, nor am I suggesting it is not, I've forgotten this level of detail of the C standard. I am not too enthusiastic about passing the wrong type, but if we add casts both when going to mpq and when going back to mpz, I cannot see how that could break with a conforming compiler. Good point. I agree that (mpz_srcptr)op2 is a safer way to do the same thing as NUM(op2) in this case. (I am not suggesting changing the gmp-impl implementation of NUM to a cast) -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpq_cmp_z
On Thu, 20 Aug 2015, Marco Bodrato wrote: Is casting an mpz to an mpq, then accessing only the NUM() part of it, portable? From what I understand of the aliasing model currently used by gcc, to be safe, in the function using it, we should have: mpz_srcptr op2n = NUM(op2); and then use SIZ(op2n) instead of directly SIZ(NUM(op2)). The reason is that as long as you are only doing pointer arithmetic (NUM counts as pointer arithmetic), the exact type is kind of irrelevant (size matters as a multiplicative factor, and alignment because it can make the result invalid, but that's it), but as soon as you actually use it (load or store), you are making a promise that the type is right. So x=op2-_mp_den._mp_size promises that op2 points to a __mpq_struct while x=op2n-_mp_size only promises a __mpz_struct (and gcc folds * to nothing very early, so it sees SIZ(NUM(op2)) as the first expression). Note that my understanding could be wrong, and other compilers could have a different model. In practice, I doubt your code would fail, but with the generalization of link-time optimizations, the library and user code are not hidden from each other anymore, and surprising things could happen. The cast itself seems fine: A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning. On Thu, 20 Aug 2015, Torbjörn Granlund wrote: (We might consider adding mpf_cmp_z too, at least in a simple-minded manner, to keep the GMP interface as orthogonal as possible.) Adding new mpf_t functions might confuse the message that people should use mpfr... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: GMP and clang bugginess
On Thu, 21 May 2015, Marc Glisse wrote: On powerpc-linux-gnu, clang complains about the bc+ instruction, and indeed I can't find that in IBM's documentation. After removing divrem_2.asm, it compiles fine and passes the testsuite. Now I've found it (and reported https://llvm.org/bugs/show_bug.cgi?id=23646 ). Note that the same (?) instruction is spelled differently in the same file: bc+ 12, 28, L(9) vs. blt+cr7, L(24) (there is also a mix of using 7 vs cr7) and llvm is happy with the second form. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: GMP and clang bugginess
On Mon, 25 May 2015, Torbjörn Granlund wrote: Marc Glisse marc.gli...@inria.fr writes: Now I've found it (and reported https://llvm.org/bugs/show_bug.cgi?id=23646 ). Note that the same (?) instruction is spelled differently in the same file: bc+ 12, 28, L(9) vs. blt+cr7, L(24) Note that the former form works with clang 3.5 installs. A 3.6 regression? Indeed... (there is also a mix of using 7 vs cr7) and llvm is happy with the second form. Please point me to the place where 7 is used. Ah, no, my mistake, I got confused by the preprocessing. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: GMP and clang bugginess
On Mon, 25 May 2015, Marc Glisse wrote: On Mon, 25 May 2015, Torbjörn Granlund wrote: Marc Glisse marc.gli...@inria.fr writes: Now I've found it (and reported https://llvm.org/bugs/show_bug.cgi?id=23646 ). Note that the same (?) instruction is spelled differently in the same file: bc+ 12, 28, L(9) vs. blt+cr7, L(24) Note that the former form works with clang 3.5 installs. A 3.6 regression? Indeed... Er, actually, that's just the time when they enabled the integrated 'as' by default, 3.5 was using binutils. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: GMP and clang bugginess
On Thu, 21 May 2015, Torbjörn Granlund wrote: GMP triggers bugs in clang on every platform where we tried this compiler. Some configs work, though. To see how bad it is, please take a look here: https://gmplib.org/devel/tm-date.html I think we would help our users by making it hard to use clang with the next release. What do you think? My idea is to reject clang with an error message along these lines: error: clang is not able to correctly compile GMP. To override, use --enable-clang. Make sure to run make check and don't use the library of this fails. It is your call, but that seems a bit excessive to me. I just did a few tests with clang-3.6. It seems to work fine on x86_64, so probably on macs, where it is the default compiler and a large part of the user base is. On powerpc-linux-gnu, clang complains about the bc+ instruction, and indeed I can't find that in IBM's documentation. After removing divrem_2.asm, it compiles fine and passes the testsuite. aarch64-linux-gnu and arm-linux-gnueabihf are working fine for me. powerpc64le-linux-gnu seems broken indeed. I tend to consider that the usual run the testsuite message is sufficient, possibly with extra warnings in the release notes or some such place. But again, your call. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Adding support for R6 of MIPS architecture
On Mon, 2 Feb 2015, Torbjörn Granlund wrote: Does MIPS64r6 contain all older architecture revisions as a subset, Apparently not, the motivation for the patch is that multu has disappeared... -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: Additional memory handler features.
On Sun, 4 Jan 2015, Victor Shoup wrote: But I see mention of itching and scratching: could somebody describe what that is or provide a link? Sorry for my ignorance. and sorry for the length of this post The general idea is to push all operations that may fail or otherwise require customization to user code. There would be a function mpn_mul_itch that would tell you how much temporary (scratch) space mpn_mul may need, and mpn_mul would take as argument a pointer to a buffer of at least this size. Allocation is the user's responsibility. There should already be a few functions or macros with itch in their name. [FULL DISCLOSURE: my own, somewhat narrow and selfish goal is to see GMP's mpn-level routines throw exceptions, rather than abort, with no interface changes. This is what would work best for my own NTL library] mpn functions have few reasons to abort. Except for allocation failure, as long as you checked the operands before passing them to GMP... [And yet another issue: my understanding is that some OS's actually have rather weird ways of dealing with out-of-memory errors: malloc always succeeds and returns a non-null pointer, but indirecting through that pointer may abort the program. In such a setting, all of this memory-related error handling stuff is pointless] Yes. Memory overcommit can often be disabled or mitigated in various ways, but it does complicate things (get a better OS ;-) -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
C++ factorial error reporting
Hello, I am trying to add factorial to the C++ interface, and since GMP only provides mpz_fac_ui, I end up having to check and report errors directly. Any preferences? Calling factorial on a negative integer doesn't make sense, we could have assert(number = 0). I am throwing an exception because that seems a little friendlier, but I am still choosing one that derives from logic_error. Calling factorial on a number that is a bit too large is a different issue. overflow_error is the natural exception when trying to convert an mpz_class to an unsigned long if it will not fit. But even if it fits, it may still be too big and mpz_fac_ui may fail, in the allocation function, which might abort but a natural replacement would throw bad_alloc. I don't think it makes that much sense to have a different exception depending on who notices that the number is too big, which is why I was also considering throwing bad_alloc instead of overflow_error. We could also pick a single exception and throw it for both negative and too-big. (you can check the list of standard exceptions at http://en.cppreference.com/w/cpp/error/exception , defining our own exception type doesn't seem worth the trouble) struct __gmp_factorial_function { static void eval(mpz_ptr z, mpz_srcptr w) { if (mpz_sgn(w) 0) throw std::domain_error (factorial(negative)); // There is no point trying to compute such a huge number. if (!mpz_fits_ulong_p(w)) throw std::overflow_error (factorial); // or std::bad_alloc()? eval(z, mpz_get_ui(w)); } static void eval(mpz_ptr z, unsigned long int l) { mpz_fac_ui(z, l); } static void eval(mpz_ptr z, signed long int l) { if (l 0) throw std::domain_error (factorial(negative)); eval(z, static_castunsigned long(l)); } static void eval(mpz_ptr z, double d) { __GMPXX_TMPZ_D;eval (z, temp); } }; -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
TMP_ALLOC in C++
Hello, this patch moves deallocation of temporary memory to a destructor when GMP is compiled with a C++ compiler. This may not be the final form of the patch, but I am interested in comments. Most of the patch is adjustments to tests/mpn so that temporary memory is freed before calling tests_end. (for the tal-debug.c patch, it may be simpler to change the type of block to void* in gmp-impl.h) -- Marc Glissediff --git a/gmp-impl.h b/gmp-impl.h --- a/gmp-impl.h +++ b/gmp-impl.h @@ -5150,16 +5150,53 @@ mpn_toom54_mul_itch (mp_size_t an, mp_si #if 0 #define mpn_fft_mul mpn_mul_fft_full #else #define mpn_fft_mul mpn_nussbaumer_mul #endif #ifdef __cplusplus +/* Handle C++ exceptions. */ +#if !WANT_TMP_DEBUG || __cplusplus = 201103L +struct gmp_tmp_salloc_t { + /* May warn in pedantic mode when TMP_SDECL is empty. */ + TMP_SDECL; + gmp_tmp_salloc_t(){ TMP_SMARK; } + void*salloc(size_t n){ return TMP_SALLOC(n); } + ~gmp_tmp_salloc_t(){ TMP_SFREE; } +}; +struct gmp_tmp_alloc_t { + TMP_DECL; + gmp_tmp_alloc_t(){ TMP_MARK; } + void*salloc(size_t n){ return TMP_SALLOC(n); } + void*balloc(size_t n){ return TMP_BALLOC(n); } + void*alloc(size_t n){ return TMP_ALLOC(n); } + ~gmp_tmp_alloc_t(){ TMP_FREE; } +}; +#undef TMP_SDECL +#undef TMP_DECL +#undef TMP_SMARK +#undef TMP_MARK +#undef TMP_SALLOC +#undef TMP_BALLOC +#undef TMP_ALLOC +#undef TMP_SFREE +#undef TMP_FREE +#define TMP_SDECL +#define TMP_DECL +#define TMP_SMARK gmp_tmp_salloc_t gmp_tmp_alloc +#define TMP_MARK gmp_tmp_alloc_t gmp_tmp_alloc +#define TMP_SALLOC(n) gmp_tmp_alloc.salloc(n) +#define TMP_BALLOC(n) gmp_tmp_alloc.balloc(n) +#define TMP_ALLOC(n) gmp_tmp_alloc.alloc(n) +#define TMP_SFREE +#define TMP_FREE +#endif + /* A little helper for a null-terminated __gmp_allocate_func string. The destructor ensures it's freed even if an exception is thrown. The len field is needed by the destructor, and can be used by anyone else to avoid a second strlen pass over the data. Since our input is a C string, using strlen is correct. Perhaps it'd be more C++-ish style to use std::char_traitschar::length, but char_traits isn't available in gcc 2.95.4. */ diff --git a/mpf/get_str.c b/mpf/get_str.c --- a/mpf/get_str.c +++ b/mpf/get_str.c @@ -175,16 +175,17 @@ mpf_get_str (char *dbuf, mp_exp_t *exp, if (un == 0) { *exp = 0; *dbuf = 0; n_digits = 0; goto done; } + { TMP_MARK; /* Allocate temporary digit space. We can't put digits directly in the user area, since we generate more digits than requested. (We allocate 2 * GMP_LIMB_BITS extra bytes because of the digit block nature of the conversion.) */ tstr = (unsigned char *) TMP_ALLOC (n_digits + 2 * GMP_LIMB_BITS + 3); @@ -312,16 +313,17 @@ mpf_get_str (char *dbuf, mp_exp_t *exp, if (SIZ(u) 0) { dbuf[0] = '-'; n_digits++; } TMP_FREE; + } done: /* If the string was alloced then resize it down to the actual space required. */ if (alloc_size != 0) { __GMP_REALLOCATE_FUNC_MAYBE_TYPE (dbuf, alloc_size, n_digits + 1, char); } diff --git a/tal-debug.c b/tal-debug.c --- a/tal-debug.c +++ b/tal-debug.c @@ -103,17 +103,17 @@ void * { __gmp_assert_header (file, line); fprintf (stderr, GNU MP: TMP_ALLOC without TMP_MARK(%s)\n, decl_name); abort (); } p = __GMP_ALLOCATE_FUNC_TYPE (1, struct tmp_debug_entry_t); p-size = size; - p-block = (*__gmp_allocate_func) (size); + p-block = (char*) (*__gmp_allocate_func) (size); p-next = mark-list; mark-list = p; return p-block; } void __gmp_tmp_debug_free (const char *file, int line, int dummy, struct tmp_debug_t **markp, diff --git a/tests/mpn/logic.c b/tests/mpn/logic.c --- a/tests/mpn/logic.c +++ b/tests/mpn/logic.c @@ -57,78 +57,80 @@ check_one (mp_srcptr refp, mp_srcptr rp, int main (int argc, char **argv) { mpz_t a, b; mp_ptr ap, bp, rp, refp; mp_size_t max_n, n, i; gmp_randstate_ptr rands; long test, reps = 1000; - TMP_DECL; - TMP_MARK; + { +TMP_DECL; +TMP_MARK; - tests_start (); - TESTS_REPS (reps, argv, argc); +tests_start (); +TESTS_REPS (reps, argv, argc); - mpz_inits (a, b, NULL); +mpz_inits (a, b, NULL); - rands = RANDS; /* FIXME: not used */ +rands = RANDS; /* FIXME: not used */ - max_n = 100; +max_n = 100; - rp = TMP_ALLOC_LIMBS (1 + max_n * 8 / GMP_LIMB_BITS); - refp = TMP_ALLOC_LIMBS (1 + max_n * 8 / GMP_LIMB_BITS); +rp = TMP_ALLOC_LIMBS (1 + max_n * 8 / GMP_LIMB_BITS); +refp = TMP_ALLOC_LIMBS (1 + max_n * 8 / GMP_LIMB_BITS); - for (test = 0; test reps; test++) -{ - for (i = 1; i = max_n; i++) - { - mpz_rrandomb (a, rands, i * 8); - mpz_rrandomb (b, rands, i * 8); - mpz_setbit (a, i * 8 - 1); - mpz_setbit (b, i * 8 - 1); -
Re: Compiling GMP with clang
On Sat, 29 Nov 2014, Torbjörn Granlund wrote: 3. Link errors on some arm32 systems. We have not investigates this. Help is welcome. Failure log: https://gmplib.org/devel/testmachines/build/failure/armv5.gmplib.org-stat-clang-clang++:standard.txt #include stdexcept int main(){throw std::invalid_argument(hello);} $ clang++ -target arm-linux-gnueabi main.cc $ clang++ -target arm-linux-gnueabi main.cc -O -latomic $ clang++ -target arm-linux-gnueabi main.cc -O /tmp/main-d6b7a1.o: In function `main': main.cc:(.text+0x84): undefined reference to `__atomic_fetch_add_4' It should be possible to test this in configure. I don't know how relevant armv5 is to GMP though. (I also killed lt-reuse after 5 minutes, but it might just be that long) -stdlib=libc++ testing is complicated because of https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=771512 -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: allocated blocks holding pointers to other allocated blocks
On Wed, 5 Mar 2014, David Warme wrote: The GMP manual on Custom Allocation contains the following paragraph: GMP may use allocated blocks to hold pointers to other allocated blocks. This will limit the assumptions a conservative garbage collection scheme can make. Questions: 1. This seems like a situation that can only exist while certain GMP routines are active in the call stack context -- if no GMP function is active, then this situation will not exist, correct? That's not obvious to me. 2. What places within GMP use this technique (pervasive, or hopefully just a few places)? I am surprised google didn't point you to: https://gmplib.org/list-archives/gmp-discuss/2009-May/003733.html Apparently, I had only found one at the time, and I doubt we introduced many since. But I could have missed other places. -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel
Re: mpz_limbs interface
On Thu, 6 Feb 2014, Niels Möller wrote: ni...@lysator.liu.se (Niels Möller) writes: For mpn_set_d, I think it would make some sense to have it return a base-2 exponent, and write the mantissa to a few limbs. Number of limbs would be a constant, part of the ABI, similar to LIMBS_PER_DOUBLE but renamed for external use. mp_bitcnt_t mpn_set_d (mp_limb_t rp[LIMBS_PER_BOUBLE], d); Below is a patch to do this (and return value is long, not mp_bitcnt_t, since it needs to be signed). Thanks. What do you think? (I haven't looked at it much yet) Why not return int, since int is what we use for _mp_size? Is 53 really safe for non-IEEE double? Maybe something based on DBL_MANT_DIG, assuming that FLT_RADIX==2? I don't think we are still supporting gcc-2.8... From a performance POV, it may not be optimal to split the sign/infinity/nan/zero test from the rest, but I agree it makes the interface simpler. + ASSERT (d != 0.5*d);/* Exclude infinities */ That excludes more than infinities, it might also exclude FLT_TRUE_MIN, no? -- Marc Glisse ___ gmp-devel mailing list gmp-devel@gmplib.org https://gmplib.org/mailman/listinfo/gmp-devel